From c840c4d5cf4d40472f27412b7a0ec1e2176a209c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= <33655937+jkoenig134@users.noreply.github.com> Date: Fri, 15 Mar 2024 11:52:15 +0100 Subject: [PATCH] Admin UI: Initialize flutter setup (#547) * chore: update settings.json with dart * chore: add readme * fix: git-un-ignore adminui packages * chore: add initial flutter setup * feat: add adminui boilerplate * feat: add types * feat: add sdk * feat: use client in the app * chore: move AdminUI to AdminUI folder * fix: allow internet access for the mac app * chore: add setup for configs * feat: async creation of client * chore: update mac icons * chore: change name from admin_ui to AdminUI * feat: add window_size plugin * fix: use empty baseurl for web * feat: add shared preferences * feat: add routing * feat: add packages * chore: move AdminUI to AdminUi * chore: add packages * chore: move stuff * chore: ignore again * chore: simplify logout * chore: make more readable * fix: check for api key validity * chore: do not copy code from go_router package * fix: use enmeshed logo as svg * chore: update default window size on macos * chore: yeet unused launch config * chore: update extensions * fix: obscure text in pw field * chore: add tier get and delete endpoints * feat: add quota types and endpoints * feat: add quota endpoint * chore format * wip * chore: wip * chore: update identity * chore: update, change method name and type * chore: remove unnecessary imports * feat: add relationships type and endpoint * ci: move runAdminUiChecks to aui folder and rename it to runChecks * ci: add and execute runFlutterChecks script * ci: rename flutter checks jobs * ci: use correct script folder and name * chore: simplify relationship type * chore: finalize identities odata * chore: add separate get and make result for odata * chore: comment now follows flutter style to-do * chore: simplify relationship endpoint * chore: show the results of getting the data * ci: trigger pipelines * chore: add some basic pagination * chore: add filtering for odata * chore: add filtering example * chore: export identity overview filter * fix: syntax * chore: bump melos * chore: use builtin melos analyze command * refactor: identities * chore: add types to dependencies * refactor: move enum * chore: rename parameters * feat: add identity overview * chore: display only identity overview * chore: add trailing comma and add named parameter * refactor: use port 8082 for local testing * chore: remove UI code * fix: make pagination usable * chore: remove comment * fix: early return * refactor: make pretty * chore: remove unused file --------- Co-authored-by: Vladimir Vuckovic Co-authored-by: Timo Notheisen Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .ci/{runAdminUiChecks.sh => aui/runChecks.sh} | 1 + .ci/aui/runFlutterChecks.sh | 9 + .github/workflows/test.yml | 13 +- .gitignore | 3 + .vscode/extensions.json | 2 +- .vscode/launch.json | 14 +- .vscode/settings.json | 7 +- AdminUi/.gitignore | 9 + AdminUi/README.md | 35 + AdminUi/analysis_options.yaml | 9 + AdminUi/apps/admin_ui/.gitignore | 43 + AdminUi/apps/admin_ui/.metadata | 36 + AdminUi/apps/admin_ui/README.md | 3 + AdminUi/apps/admin_ui/analysis_options.yaml | 1 + AdminUi/apps/admin_ui/assets/icon.png | Bin 0 -> 4169 bytes AdminUi/apps/admin_ui/assets/logo.svg | 15 + AdminUi/apps/admin_ui/assets/mac-icon.png | Bin 0 -> 16216 bytes AdminUi/apps/admin_ui/lib/home/home.dart | 42 + AdminUi/apps/admin_ui/lib/main.dart | 80 ++ .../apps/admin_ui/lib/pages/home_page.dart | 91 ++ .../apps/admin_ui/lib/pages/login_page.dart | 97 +++ AdminUi/apps/admin_ui/lib/pages/pages.dart | 3 + .../apps/admin_ui/lib/pages/splash_page.dart | 64 ++ .../admin_ui/lib/setup/setup_desktop.dart | 10 + .../apps/admin_ui/lib/setup/setup_web.dart | 3 + AdminUi/apps/admin_ui/macos/.gitignore | 7 + .../macos/Flutter/Flutter-Debug.xcconfig | 2 + .../macos/Flutter/Flutter-Release.xcconfig | 2 + .../Flutter/GeneratedPluginRegistrant.swift | 14 + AdminUi/apps/admin_ui/macos/Podfile | 43 + AdminUi/apps/admin_ui/macos/Podfile.lock | 29 + .../macos/Runner.xcodeproj/project.pbxproj | 801 ++++++++++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 +++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../admin_ui/macos/Runner/AppDelegate.swift | 9 + .../AppIcon.appiconset/Contents.json | 68 ++ .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 98631 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 5720 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 553 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 14416 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1106 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 37761 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 2487 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 344 ++++++++ .../macos/Runner/Configs/AppInfo.xcconfig | 14 + .../macos/Runner/Configs/Debug.xcconfig | 2 + .../macos/Runner/Configs/Release.xcconfig | 2 + .../macos/Runner/Configs/Warnings.xcconfig | 13 + .../macos/Runner/DebugProfile.entitlements | 14 + AdminUi/apps/admin_ui/macos/Runner/Info.plist | 32 + .../macos/Runner/MainFlutterWindow.swift | 15 + .../macos/Runner/Release.entitlements | 10 + .../macos/RunnerTests/RunnerTests.swift | 12 + AdminUi/apps/admin_ui/pubspec.lock | 569 +++++++++++++ AdminUi/apps/admin_ui/pubspec.yaml | 44 + AdminUi/apps/admin_ui/web/favicon.png | Bin 0 -> 356 bytes AdminUi/apps/admin_ui/web/icons/Icon-192.png | Bin 0 -> 4502 bytes AdminUi/apps/admin_ui/web/icons/Icon-512.png | Bin 0 -> 23723 bytes .../admin_ui/web/icons/Icon-maskable-192.png | Bin 0 -> 4502 bytes .../admin_ui/web/icons/Icon-maskable-512.png | Bin 0 -> 23723 bytes AdminUi/apps/admin_ui/web/index.html | 59 ++ AdminUi/apps/admin_ui/web/manifest.json | 35 + AdminUi/apps/admin_ui/windows/.gitignore | 17 + AdminUi/apps/admin_ui/windows/CMakeLists.txt | 108 +++ .../admin_ui/windows/flutter/CMakeLists.txt | 109 +++ .../flutter/generated_plugin_registrant.cc | 14 + .../flutter/generated_plugin_registrant.h | 15 + .../windows/flutter/generated_plugins.cmake | 24 + .../admin_ui/windows/runner/CMakeLists.txt | 40 + .../apps/admin_ui/windows/runner/Runner.rc | 121 +++ .../windows/runner/flutter_window.cpp | 71 ++ .../admin_ui/windows/runner/flutter_window.h | 33 + AdminUi/apps/admin_ui/windows/runner/main.cpp | 43 + .../apps/admin_ui/windows/runner/resource.h | 16 + .../windows/runner/resources/app_icon.ico | Bin 0 -> 9169 bytes .../windows/runner/runner.exe.manifest | 20 + .../apps/admin_ui/windows/runner/utils.cpp | 65 ++ AdminUi/apps/admin_ui/windows/runner/utils.h | 19 + .../admin_ui/windows/runner/win32_window.cpp | 288 +++++++ .../admin_ui/windows/runner/win32_window.h | 102 +++ AdminUi/config.local.json | 3 + AdminUi/melos.yaml | 28 + AdminUi/packages/admin_api_sdk/.gitignore | 10 + .../admin_api_sdk/analysis_options.yaml | 1 + .../example/admin_api_sdk_example.dart | 39 + .../admin_api_sdk/lib/admin_api_sdk.dart | 2 + .../lib/src/admin_api_sdk_base.dart | 60 ++ .../lib/src/builders/builders.dart | 1 + .../identity_overview_filter_builder.dart | 107 +++ .../lib/src/endpoints/clients_endpoint.dart | 76 ++ .../lib/src/endpoints/endpoint.dart | 138 +++ .../lib/src/endpoints/endpoints.dart | 5 + .../lib/src/endpoints/identity_endpoint.dart | 49 ++ .../lib/src/endpoints/quotas_endpoint.dart | 67 ++ .../src/endpoints/relationships_endpoint.dart | 26 + .../lib/src/endpoints/tiers_endpoint.dart | 39 + .../lib/src/types/api_error.dart | 25 + .../lib/src/types/api_response.dart | 65 ++ .../admin_api_sdk/lib/src/types/types.dart | 2 + AdminUi/packages/admin_api_sdk/pubspec.yaml | 16 + AdminUi/packages/admin_api_types/.gitignore | 7 + .../admin_api_types/analysis_options.yaml | 1 + .../admin_api_types/lib/admin_api_types.dart | 1 + .../lib/src/admin_api_types_base.dart | 5 + .../lib/src/clients/client.dart | 61 ++ .../lib/src/clients/client.g.dart | 53 ++ .../lib/src/clients/clients.dart | 1 + .../lib/src/identities/identities.dart | 1 + .../lib/src/identities/identity.dart | 100 +++ .../lib/src/identities/identity.g.dart | 87 ++ .../admin_api_types/lib/src/quotas/quota.dart | 35 + .../lib/src/quotas/quota.g.dart | 31 + .../lib/src/quotas/quotas.dart | 1 + .../lib/src/relationships/relationship.dart | 29 + .../lib/src/relationships/relationship.g.dart | 29 + .../lib/src/relationships/relationships.dart | 1 + .../admin_api_types/lib/src/tiers/tier.dart | 35 + .../admin_api_types/lib/src/tiers/tier.g.dart | 29 + .../admin_api_types/lib/src/tiers/tiers.dart | 1 + AdminUi/packages/admin_api_types/pubspec.yaml | 14 + AdminUi/pubspec.lock | 333 ++++++++ AdminUi/pubspec.yaml | 12 + docker-compose/docker-compose.services.yml | 6 +- 125 files changed, 5576 insertions(+), 15 deletions(-) rename .ci/{runAdminUiChecks.sh => aui/runChecks.sh} (94%) create mode 100755 .ci/aui/runFlutterChecks.sh create mode 100644 AdminUi/.gitignore create mode 100644 AdminUi/README.md create mode 100644 AdminUi/analysis_options.yaml create mode 100644 AdminUi/apps/admin_ui/.gitignore create mode 100644 AdminUi/apps/admin_ui/.metadata create mode 100644 AdminUi/apps/admin_ui/README.md create mode 100644 AdminUi/apps/admin_ui/analysis_options.yaml create mode 100644 AdminUi/apps/admin_ui/assets/icon.png create mode 100644 AdminUi/apps/admin_ui/assets/logo.svg create mode 100644 AdminUi/apps/admin_ui/assets/mac-icon.png create mode 100644 AdminUi/apps/admin_ui/lib/home/home.dart create mode 100644 AdminUi/apps/admin_ui/lib/main.dart create mode 100644 AdminUi/apps/admin_ui/lib/pages/home_page.dart create mode 100644 AdminUi/apps/admin_ui/lib/pages/login_page.dart create mode 100644 AdminUi/apps/admin_ui/lib/pages/pages.dart create mode 100644 AdminUi/apps/admin_ui/lib/pages/splash_page.dart create mode 100644 AdminUi/apps/admin_ui/lib/setup/setup_desktop.dart create mode 100644 AdminUi/apps/admin_ui/lib/setup/setup_web.dart create mode 100644 AdminUi/apps/admin_ui/macos/.gitignore create mode 100644 AdminUi/apps/admin_ui/macos/Flutter/Flutter-Debug.xcconfig create mode 100644 AdminUi/apps/admin_ui/macos/Flutter/Flutter-Release.xcconfig create mode 100644 AdminUi/apps/admin_ui/macos/Flutter/GeneratedPluginRegistrant.swift create mode 100644 AdminUi/apps/admin_ui/macos/Podfile create mode 100644 AdminUi/apps/admin_ui/macos/Podfile.lock create mode 100644 AdminUi/apps/admin_ui/macos/Runner.xcodeproj/project.pbxproj create mode 100644 AdminUi/apps/admin_ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 AdminUi/apps/admin_ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 AdminUi/apps/admin_ui/macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 AdminUi/apps/admin_ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 AdminUi/apps/admin_ui/macos/Runner/AppDelegate.swift create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Base.lproj/MainMenu.xib create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Configs/AppInfo.xcconfig create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Configs/Debug.xcconfig create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Configs/Release.xcconfig create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Configs/Warnings.xcconfig create mode 100644 AdminUi/apps/admin_ui/macos/Runner/DebugProfile.entitlements create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Info.plist create mode 100644 AdminUi/apps/admin_ui/macos/Runner/MainFlutterWindow.swift create mode 100644 AdminUi/apps/admin_ui/macos/Runner/Release.entitlements create mode 100644 AdminUi/apps/admin_ui/macos/RunnerTests/RunnerTests.swift create mode 100644 AdminUi/apps/admin_ui/pubspec.lock create mode 100644 AdminUi/apps/admin_ui/pubspec.yaml create mode 100644 AdminUi/apps/admin_ui/web/favicon.png create mode 100644 AdminUi/apps/admin_ui/web/icons/Icon-192.png create mode 100644 AdminUi/apps/admin_ui/web/icons/Icon-512.png create mode 100644 AdminUi/apps/admin_ui/web/icons/Icon-maskable-192.png create mode 100644 AdminUi/apps/admin_ui/web/icons/Icon-maskable-512.png create mode 100644 AdminUi/apps/admin_ui/web/index.html create mode 100644 AdminUi/apps/admin_ui/web/manifest.json create mode 100644 AdminUi/apps/admin_ui/windows/.gitignore create mode 100644 AdminUi/apps/admin_ui/windows/CMakeLists.txt create mode 100644 AdminUi/apps/admin_ui/windows/flutter/CMakeLists.txt create mode 100644 AdminUi/apps/admin_ui/windows/flutter/generated_plugin_registrant.cc create mode 100644 AdminUi/apps/admin_ui/windows/flutter/generated_plugin_registrant.h create mode 100644 AdminUi/apps/admin_ui/windows/flutter/generated_plugins.cmake create mode 100644 AdminUi/apps/admin_ui/windows/runner/CMakeLists.txt create mode 100644 AdminUi/apps/admin_ui/windows/runner/Runner.rc create mode 100644 AdminUi/apps/admin_ui/windows/runner/flutter_window.cpp create mode 100644 AdminUi/apps/admin_ui/windows/runner/flutter_window.h create mode 100644 AdminUi/apps/admin_ui/windows/runner/main.cpp create mode 100644 AdminUi/apps/admin_ui/windows/runner/resource.h create mode 100644 AdminUi/apps/admin_ui/windows/runner/resources/app_icon.ico create mode 100644 AdminUi/apps/admin_ui/windows/runner/runner.exe.manifest create mode 100644 AdminUi/apps/admin_ui/windows/runner/utils.cpp create mode 100644 AdminUi/apps/admin_ui/windows/runner/utils.h create mode 100644 AdminUi/apps/admin_ui/windows/runner/win32_window.cpp create mode 100644 AdminUi/apps/admin_ui/windows/runner/win32_window.h create mode 100644 AdminUi/config.local.json create mode 100644 AdminUi/melos.yaml create mode 100644 AdminUi/packages/admin_api_sdk/.gitignore create mode 100644 AdminUi/packages/admin_api_sdk/analysis_options.yaml create mode 100644 AdminUi/packages/admin_api_sdk/example/admin_api_sdk_example.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/admin_api_sdk.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/admin_api_sdk_base.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/builders/builders.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/builders/identity_overview_filter_builder.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/endpoints/clients_endpoint.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/endpoints/endpoint.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/endpoints/endpoints.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/endpoints/identity_endpoint.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/endpoints/quotas_endpoint.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/endpoints/relationships_endpoint.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/endpoints/tiers_endpoint.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/types/api_error.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/types/api_response.dart create mode 100644 AdminUi/packages/admin_api_sdk/lib/src/types/types.dart create mode 100644 AdminUi/packages/admin_api_sdk/pubspec.yaml create mode 100644 AdminUi/packages/admin_api_types/.gitignore create mode 100644 AdminUi/packages/admin_api_types/analysis_options.yaml create mode 100644 AdminUi/packages/admin_api_types/lib/admin_api_types.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/admin_api_types_base.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/clients/client.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/clients/client.g.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/clients/clients.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/identities/identities.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/identities/identity.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/identities/identity.g.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/quotas/quota.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/quotas/quota.g.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/quotas/quotas.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/relationships/relationship.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/relationships/relationship.g.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/relationships/relationships.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/tiers/tier.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/tiers/tier.g.dart create mode 100644 AdminUi/packages/admin_api_types/lib/src/tiers/tiers.dart create mode 100644 AdminUi/packages/admin_api_types/pubspec.yaml create mode 100644 AdminUi/pubspec.lock create mode 100644 AdminUi/pubspec.yaml diff --git a/.ci/runAdminUiChecks.sh b/.ci/aui/runChecks.sh similarity index 94% rename from .ci/runAdminUiChecks.sh rename to .ci/aui/runChecks.sh index 65b6aefa1c..0dd255f220 100755 --- a/.ci/runAdminUiChecks.sh +++ b/.ci/aui/runChecks.sh @@ -1,3 +1,4 @@ +#!/bin/bash set -e set -x diff --git a/.ci/aui/runFlutterChecks.sh b/.ci/aui/runFlutterChecks.sh new file mode 100755 index 0000000000..babe8784b7 --- /dev/null +++ b/.ci/aui/runFlutterChecks.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e +set -x + +cd AdminUi +dart pub global activate melos +melos bootstrap +melos analyze +melos format diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7fda10ecdf..b916e28ece 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,18 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Run Checks - run: ./.ci/runAdminUiChecks.sh + run: ./.ci/aui/runChecks.sh + + run-adminUi-flutter-checks: + runs-on: ubuntu-latest + name: Run Admin UI Flutter Checks + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Flutter + uses: subosito/flutter-action@v2.8.0 + - name: Run checks + run: ./.ci/aui/runFlutterChecks.sh check-formatting: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 43450a0471..ee910f9a14 100644 --- a/.gitignore +++ b/.gitignore @@ -366,3 +366,6 @@ dist # feature.cs files are generated by the build process and should not be committed to source control **/*.feature.cs **/SpecFlow/ + +# flutter +!AdminUi/packages/* diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 8c332ef07a..05f6ab75f2 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,3 @@ { - "recommendations": ["ms-azuretools.vscode-docker", "ms-dotnettools.csdevkit"] + "recommendations": ["ms-azuretools.vscode-docker", "Dart-Code.flutter", "Dart-Code.dart-code"] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 6e15e53a3f..ef2964d8a7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,15 +2,11 @@ "version": "0.2.0", "configurations": [ { - "name": "Attach to Consumer API (Docker)", - "type": "docker", - "request": "attach", - "platform": "netCore", - "sourceFileMap": { - "/app": "${workspaceFolder}" - }, - "containerName": "consumerApi", - "processName": "ConsumerApi" + "name": "Launch current dart file", + "request": "launch", + "type": "dart", + "toolArgs": ["--dart-define-from-file=${workspaceFolder}/AdminUi/config.local.json"], + "templateFor": "" } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 3666534e1e..31c1e80500 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -29,5 +29,10 @@ "editor.codeActionsOnSave": { "source.organizeImports": "explicit" }, - "files.eol": "\n" + "files.eol": "\n", + "dart.lineLength": 150, + "[dart]": { + "editor.defaultFormatter": "Dart-Code.dart-code", + "editor.rulers": [150] + } } diff --git a/AdminUi/.gitignore b/AdminUi/.gitignore new file mode 100644 index 0000000000..8ec354c5e6 --- /dev/null +++ b/AdminUi/.gitignore @@ -0,0 +1,9 @@ +pubspec_overrides.yaml +.dart_tool +build +.flutter-plugins +.flutter-plugins-dependencies +.DS_Store + +# config.json for connecting to the admin api +config.json diff --git a/AdminUi/README.md b/AdminUi/README.md new file mode 100644 index 0000000000..61a489674a --- /dev/null +++ b/AdminUi/README.md @@ -0,0 +1,35 @@ +# Admin UI + +## Development Guide + +### Prerequisites + +- [Flutter](https://flutter.dev/docs/get-started/install) (we are using the `stable` channel) +- [melos](https://melos.invertase.dev/getting-started) + + TLDR: `dart pub global activate melos` + + Make sure to [add the system cache bin directory to your path](https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path) (`$HOME/.pub-cache/bin` for mac and linux and `%LOCALAPPDATA%\Pub\Cache\bin` for most Windows versions). + +### Getting Started + +Run `melos bootstrap` to [install and link dependencies](https://melos.invertase.dev/commands/bootstrap) in all packages and apps. + +### Melos scripts + +For an overview of all available melos scripts, run `melos run` or `melos run --help`. + +### Configuration + +Create a file `AdminUI/config.json` with the following content: + +```json +{ + "BASE_URL": "...", + "API_KEY": "..." +} +``` + +This configuration is automatically used when using the VSCode tooling (run / debug buttons). + +For building and running the app from the command line, you can use the `--dart-define-from-file=` flag. diff --git a/AdminUi/analysis_options.yaml b/AdminUi/analysis_options.yaml new file mode 100644 index 0000000000..8218bea432 --- /dev/null +++ b/AdminUi/analysis_options.yaml @@ -0,0 +1,9 @@ +include: package:very_good_analysis/analysis_options.yaml + +linter: + rules: + lines_longer_than_80_chars: false + sort_constructors_first: false + public_member_api_docs: false + always_use_package_imports: false + avoid_setters_without_getters: false diff --git a/AdminUi/apps/admin_ui/.gitignore b/AdminUi/apps/admin_ui/.gitignore new file mode 100644 index 0000000000..29a3a5017f --- /dev/null +++ b/AdminUi/apps/admin_ui/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/AdminUi/apps/admin_ui/.metadata b/AdminUi/apps/admin_ui/.metadata new file mode 100644 index 0000000000..85ab3daecc --- /dev/null +++ b/AdminUi/apps/admin_ui/.metadata @@ -0,0 +1,36 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "abb292a07e20d696c4568099f918f6c5f330e6b0" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: macos + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: web + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + - platform: windows + create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/AdminUi/apps/admin_ui/README.md b/AdminUi/apps/admin_ui/README.md new file mode 100644 index 0000000000..e75ebdb671 --- /dev/null +++ b/AdminUi/apps/admin_ui/README.md @@ -0,0 +1,3 @@ +# admin_ui + +The Enmeshed Backbone Admin UI. diff --git a/AdminUi/apps/admin_ui/analysis_options.yaml b/AdminUi/apps/admin_ui/analysis_options.yaml new file mode 100644 index 0000000000..f04c6cf0f3 --- /dev/null +++ b/AdminUi/apps/admin_ui/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options.yaml diff --git a/AdminUi/apps/admin_ui/assets/icon.png b/AdminUi/apps/admin_ui/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..382dae628e8273072333df1931401e1f1db4175c GIT binary patch literal 4169 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 + + + diff --git a/AdminUi/apps/admin_ui/assets/mac-icon.png b/AdminUi/apps/admin_ui/assets/mac-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dc1c94a72e04aa6fad0e57148ea41198c892f00d GIT binary patch literal 16216 zcmdVAbx01~(BKlBV8J!GySo$I-RGFV|eLU(<5%TySG2|yzLMYsrq}pP!@2P?IwB2pe(<;|m0)4D; z=G%IX%hn*Qzm)BODL(BeaTE264LGU})w_Q@dHyK6c#jfDM&8QU zFoZXLD&un>M4mS`5RbD;Z)BO{*kAHoZ?sx&9E}6o_&+}!H!k`*sTzq$bwil;-T^ZV z=UaJaS9^_chig?W9qcXNC%#X%8dx?yY0#$|-R}qLHq@@~=xTRm)Di20aV>l7%xt$fYqKh<;aNt1@Vs6?`nf{^K{cD>bTFW*)H zn;iTfY=FOM&qk|WMq2n@8pf;hj|=Il4ghYK$qSpe{dCy-e+;_TqHNqN``C5Ho(AAg zUdWx@Kn4!C>VSTk8|}Exes=8sietYC;as>FLwh4_by_RnB2E7`=Wj>vFMcOUNHxEj;A2OJ#|Q>ir)~lI(8#||N!hm- z^ao^H1!}6^K2%MsDG_@uXiz%L=2H2#ShtiD%z|+kDz63wG=oQiJjk|yB9WzP1Q_O*-o9@I z0~cSw6Cwg9tVHa-(R+hBl%isicX?|Sjkd+T*syIQoF{G|J`L)}G~1GtX=`QjJzh8U6Fjy!V_m%f6p zSmL2=Ld*$%bn9fCn=fsC*PuRxquf?j7p+>d@^c=<1iMPDt;Qi8yC^GNp=&*5gx=L6 z8^_xy$j&yKYAx9q6|7T)EL*2O~G7oi2iGNP-`| z5QNnEUMea*9ad>1WnFR3xtHt2_Rw9tu-?AuViN3h6+e6hMCuPG0%FX0RL&%Sx!CWL zI{~v59&SC9-kyP_`l-sdWx)*uz}SM7<4%ISC)qBE$=CTgKzVzizMJy$x_2bVfelsQ zns*$L?J-b@rh<8EdcbG$+Y+n&xlkxc2`B1h z)=tl98(d#q)HBQXVjw%qkfTr^C>sIMa+!|;|NVhkaMOtwMqQ$0;aSq)*U=GlNMHsO z@Q}PcWv!N~~ytTVt49ADy?O$&?AvD>{JF?iwHXbGYcyG@k zwlB9twVncJXCWI=>x}`5n@pcV_dA&lFJW3XelrlUt%9qwmRxjw3RCse3@OBYiIxA+ z;0{x3I2D75jZpm&-L`i81s6Z8-rGyvZ@$NYyB{mQR~h``gdR&Ba@bi=j3ELjTY5h=g7MOTzs zk`$fG%W=pHi7?5`_UGp1mTHP|XhAH1l}9VP1Trnm_35GdK3RnbK42p*3h7NEE~YRR z>Jbxas7*y&KQ;(65?M666Hfh$ufcv4^4lI2tU5+X46j*;r$P~iDHbU$k6Iv26roE5 z%AN`#A7G) zmp#gHY6-cIpM!=uQ4Pfl;yP_Jnr$02$P77P?2p-N+%-sRuoQca+Uho~@&Vg|7( z2%3I7auoDki-wiO@g@0nZ;OP*i;~o!DGGdHQP_c07fu43v|SV1bQ32I_r0JH++8gb z8e)Xmfi&n>4pocWtTE^x9-;MDV*bLdvJ(ZN4pH!{-yra(i8*$WkPIS*i);)ka`Tj) zn>K1FWC}5tM}4y+dJWcevqwEUHEb=6zWb_ajf;0tl75<`D7*ES0jF5CfD(2_J*{}YcsCRTXsD4tjLLpyD_r^+*#QYY2ht=1 z>cl*6vf>V>A$G*X1VGqGYS9RPp@Q6Du7GgShzv0yP?2f)pa|Shqm;c7l-~T$6NcJi z)9kEcxLxPH|^CLg^i+SbWmLh)s9QuPKNna&D2nK-} zI~m)$`cm=L>=1#=;+|cn1g$MoYC2JIfh0aRo3uY&MMT z$sZ)9wRG(7wH#dUuSkpX7R`uq3JiAQ49I?Rvc?Y zXgEU%Pgu=n-Us%HIDf!z1(%iBLHevhB$7{1@XcgKEe1MY_inIbgdK~;&v0$&Ro;Lf zkwE%^y1T=UB%Ba00ymsq-{v6w%O`*bxadSe_gi-javj?hWKiegrOhqy5|i;xn#4cb zmqe1N?1uq16!ufl7)@{lPLe>xQ)+lDuiqz63np{sUHUUmvG?6@ot3&r0jaC2P=mR9by<2-? zdO=}je##`|L;wVJ9p;h$Arg-C%Md}pd_&(MHCIENzDNcO7AB1E22JsRn_iF)hz|th z7spnk4cO&l^#)^`%u~4UbmjIE6FQ>lFQjCBA{^)-eWW84l{bKMPPJL>?Uwf;J`ssT z!Qk6>o?*{}ffR*`>}7<>?0u;l&#?nZaT%177Yt)CKQW+WhsCw3lQqI&h9V4PhsE(g z%dN26IgY?-1HhjzSC;&Xz;}gh&t6$CXy!(pTavJmiyNx0>qGUIt+vBO;bX4#gu~H-C3?C86G( zZ!0c6ZLxxn--by01)~q7Pu@x-rdgif;#Wd!+RN)lIr)W*STr)c$K8_hi}&;UgJt--Pd*Fj zMqu1)Q7}u$p^szHtl26{q`fH0iTCPVrn4n7qhHI&$+7wMm)Vd?3&Jk7U{F6%vx!Yp z@E@{cQlD|^lC~0j*8X6Kuqk6%3YGM zsYm36xsxlb0M@Y!Qd2yvq>mJ1x7M!xmC$k)UfX@QnrxUOi$IV`OO}1NzFM0p6fAzt z32~>Cxf!%(jWnV#ow{+%c<7!4$C*O&Db~Mw4hmgwi>kzl6qqSE`_$VG!8bG#yw97njgm^?cYmEdgx5=Sf^09H)?s_Nf&u00m4i-|C{(- zz8SS6P+rHD^TY#_K=RV0cu+~!Tx{E?3iM&&!qRSlpHRBIEdt5Y$R>3O;8<=p#m}&Xmdu zMS4x*WI=|nEk1O44c*+#Vv3d!rV7uMH+|V*x)TjfUPItNP>?H;c|dZr+)B3Q;9>L}Hy}dL7iWzp_L_}{4hrtvwKl`i|A7&>cl~BJ5UAVr zLst-48yTUn=>BHPZZn*~B#j*BPc3uiLnAK}O*@dqWsINZkHB;)uQxr_%f)9? zv+dU^w-dbySuf%em_A~wdL^ptn{y_NmnTTf5>vHFqdeR1RBN|$oWXwHSMgM7%q40C zkqTsqvQPKeusU@BvPANbLX9->Ud}a#KVlb@vb3ZKlYvvk3ezvqz%;uJmiu+FeAqsH zt9rSW=eQaN*T2UDrE8+a~}|AhDlX zy>L3~!wjH-7pnbc&w&~}z;QBwPe3NS1_!LtwPaC@Fv)U++!*kdhN9vjk4qv=nU?yts>K>T#7i-+K&wmt2p$)rabs=Rut zkbH~t;xnGh`kTfuno_l@yp+;P#Q)IH28%#YmjE_M_&>8 zbl|&k{KVWhR})t_$3nuUvV}2x!!oPAilRKuNkAIqGimOVq6#R=?$hDUGI<+5FI$2_ z3ZuK-;@>WF>flhB$Gy=s!pO!1UEIr!@q;V#fH};v#Sx8k{^v*3=m?EL7kfG_ituVYlWjk)T0hec>{FZ?rL^@1m zK{p(=H2K-E^*5DbC{3rHaiX%yXRYe=Mi-GDLmf-_x<@M1=QdLgD%@rA5g8SAGSqVC zaeEqqcuNFg#>4UA|7Ojc7*npU3n(&=#TDU>UV zvZ}}N&EirDOwJ0HiVB-c|D0nuQ(67IYDMuBT!^1$R-O-7{C;^6qHb)Xvy}}zKV)p; z53+{Fpb$dmbVUvMUrA+b7R5I!DYWvXt%a13!j_crKZ|CkH_-cZ9BVtiDW3@OWi6Md zYpK@>!xy$Kf>-T3in$pDQhnGuoltEW#gzw&ad;y1tv``fq8iDjD)L* zi>{}KG%D0a!mW-u7U|m@Dcta~9+9YKp+`siIcnDB*2kUBD70VZn;F$#R~bOClu$0N zE?r^pDa9AjB6qq}kf-t3Po5Q!bDE6@l@?=2lt6nwun_At!s+@h-u1oGa9?FYKONfPt8~Y1OD_|uaXV2SjdrqFXE)aO#k64wI zVFO_N*4w|DDk&>VmK^%?-YqSU|E3*3Oa_dVU?!``PlrIDe8GcRI-)6*xXNl;b<;Qb z*>y?D*7d-rtdR&sOe(}JCMDV6s3MK)whVp7UK>Bn<~^nUbF3tg~hD1_Q9l-eLS7+m=rE#@PcSlO)LI}F*9=<6yk!$afWZD7A&D7{oK5O#lkY}atmiXV`2!+J@C;qEFeC|FE+i7T>gnV%ecupe~IOk(au$pFXTri7Mo$^ zG}c_DNEI?fMSAP87~`-3B=30f-b;H8mrxYemnT~p8T)Cd^vYWH|>caIjrV1Dg&c28X zrzn&*)8L087MgM9Li_g9z<8P>mGJ)U2^(-Dj%lpAeWR)K#66gG5eKiFpQcc#k8>!2 ztgw8YqvUU?aA|w~c&6HU9?g4LO45c&@ba4dR3e#u7Z;zFC!M&&Y*vmVFr&g%%?{ZN*fD}1vi>> zpDb)RA2Zr2**$DjH+@~Y&SrTV0FRmDUCe2$Vdh~1f~wNY`~k(^ytrNzG>oKUByifF z2LX@Y&N+c4P1;^({LZjXlP;ZS$$-1u>q@ttx_iGV_RJ}zN#;lq98}VfrLFxRsrB_s z=2L`X@j-i8$*)hi>(jV4ZD&{4QTx^BH^FPSMeDD-Z1^o3X>D2F<^0MLyN(jMQxgR! zenOuccE{6#tS8LNW|94raLi1(?=E@43*=U!ybacKRmsMekKb<2zmrZ4%Wgh#U48cFCB#}$0#GEEhC4ek6Lu5EIXIZAffv=>L z2IZ?HL@E?O81l#!@rY-=a9KTNCW(xUl90zdT98{p5x_^tBt4UBG%{a5D`BQYB`ple zA1_2qY)Fn=r=HA`zHi%YaO?ibOmdm0hRocGg_$f7Re?xAN^mCEcy6{{qEHF0q&S5< zRtOaZMIc6eWME)Xk7t>aGs;4D8S&)v397JsqKZU9f)WmlSpk0miqiwOp+a$ybRn~J zVIC7BUFeALkTJvPcfH_l;;_}3%nHA&3 zP+?PHiC`cYMd$jSEay-7=Vz7#a*-i8g@n+TQ>5~d3j$IQd|?P37Wfor>g5vZDUIXA zP#qXT3Bla3YFPISsBNG#`PnGK1o(u6EPs4$R7@SIlt9+U0X6i-okfEa7RHq}ks=l+ zMMZI7fMxPcF@{Q&s?&~NORHMUqe$@64k32_fjeqUp2mkW4Z?UHIfa&Hj+Q8ZDoz?J zHWC=(#P3O?Z)Lf7I?1u>lXr~#3nMSDn1V_ykXa1eEPxT3Hji0Y@mknGq&yaxNC4T7 zZ)CvIvbiIl>3i-3HY5rJ3Yt7xVItIIOppjp9%5`bMPi;=n26BFCxj4!pU~KV)tITS zuu1r=AA?fMPM$bpJc$>Vey^6baJDK0mx{vK}JPy7zS@9mUx_Q-|4l=?Ny`*1uT{Yis z@IPYS0NSmU@vH8VThiayDmunGa|wQTH391Hlz`xGU8&I{UHyPXAkziHi_25h3*drh zN~aBI+Ytm*^9J^0FQ?w^d9`F)oBaRfB60rl^3WDp^1^hCNCPsjSsJ^Kny+3JHlIDv z6eDbt*#x-)Y*LFnB1Jg+4ig>H!2|PO5gIwYLS9vJ>{2IHF`bS)JMgTGH~n+bVMahK zk=csr#dS8U2k%Vxan~eX`+?x{f}fj5!)OAs?cYZJfyo{SR8OmD_ZO3?+5{DgXuU`R zY0}>hUUMn5X3 zzaiX$lsrWtS-H9VDmRL_Pg$@3Zi;w|UUTFrbo~*`F!|Gn5S$-t4tZfC%51 zILHOQr>^bf$W#&z)VlvKca8j>52AKWi$JYg9NNSi!}KtY6I^3pMYLTdfa;M_hO+<4 z^UAoAi(#=-NBGFIDWgO^*lPH&wcCo~dr}UhioAgTsR12`He2P&b}}EDhnjNucQ!m- zK!N#1*LJ^Qy3qF*06I&5(XIy-*{hvjH27iZG*a+7c4iSo*u12MbaNjp?k^h>1X+my=T8;vdqI7ba(>TKR+ZHU{lD>hlj+e~(s|E0H4`t=j-1@o-;yzP zR;}*QZ*Ik2iZpI#3&$JH(L5ZQQ#!sQ-7X)WY{pR`dL%rqWI=iHKjgSQj9PhjarX3`2U6pFHH4qmoT??? zIcH8z_TtJDEA$`vdwPEv`)^2T?cbaD?~IS|#BT7pp9jOFzqPOZQ)B<(b@=FeT#27J z6Y@q>lMdd)Du9U!pRaDh_^WLnPd%Q-|7a+GDcj1Y#wV&^t?=}iZ7nS{LATPaN_4xD)MErw zkt_1kPu9F9P1T8I)Drw?0C+{#Nc}s*ZJ7Tkz+cg^myjEY{jz5967;fJ5Qtg9N7AcI zeYf!ag!GUWtEO%6Qz>!Z)5PK?ns91yKMdxN|D(zoxj$6mug);OzkS(_UqH;@5UgfT zEd?TMqT!YiFc~0cHZb}8@1>q~6Up`OUWyIjs$V&5G#XCdyz<1}e zuZC#;OM|_9saFe>l;$UEBYm!2dKX_Ll%uwD0uq zT-Ongn(EY|K^T~n0^|H(Mz(fC6yU#RH>HV&e@#<M?0|Z-UeX(r;SkI&JuHMU*Rtaytn8WsBJ71AH;ygcW35l2x_fA;&B+v z>wNFYAH03n`Q6{DuRk50EZ$ps;sJO-1MPPUsSo7|3(3IdUs`%^Sm85_v59LkfANQbUfGak%I0{2JQRziDcP?q&uBSZa1OS)1SiFw8g!}_4rUp!k%4C_P-G**p% z4D1IdHc;W?r8Y*WY%M4-F63@k7@)3w$7PRuPs3_x&7a3?)EA?VZAj}@w~I;Rm{!=o ztu%3j;>%;nt3=NgHupa2V{>GOmbFb#YYM-6to9wu;1ubfnyBZ-Assa?+Y$VqJD-+! z?219^U~dJkKbE|2FOD;3utoJH%qEgXF{au|HyjzxRc|Ms50iE>SA{qFs59eXESc<}arEC2sH8{Zut zkT>9>>-+y?{__FP2ln5R4gl_&_&~FtiIJ=rhDnvURKT&?&T|1-Z|K9D%Q1Af8dmdz z^t@ClV`aW#PVC6=!(f#f9t-JC=|Q%DuY9|WpoI7gPL7<3(vg6Y(BC>^HC{`1vDB^A zJaU)@0-k_g&agWCCSsdc5zv?Dm$M>y0gsd?gJ;RE$CD-b%dwUR4jtXm;a32zV5#Un zrZLI4n(Sua1#%f|1!H$YTbe)TIGWdbs_-;eh^m>O!eH=qJe)B2_X8W$e4q5x#Hg2a zx2o!k1nOS5&g35H(@OE!maGDEA}X6K%;T5~(Mr7suGwGtSB_%2*xz_q_CmUb>fOHH zj-jT07my%5Bv^rC_6W%=&VhtP@`MR?T;dSj>UywxBbnL;-dUqrnbikhUqv`7+hSKB zLlF!<4z9r!nkQXEoR=ujp)eJE4xD#xDQyKDR0}lwGx3tuWA`;n7pv559hAU zwuJR-3E%R>U*bLJl1$Di>XBvgiduh=b45=GQh$ER!YE-2g?yty^>%20U_3o+KP-0B zqA!3^Kk11ca7GO)wH278SmpwO!e4v{YOAoLZj*7LFATYN(@h+sV61q5=vr@4 za%`HYlQP>FR28{iC6gtD1-3EuMVzlW^0e^bXOxOfL{$>Huy@YtbTy&wodKL!bwk6% zo2lzLmSTMf#Z-E8X<+D4@WSBgEnU9JnS~*`Q~Qbk~VhGRTDAiO#DEM+~em0;>{%SJ(3F-Of| z4T%PNcZw}Hk7-fL5@%d=s`6`CXe}iF*6)y@S@BY8&aA7wM8Ez;^D<}y-)xJDgi44y zK8FR%{>et`t^o80=92cEOqWdw5k1U#;-4|Ou|bAdUTtWba9mULPszoQyJo_Ph1MBo z-Lr3%ZQVXc0dlg2!9{D!BMYGUNE1!0p=ga*3*4ytzUc`>$n9K9D3EfGEOH}ZvT`)) zB!YLA<#ippzEVYPxlvL6)u1Y5uupjAwtO*oL0!8+e!IWNb;Fl_1e#dOk%e;{sx6FWg4%+m#wDgzmpS_OZm*&j7LQkVH%C-!Q8l|yn_%*W3 zb=mma$B}|8%%R&0K0D<@%$0vBml30^h-}@C|i8%(k3s1A6&|AV}eDU#Dy{ z^#Z-xD=(Q{qrRGjAdafILMHl5F@}tgOGomanBR8nHITUT_y%}5DBMQ&IL$FuxDFwGqPf<@>{VA)_#fc z$CBlDEuo6*eyjk0VB*9nvupcJ1 z_se{tWihtDygLOsyVYLll;l_T(o(bHFkuo*F0J?CXlM5Pm|{rM*l zo^6B6`TdCJq$&{dj<{(yjf$_>EZ&Js1Mxz8RD-Qf#|l!L7GsCaT{XeMz zZ_%4;jNTAdhG1^Y2+_Fen|VVPFWj+wBD_17sFC7Q@;g?7nK6%vc&qxt+5B+hr{R;P zq#CnNqOhoZ)4q%`b2$0GIBSb8L zunuL`xqf#Faq^Go&GKwR>io2p)pM75Q(r+dJ8VI~e(IG>GdN@0DrzT$m%>(bcv>u) z}2_!hIcK+pOGR)@GiEVtRIAzo40>&U8P43g^Q!rGiFB9g@#PhL9L5-)L9xk$V;up5U25(7!V| zI@V3QJUeo`d?k9bp>43KVuyV(eHf8Ysz4;AapES^kYhb@o2FuDjq>I3(j#LOk0zil z$&pQVgrz8CvPl?)A?t%i@|Mb;6kqwgt=i!Q5>b+P`^iVkF~jq8f>9O9zi4bTusD2N z9?O90nIKE4?;^HZltI8^ubrKA-CtV|W{LmKYBA8_BBoGR?Sv4_P`j75wV2|TU(~}c zizZ(bH3SlxM*0gD?-zXD_8a^Y!+xmbUy^{3KEp_4GCT$=DX-}$rc0h(EOK1u^7KS5 z^rd^nR8JOsaJv3Lfq2Z6B<3fb*k6JiFbaGHXk3-x3s!f(xk{G5^oLpkR))~@iRdhM z0X+f%{N`>8=-$ij2qsfcN$WM=`e{yF61x~Zx6g3CDK33ZokT5xb!tr@07b1|T>mP0 z8>7&@+)<7DYnSrn>y^pRV1#rO^3Q+rwJ5|<#N{;|h={57=`CS5M?&7Ti6Mnar$WIQ z7Cx1SC*>P(8N0N;7(IV-ZVL-Ct5uC8!G4+0b@`3~vXVe{x|mP4YYf{yR8Q%b*1j@> zREfzq?jt4sYkhRLHM}1)F!qoJfR0(@gH+b~nbX_na`-~=(qIj`5F4ql z8w504)6s8-gS8~7`_r2Pn{jqH(%BNyd|>?RXl5gq5}^l7 z`9R1hi<>y>UX`L58pXt)u(Re+;Y3%5s;QR=n@;Wp6*FsCxzsAkoJ?Ty*5atuEJ{h=aID2 zS&(}hDyOlCmA6I_&qHr+tOZ}=5ocg8Rs%qesCFlylOklr_Z0+0Z(Y2y8*@VR{@!^v zyOB^;WwM!ZccgU80e$7HLr22@hdzH;SEX}nl;s=gJbbc{{jN08f zm;J$yPn#3x$}Q*CrAG6})uUv~oz-?}Ha`NpZH9~ebvA9DzoM(X#Y_cGml@Wg+reg! zh-F87BN}W7l`Y(|$03<(Klvo;SrCuWPV{?;aYl~Njrcbs4o?|1+!QsGxH?}z>IF6+ z=+RcOr-cce(Kh&$lpVy#Gf&(i!f8S7iW)_~zk2u!T(i-&M?;Aw=C$Uh`$ha~7a>ZcF%U4B(C7M#AD?`KCag7dLc3)bemzBG(W!r% zko%(6g&>Fser;Uma*2>{#-eE3s`rB+c(Y%a-3d1{4xcbVe%9erVA&1m`PDuMP zo!kc?_RBl#js~shRE~TO-_eNrcuKu~I%b!|U&w!w!>x>@wJWi}9}VS9u~8?rY^877 zhP&42C`d$#RRFn^8KHL9O02)sm>twM;AQ*ZlsVs6ij(&#BL1E2Fd7SJ_rt#C}Lo-vT+FpxY}&PVtNH zeUS!H%==YbE?aq45Innqu{dn+`#IT)`eI%uvR@aeFm71ZKZ_O2vDZ_8Ahh@;${PW` zqZ7MzFVB?3rpnHpo9};@=|?GHz6zTv z#J%AaR!?chstZzON-F-7!^ z+~ld%2I06@2p(lx5TY?r;PCrBk;1Y&YpM2p#$`ft7CNOW0Pv<$~i!>qzGsekhH2gpWb;TrfGwqPZq^Y244$SV^i z(?E)*k`46{F1n-R15Y)v@s_i?5mOIkz*>CPoTYGsYEmEFziYG83S#hFK0uv=UIxEj z34IF{=CQn?EXQ|t@ms*sz*r$hlA#gdldRGftudbcrl{e?N6txJ5O;I{6*N1aFtI+` z#0GO5FSDtvHmT9^Z6&3)0pDuz&ruHuBGR=T$SNHKgG%ik-rf!;61Wu_5{6-S^qCb{4PvYt4?E#Gcof;!z5bECVK_EFs+eWtO6zz- zEpc-xY5F2iR5|<>8;(c^a!;*kT+tZvlXC5^mRMmITok=0cppJ$VYmv0(%?@O7ugqc z&U-i)S`45=?;lA8TFkL8!*Q4zD^zt)o#1Zqejb^p{E| zvvPB2%Hz2Xtkp^PgaY!uyG!Yh`066Nf~{&L-;QE4NUAn3Q)sx+ej(a)FH1$FLjGu7&I}RPZT4(&--5dt ze@~8ZiQ0w&xFnKL5U&No@$eE-L11lZnqDEt9(jRER}y6kk&M?PyH5p2+Vu5!u&{tj zW+ux_yqNTa1L@y*R>+r$@M|@bD(Z=}`Lkjl!uG9;&61LR^AoA1N_xh)RnzQSK@}!* z``Rc>mepAY*{rGh#X8p6wKI@#OgbBWW1*pcX{Bt zkg)nQr*44AJKiXA<~7X{sJ4BF*M}bn=&DP!Y)3wyzb25G13L2-p_?+Yf{HJ4F$WbF zMBHN8Gj7Z*YJ=@_PlEL$JMvTxVIMVrzNh~x-DnfG)3C_V96Ta1goM~Z@d6?R78*9D zZ4)wj(5$~vUO?Vw=D=+IY!oDOD|H1L9mZ4&qYZ2Wd|9_2C=>YQ9%k2oUcVxwYqGbu z02bxYl5`WZExTH)03Y4li$+LRkIIu+s9fxVHYI8PN1^L!ME-6{O0gbbD@{N4a|nvV zs~v)-{8Gb?t=evZ*GFno1S6?B+zh%}Q86{LtDVOw3Ds9^lv<7qCVN}9E@7PEN$CY; zqP?fY-b~k2Q^2zYql@vi9}*fyJ7fw*R@yVTlp__^VQ;GTJN67%mO911U(o(N|3CLm BCYAsI literal 0 HcmV?d00001 diff --git a/AdminUi/apps/admin_ui/lib/home/home.dart b/AdminUi/apps/admin_ui/lib/home/home.dart new file mode 100644 index 0000000000..02c8e2b62d --- /dev/null +++ b/AdminUi/apps/admin_ui/lib/home/home.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +class Dashboard extends StatefulWidget { + const Dashboard({super.key}); + + @override + State createState() => _DashboardState(); +} + +class _DashboardState extends State { + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} + +class Identities extends StatelessWidget { + const Identities({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} + +class Tiers extends StatelessWidget { + const Tiers({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} + +class Clients extends StatelessWidget { + const Clients({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/AdminUi/apps/admin_ui/lib/main.dart b/AdminUi/apps/admin_ui/lib/main.dart new file mode 100644 index 0000000000..3513a20db9 --- /dev/null +++ b/AdminUi/apps/admin_ui/lib/main.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +import 'home/home.dart'; +import 'pages/pages.dart'; +import 'setup/setup_desktop.dart' if (dart.library.html) 'setup/setup_web.dart'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + await setup(); + + runApp(const MainApp()); +} + +final _rootNavigatorKey = GlobalKey(); +final _shellNavigatorKey = GlobalKey(); + +final _router = GoRouter( + initialLocation: '/splash', + navigatorKey: _rootNavigatorKey, + routes: [ + GoRoute( + parentNavigatorKey: _rootNavigatorKey, + path: '/splash', + builder: (context, state) => const SplashScreen(), + ), + GoRoute( + parentNavigatorKey: _rootNavigatorKey, + path: '/login', + builder: (context, state) => const LoginScreen(), + ), + ShellRoute( + navigatorKey: _shellNavigatorKey, + parentNavigatorKey: _rootNavigatorKey, + routes: [ + GoRoute( + parentNavigatorKey: _shellNavigatorKey, + path: '/dashboard', + pageBuilder: (context, state) => const NoTransitionPage(child: Dashboard()), + ), + GoRoute( + parentNavigatorKey: _shellNavigatorKey, + path: '/identities', + pageBuilder: (context, state) => const NoTransitionPage(child: Identities()), + ), + GoRoute( + parentNavigatorKey: _shellNavigatorKey, + path: '/tiers', + pageBuilder: (context, state) => const NoTransitionPage(child: Tiers()), + ), + GoRoute( + parentNavigatorKey: _shellNavigatorKey, + path: '/clients', + pageBuilder: (context, state) => const NoTransitionPage(child: Clients()), + ), + ], + builder: (context, state, child) => HomeScreen( + location: state.fullPath!, + child: child, + ), + ), + ], +); + +class MainApp extends StatelessWidget { + const MainApp({super.key}); + + @override + Widget build(BuildContext context) { + const colorSchemeSeed = Color.fromARGB(255, 23, 66, 141); + return MaterialApp.router( + debugShowCheckedModeBanner: false, + themeMode: ThemeMode.light, + theme: ThemeData(colorSchemeSeed: colorSchemeSeed, useMaterial3: true), + darkTheme: ThemeData(brightness: Brightness.dark, colorSchemeSeed: colorSchemeSeed, useMaterial3: true), + routerConfig: _router, + ); + } +} diff --git a/AdminUi/apps/admin_ui/lib/pages/home_page.dart b/AdminUi/apps/admin_ui/lib/pages/home_page.dart new file mode 100644 index 0000000000..94efa8693b --- /dev/null +++ b/AdminUi/apps/admin_ui/lib/pages/home_page.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get_it/get_it.dart'; +import 'package:go_router/go_router.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class HomeScreen extends StatefulWidget { + final Widget child; + final String location; + + const HomeScreen({required this.child, required this.location, super.key}); + + @override + State createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + bool extended = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset('assets/logo.svg', width: 30, height: 30), + const SizedBox(width: 10), + const Text('Enmeshed Admin UI'), + ], + ), + leading: IconButton( + icon: const Icon(Icons.menu), + onPressed: () { + setState(() { + extended = !extended; + }); + }, + ), + actions: [ + IconButton(icon: const Icon(Icons.logout), onPressed: _logout), + const SizedBox(width: 10), + ], + ), + body: Row( + children: [ + NavigationRail( + extended: extended, + destinations: const [ + NavigationRailDestination(icon: Icon(Icons.apps), label: Text('Dashboard')), + NavigationRailDestination(icon: Icon(Icons.badge), label: Text('Identities')), + NavigationRailDestination(icon: Icon(Icons.clear_all), label: Text('Tiers')), + NavigationRailDestination(icon: Icon(Icons.person), label: Text('Clients')), + ], + selectedIndex: _selectedIndex, + onDestinationSelected: (int index) { + if (index == _selectedIndex) return; + + context.go( + switch (index) { + 0 => '/dashboard', + 1 => '/identities', + 2 => '/tiers', + 3 => '/clients', + _ => throw Exception(), + }, + ); + }, + ), + Expanded(child: widget.child), + ], + ), + ); + } + + int get _selectedIndex { + if (widget.location.startsWith('/dashboard')) return 0; + if (widget.location.startsWith('/identities')) return 1; + if (widget.location.startsWith('/tiers')) return 2; + if (widget.location.startsWith('/clients')) return 3; + + throw Exception(); + } + + Future _logout() async { + final sp = await SharedPreferences.getInstance(); + await sp.remove('api_key'); + await GetIt.I.reset(); + if (mounted) context.go('/login'); + } +} diff --git a/AdminUi/apps/admin_ui/lib/pages/login_page.dart b/AdminUi/apps/admin_ui/lib/pages/login_page.dart new file mode 100644 index 0000000000..29fc7d23ab --- /dev/null +++ b/AdminUi/apps/admin_ui/lib/pages/login_page.dart @@ -0,0 +1,97 @@ +import 'package:admin_api_sdk/admin_api_sdk.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get_it/get_it.dart'; +import 'package:go_router/go_router.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class LoginScreen extends StatefulWidget { + const LoginScreen({super.key}); + + @override + State createState() => _LoginScreenState(); +} + +class _LoginScreenState extends State { + final _apiKeyController = TextEditingController(); + final _apiKeyFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + + _apiKeyFocusNode.requestFocus(); + } + + @override + void dispose() { + _apiKeyController.dispose(); + _apiKeyFocusNode.dispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Enmeshed Admin UI - Login'), + ), + body: Center( + child: SizedBox( + width: 300, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset('assets/logo.svg', width: 200, height: 200), + const SizedBox(height: 40), + TextField( + controller: _apiKeyController, + focusNode: _apiKeyFocusNode, + decoration: const InputDecoration( + labelText: 'API Key', + border: OutlineInputBorder(), + ), + onSubmitted: (_) => _login(), + obscureText: true, + ), + const SizedBox(height: 20), + ElevatedButton( + onPressed: _login, + child: const Text('Login'), + ), + ], + ), + ), + ), + ); + } + + Future _login() async { + final apiKey = _apiKeyController.text.trim(); + if (apiKey.isEmpty) return; + + const baseUrl = kIsWeb ? '' : String.fromEnvironment('base_url'); + final apiKeyValid = await AdminApiClient.validateApiKey(baseUrl: baseUrl, apiKey: apiKey); + + if (!mounted) return; + + if (!apiKeyValid) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Invalid API Key'), + backgroundColor: Colors.red, + ), + ); + return; + } + + final sp = await SharedPreferences.getInstance(); + await sp.setString('api_key', apiKey); + await GetIt.I.reset(); + + GetIt.I.registerSingleton(await AdminApiClient.create(baseUrl: baseUrl, apiKey: apiKey)); + if (mounted) context.go('/dashboard'); + } +} diff --git a/AdminUi/apps/admin_ui/lib/pages/pages.dart b/AdminUi/apps/admin_ui/lib/pages/pages.dart new file mode 100644 index 0000000000..bac7e17980 --- /dev/null +++ b/AdminUi/apps/admin_ui/lib/pages/pages.dart @@ -0,0 +1,3 @@ +export 'home_page.dart'; +export 'login_page.dart'; +export 'splash_page.dart'; diff --git a/AdminUi/apps/admin_ui/lib/pages/splash_page.dart b/AdminUi/apps/admin_ui/lib/pages/splash_page.dart new file mode 100644 index 0000000000..0fe6ab31ca --- /dev/null +++ b/AdminUi/apps/admin_ui/lib/pages/splash_page.dart @@ -0,0 +1,64 @@ +import 'package:admin_api_sdk/admin_api_sdk.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get_it/get_it.dart'; +import 'package:go_router/go_router.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class SplashScreen extends StatefulWidget { + const SplashScreen({super.key}); + + @override + State createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + @override + void initState() { + super.initState(); + + route(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset('assets/logo.svg', width: 200, height: 200), + const SizedBox(height: 40), + const SizedBox(width: 300, child: LinearProgressIndicator()), + ], + ), + ), + ); + } + + Future route() async { + await GetIt.I.allReady(); + final sp = await SharedPreferences.getInstance(); + + if (!sp.containsKey('api_key')) { + if (mounted) context.go('/login'); + + return; + } + + final apiKey = sp.getString('api_key')!; + const baseUrl = kIsWeb ? '' : String.fromEnvironment('base_url'); + + final isValid = await AdminApiClient.validateApiKey(baseUrl: baseUrl, apiKey: apiKey); + if (!isValid) { + await sp.remove('api_key'); + if (mounted) context.go('/login'); + + return; + } + + GetIt.I.registerSingleton(await AdminApiClient.create(baseUrl: baseUrl, apiKey: apiKey)); + if (mounted) context.go('/dashboard'); + } +} diff --git a/AdminUi/apps/admin_ui/lib/setup/setup_desktop.dart b/AdminUi/apps/admin_ui/lib/setup/setup_desktop.dart new file mode 100644 index 0000000000..728426f881 --- /dev/null +++ b/AdminUi/apps/admin_ui/lib/setup/setup_desktop.dart @@ -0,0 +1,10 @@ +import 'dart:io'; +import 'dart:ui'; + +import 'package:window_size/window_size.dart'; + +Future setup() async { + if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) { + setWindowMinSize(const Size(1200, 800)); + } +} diff --git a/AdminUi/apps/admin_ui/lib/setup/setup_web.dart b/AdminUi/apps/admin_ui/lib/setup/setup_web.dart new file mode 100644 index 0000000000..a8c68561e1 --- /dev/null +++ b/AdminUi/apps/admin_ui/lib/setup/setup_web.dart @@ -0,0 +1,3 @@ +Future setup() async { + // No setup required for web +} diff --git a/AdminUi/apps/admin_ui/macos/.gitignore b/AdminUi/apps/admin_ui/macos/.gitignore new file mode 100644 index 0000000000..746adbb6b9 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/AdminUi/apps/admin_ui/macos/Flutter/Flutter-Debug.xcconfig b/AdminUi/apps/admin_ui/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000000..4b81f9b2d2 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/AdminUi/apps/admin_ui/macos/Flutter/Flutter-Release.xcconfig b/AdminUi/apps/admin_ui/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000000..5caa9d1579 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/AdminUi/apps/admin_ui/macos/Flutter/GeneratedPluginRegistrant.swift b/AdminUi/apps/admin_ui/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000000..f717508927 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import shared_preferences_foundation +import window_size + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) +} diff --git a/AdminUi/apps/admin_ui/macos/Podfile b/AdminUi/apps/admin_ui/macos/Podfile new file mode 100644 index 0000000000..c795730db8 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/AdminUi/apps/admin_ui/macos/Podfile.lock b/AdminUi/apps/admin_ui/macos/Podfile.lock new file mode 100644 index 0000000000..0ab7669657 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Podfile.lock @@ -0,0 +1,29 @@ +PODS: + - FlutterMacOS (1.0.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - window_size (0.0.2): + - FlutterMacOS + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + window_size: + :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos + +SPEC CHECKSUMS: + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 + window_size: 339dafa0b27a95a62a843042038fa6c3c48de195 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.15.2 diff --git a/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/project.pbxproj b/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..6a3a00d273 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 54A9498E0709C059D43C7024 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 352EE72622EBA5B521A8C5EF /* Pods_RunnerTests.framework */; }; + 8573E044A822EC41EA86DA3A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D15F9AEE3F5A4802A3B9A5DD /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 153F75C7E1E30A5FEE84E0A9 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* admin_ui.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = admin_ui.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 352EE72622EBA5B521A8C5EF /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3716C1B835AD79FD1EBCBA15 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 68ED58E82EE19B6FDA515C36 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 6F4A83560B0FAD79B7FDE0E4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 7E79448114A88076EFD68D96 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 805FA15CD9470B1CAD88C9AF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + D15F9AEE3F5A4802A3B9A5DD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 54A9498E0709C059D43C7024 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8573E044A822EC41EA86DA3A /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + E54B6DE933026B1980C5EC75 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* admin_ui.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D15F9AEE3F5A4802A3B9A5DD /* Pods_Runner.framework */, + 352EE72622EBA5B521A8C5EF /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + E54B6DE933026B1980C5EC75 /* Pods */ = { + isa = PBXGroup; + children = ( + 68ED58E82EE19B6FDA515C36 /* Pods-Runner.debug.xcconfig */, + 6F4A83560B0FAD79B7FDE0E4 /* Pods-Runner.release.xcconfig */, + 805FA15CD9470B1CAD88C9AF /* Pods-Runner.profile.xcconfig */, + 3716C1B835AD79FD1EBCBA15 /* Pods-RunnerTests.debug.xcconfig */, + 7E79448114A88076EFD68D96 /* Pods-RunnerTests.release.xcconfig */, + 153F75C7E1E30A5FEE84E0A9 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 15A9B2657EC1A4E9B51C21CD /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 7BF10ABDFC5EFE3000BF100D /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 7A2A6C9EF96FCB16D0BDD476 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* admin_ui.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 15A9B2657EC1A4E9B51C21CD /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 7A2A6C9EF96FCB16D0BDD476 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 7BF10ABDFC5EFE3000BF100D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3716C1B835AD79FD1EBCBA15 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.adminUi.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/admin_ui.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/admin_ui"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7E79448114A88076EFD68D96 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.adminUi.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/admin_ui.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/admin_ui"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 153F75C7E1E30A5FEE84E0A9 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.adminUi.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/admin_ui.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/admin_ui"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000..1711546665 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AdminUi/apps/admin_ui/macos/Runner.xcworkspace/contents.xcworkspacedata b/AdminUi/apps/admin_ui/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..21a3cc14c7 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/AdminUi/apps/admin_ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AdminUi/apps/admin_ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/AdminUi/apps/admin_ui/macos/Runner/AppDelegate.swift b/AdminUi/apps/admin_ui/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000000..d53ef64377 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..96d3fee1a2 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "info": { + "version": 1, + "author": "xcode" + }, + "images": [ + { + "size": "16x16", + "idiom": "mac", + "filename": "app_icon_16.png", + "scale": "1x" + }, + { + "size": "16x16", + "idiom": "mac", + "filename": "app_icon_32.png", + "scale": "2x" + }, + { + "size": "32x32", + "idiom": "mac", + "filename": "app_icon_32.png", + "scale": "1x" + }, + { + "size": "32x32", + "idiom": "mac", + "filename": "app_icon_64.png", + "scale": "2x" + }, + { + "size": "128x128", + "idiom": "mac", + "filename": "app_icon_128.png", + "scale": "1x" + }, + { + "size": "128x128", + "idiom": "mac", + "filename": "app_icon_256.png", + "scale": "2x" + }, + { + "size": "256x256", + "idiom": "mac", + "filename": "app_icon_256.png", + "scale": "1x" + }, + { + "size": "256x256", + "idiom": "mac", + "filename": "app_icon_512.png", + "scale": "2x" + }, + { + "size": "512x512", + "idiom": "mac", + "filename": "app_icon_512.png", + "scale": "1x" + }, + { + "size": "512x512", + "idiom": "mac", + "filename": "app_icon_1024.png", + "scale": "2x" + } + ] +} \ No newline at end of file diff --git a/AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..535e48479514e776b22e3cbf21cff1abb4773997 GIT binary patch literal 98631 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
UurNJi zOvZ>NzREnrqbz6+Y-MYE#0VO-HI@69xq34Z(bU$bzTvge;~u`IV&pQ=ymLK)Bd>Db z@`2+YRwa0buuU7IHHIVJOJ%gGq16LpEJ6|WKc9TNA*`zR<03BjI!W8~^1yJMkv)#o zvGSxOa!&Bt-r*xBF&~e5tW}Ma{p1$D^Q`SRD^a>*ram-!MPO{4!Mphz*J!TNzZvk6 zumACQvMRsZnD(XDY@5dkr}bcad#95U&Sz4ObJKli-Qv((Tei--*n@S|DpH_W>*CTR zMjsg(+L(g7v(Ax52#hjiO6z${mlQzzAR9Mg!v2k*n|8|O4&xbjxq4I1sE#K0tivrl zv+MhoS7p?C9Br0uk=XPkDS784Tn48K|45||-+rxvoyFn%XD=sL)ut0{R7WfyBaJz) z552?b4EAqb^WG{D*eB@FC@LzVbMn@Iucw?sCYyDKjMt7`StURehx%k8IAZV|=f}`w z;Xm12#$)U^ZDrW%^h_a3n)Q6ok_<-{1i(on?c3HeS#Kmds*sdZjtvJj#;0M&OXfkv z55QD@Lz+0#C5D6zb{>etc?FRxOO$FbM3L#rOR3+99DQ*L=XY;7KcsOa)$Ix(d^Jsq zKJ-bkB>P47Kd^d3y1f)fKdevGzdyj0d9v&!QOl22)%V9S$=Y`Q_0>_YN5>=6t1}k! zW0Xjam5(&Er{>m*s&RhkxnWVw=A6c1O%;A}jrHr)JL^=n&}y2uyS@6V&!vOPrWK5sCLh9_{*% ze_?X$f!>--N(}xuOGX=7?f5#g??qBx6|12i;33ax1~Xv=ryN6>=_U11;l$J1Rj8-% z8F`r_fftVXQN_#`eus>s8OtX`RZ$1e1V3jyk5Dx5r^{9yfAftx9DiBNE`NXf>E6ti z{exkc@%6Mvj8G?e(^tHs_J8hiMCv1^f9-E=J=cB(4bll#Xkds}t&~!ocNd;4Z`MWg zN+6O3EHd!A@CzdNwY*r=KyN%e9J5!Ol@UJY1UoW-}jqO01OLZyS7jt zoa$hf*@?rmMKHum1pmk3*K5;ft37vFXET7C+kX z6F4-9yf-uC+5lU6AhNKDj+YQ!etIw1x2HG!-C9bN1b0%@qv=)yP3dalnU){^Gg)Um z-}KVOJM^5qBz@6MwUg3cxF_bF#Cm@5WOe_Xqn4}?z;5ix0db0q?lSgZVZ1hd#WFw8 zgYzB|4?4LLP&gC8Z-I}v%$EBS^8BK&L^9(nzsyt6*o?)$PJeWCaG^lMyyKm9p25tP zivnBg*Epf14Y{@~yI6}GtO}|xj`KRTu@c`a=6{xW$%mao`JHJUj~R_MD?QLJ*9&L0 z42Z;d5+1mi%rW$L$*BbePEN}5TK5TQCset3`bVi}%2w&KPP6F6NWX^u$9=5C&N>d$ z6W<=!^bA`LbPQai<97bVDuF~s%tQRnWC(J2hmJep(vr&LkFu|dN_Pl(&^ zdi3^}f54l6AR!G;=@>rPmbg>O{fy{biA0*(ACT8fR2>y-HG7UL_|k$ESupDi5h0bIyti+n^%+Gb&T zvDi3f8nqELHA2z;t|gOkQy*T2dYb0+i;!4p$lF|$n){q^Fzp$nz$>rrYj~Ge=v`d^ z)}*I=?b1Gk@5l+O*q=_fVe2fjnMmAc(OjM_8qul-@5cyUl|vj`ie^%chHdv zK0h7?yRDO2j*r)cE*Zf_z=t z;BcXi%)}S;SH=ISIFI`#z5R(0g?c`_2o%4L?n*zJM49o@J?|7bD|mO#p8vvPb?u;; zB2_Uzv&S!E;o!Y&Gsk(hdu4*P6=u!9b#zo9cQfAClFe3oADw!f>J2ry3~Fd)BA%K= zF8>xdQgm)GRHxPddit$F_~te2%drD0@kSyY3U#~Q&h`9-cuq(H0YZZcEUgzD2^70O zN2U}hzrk#4#ae~%}+R)pZcu0EY{K{RQYn; zdo!yYA)7>MZ3Q6-_blFSmO=eem$eTyc&=DRzx74fEFHbmXE#m-$X^1wx}Kn}2Rm-a z6jmz@p#BvgBS}~P;r`%Z!|FECqpk|Eu6xd>l3F+X2D21m&2MCCg)KCXb5;t4=#>~; zJ0lQV6OeiBP0MYS50^%TZ5^bYt{vN?5WLM>0!L2{8^;XJJF=Txf2>tc0-zwLV4f^k$G?S9Yj zQe^#ZZsY7=|6H>D0p)`>Rs=DDXGyHcK1qMwG5E+IlYIGncPGSh0&ow6dAymIip)Ir7UShLkgYp&@? zZ2V#f+Q=u5-nAaG7p^|L6nZXypXHgC-fEXd=UGvQ_V$m?R}!Tv2^VhI9Q9(s(y?0u zZ__(A<17eMnFm5e1wVdu{RtWbU#RLG*l4KJ6S1F*g@e^VXAWh`?716W*JQ?S@8`GY zciE}&I_cMCl|+yJ*fVeIa)@ei;)Cuv-A7R^8^>(oSQQw2PH}s026`?Vqusf%I28Bi zinrkm34kKjgzV-nacm4t$7>&>EmKRc4R8wl8oc*uu)`{m4uBe$>Tu;gPv*LOGpS2E-|+eCYPXhRPEP}!Loro2l8 zt5+w%KtPTd{a=PwUVb7qFG7%643Dhv{HKeTlNYIF+tOjx@Sf!vji>aSpSx*U2Ug^D zg5pkL&rBk>!k?#&T22yzHKdKC>9Dz5vhz>0TIC`0ORY4sq~M&}wP5Au{XxHDdNwbk z{)<*qIPtCctW{O*UJushxkz%Qhlcc{Xj+Vm;`;jmiy~04_M%m;=~u8o~OG}H?N6zh_TPsvWYM4x$XqH#Vo$o z#n%$CQ)!@3!A#CO(d2d%aE=;?{n{_GU17HN>3^Q*iz(Cd{Qhc~G@y+i4_wlNuRgPs z)-@teq138jQ{BKRbXd4^nSloWMb{GkEk@W+ptee8AUdJ3>%8BXSrQTdYcE=6@5IvC zA7OgS#Bbv(%dH}-eAYZv){ZZ13UTZ|)FbTQ%U&Gy`F4Nq8!i4j1NzCFtIrU`%rzQ~kYJn67&uVWneTY9RNslYMhhGE0e3QnzFWijEqr zg<}{bkzFi}Th9Sd`7G9M1m<7uP_{sFJ9c9=X zIoZx(G*1ftyYp}V?tJU&(+9ob$x%Ds#J@$@{oG|lw2Zs(WLMYInx$S-!@b7imd^dv zzkkDq`W(SU7jwH$PazoU3}+Rp321SIbLr*G4_u1!3hdBIIq@Lp1n*jrv&zL2?^#^3 z+1_{_bF(sexhDETlakt)7NG*qlldZ?VIDFlo&G=sGmyrle<{ax5vBnb%5W7w5H=X; zey`%hyL*BV8t=JwSWP?H{!;PP4w|=6U#591-|eB)43TeZI!2VQuY*%@xxI=M=MPhi zD>5hxo^SrFOG0t^S-@JMOJg(J)BOqlNKQ? z`j?xp+W5|ts0$KZE?GItD~1Xipi2_YzRIwxY--zI!v5km`$^H{{P`Bu6U#aCJ9p*( zRcF%Yuq!Zgd<5s9`oA>s$UhJ7#|D09v@5D1!?lB+%+F{{y|xR}%nG&X+3T6sr%1FK z8^(ig^5G-$EIo=PW*L(0Rgh?6(Y6e^3er1NF<|j^_qS*ob|&^I*Mn7K*#EiEt)rR3 znm0-4r>6^|V8Ek0Il%ndEHM#whbGPt{|S6l^qR$(m@MC0EP;@Esv>^+nWB zn6Lj7*PFImq)nmU!O}P{;NfnvoUQ* zi_POZ-tvvS@`s-ZIeXM%ES%5bofPmGfi0MiU-gK-@<<%a+5Y|zXEcUyYun+|^*GU& zdLoRRB@Vruf$26`Ep2JuJ?Dp%z7Dho<6SCWkEeX5{!U!&f(m)KO>i8`s< z_#amj9*=kOFPVft(lIAh2VLIrJ+R{BQWmXR2TLFs+pKi~jW9Zlx~GmtK~U(@ZQovz zn4Q1o0wbpHN-Vih(MnVJ!k_T`ak+)ns=jG3jcs;9d-y*=Af z_s+7c^S5U4O{lrg$Osd^$R!kwvu;Pe<=Bf(@J2oUSzw;@t$^tu-n)<$k01K^jng?3g1ynwJe5go3uHc5rAt#;+E*F;+xX9x4>zT{j z+Hw;?hik9>3@9+H+6{8)!F>^@`DX9(W#^~J;GaUH3eOeH-%PU zyfaZW zj7rxJM6o~^)p{1RR>ur+>Dx9crRM+xZLJI2x(8*hP8IyQV>P~3U^x-WYxVs?x05mp z$%FgL!h8b0WtJA$Bh;iMz`bj(UzX>1`E|`5?@x88yropY{p;4uS?<% z?LW(h*TBbFxy&6ar6jA>tu3ol+kIv)rxdN6Bn+?hUIIJ#hO4W*UgMN6vzO@sfhm|G zpn6xUs@;*-CsUA`@RHVH<(5PhI&9+1FjYi(*Y-AFE2O?Kdi9&aclOs4^Aiux$eem| z>B_68Wa;?7{?NcK`P#8kZt|{SA?j|mu5D7sOm@s)j`1ioeD*941WmMOfj?XK{;NBX zo7RLYSSX)G`xcajeDU814Df*yvghDlBZrGq zo^8;zTtFXl`f>Hw06-4(&_w@Y8JrQf?pHZ$kV0`RqUmY zHUq5n9~?b;4+&Od0GjVqCi9^Wd~_ZT@~xw0`(J$mKRLc+EKu{m!y3uU-xNc zBo19cF4JVJ-(>;$PXwCe`tP*;cIYl+vC)S|ib`wmk;8m?DL6&{?{|`wdW8boO zJF}m)+O51EW(Eigs`23F&bhc^QBnb-eLna;RYD#zH0vJYOVw*!9(4|_R7*Fx_F;Ac z+k}(ib5nsSxz6DlF)B;xtI=5lm?EoZsf$ih$AT-pvwpYecuf;*TP|b_+v%k$nk)Rt z@5H%#i5LWUu|v3EaHgJ#B7P|0;3wy*Q?u*dCXfTd>0DMzi)3X9&V$;H&O1Y|PX1e@ zeJJ%y;0R6IDztQ+@QZq5ajK6THcOFScBqilX}hY1Q9V4fuIgiw_kHRlVa`3H^f&Pv z9(RS9@HZjh6m_FjSGG(kQKh&B=X-R%-``TAN zccUi$Ruvc`?M7+Yr;t~OtLOUqE{)9CwqEn@AL&L|&>ewFx;_JHVxhUchR@KCk?}IO z`HfbzLsJHTTkH<@&8S!@b=^3MG$ZFVg#rz$zBy`bkkx8Xd^ydlhpuJEHfp>8 z+;NB!^K_3*-W>=V{`6-t)qf*yij3^V{y(O^GAyd^3wJ0fDM@L;ADz;YA|>4o1Jd0g zF$^LhNGQ^hiW0)m4FjTdcXvo5T{Cmf@PF=o?w9!l=j^@WUGG|F@3l~$z(Hx9DAnEd zk%8fhyR`3+P!lBvUg6n!y9?RS4LDYav@R`yp;Y19ScwnXuBplhR*n*-d{;AffpaTOi>fFSc#9E3NB; ze7xh2u#oOs>2pje5pKuE{KhbqPEMMvK_$1~a$(utfUEG#i0R$t6lWr3OJbkvPK{6m z)ptH%7cye#UD&3>E;mi^FX}$X*8R7CS?c3=y8JEf$z3y~biyqPG1fd>Kl07m06LsY z$3XbyUwos#RG}LoM>n|Zn~eY5x5C{&#rjO8X4xecxz0`8pc!ZC00V5`=~ucyAPjs; zwIz14sA`&B+$^q>!t^pYf1+H~i+N*Z9Y%@qMFfLhNSk911M1Ozn64UpTEvnp1^IK<7L2&5Z932R-2KiTw=hF-{=6h}YYNuP%`E`Ti*C0;gKx6=p!HV6nA?WW zOg*=2+R1$5fS=k!$NXw~o-Md7y(Gyl5&@XID1?7yFU1>^>y$}zxWB|BPIZJ|s$8mq_;VAA(C7B6ury580Dr&7AUvmjd$wRFV=R-PCEI6?ILP-1B}VuZ_P4gW0T_MquO z&{sa$3q$ORP}Fql-H*yqFzpYCY{H|^-qOTil&oTXScpdX;jmz8qDNZZAWKu7lH^s0jguG#chm>C2J(ZQ^56>k3|44f0yKM+7i>GtXuzz>#UF%tm@68wZ$laha_ zuk7^n;6|xacIDQA@H$}c@d1*gSkEpJI>YHclrqNw&&5Km88!aNzp>X^{AGxtzFC?v zR&MBDO~(va7;8RYVXIAsru-8*2)*aGChq5&UjMRee}FbF5u+^agRQ9c`W5FX6jwb7 zx0R_z_V62-l>9N%;SW-pC9^r1la=53!#;^pt6o=?VU}mKFx{20w5Ox>7K7HCi`bZR zd5x5TEXu&Njki1dJgd-rKli2?E9V1u^rgf#4Q2BAjn=Lndzlsm74AuCn)iHT)Ag$z z4DCkMa_1-;?D94|V3l7BfK@U!KfW`&_?Kpbnxns2@9MqqYZd3pX|v1n|C8AAmUFsT9qkiD^Ox(cIS!qyDYhK7n6wjrb$? zR&(V6X$DFGRuuA^6b0)}k}2P8jvw>qHKIlG_B(+V*`m`SWmbdzs#rpXpp`djLnJ?} z`v^eA6kWPZlR)#2jen2I@C2lFosF(Tn+?Qr&|OyB9nf3PUZVk8?r1;qX*Yt?KS$JG z&+$bYfac@nms6lVvy=!<_?wmYe=1$6{1t^|rS_U+64O!^cGUqZ4mfV27&hPat38j( z2m`eTY}%V-J-Z}F8x!l=qz&;^d4EUYz!iVrKHTNtTFH6ZE>~z3=PHT!_HtW(>mM8PY#OCCL^s*dvL;r~tw|3-H0-a3_xO#udVd4DWfs`t)Qw41zv=U!1VOvE z4g(X|<$&EDQTTY9q}ieBJZ3kKm-&aDa)WBTtd`jrf7T8A|A)o&&DAgQw4i>S?ThaNy79+dM^-+##?ob&zttQRr(WuxMS0fG7C z0Y8>T)i-rSc?_8-Ud_o|6c;?Ow5Cnld49DAe&V(6(6IW@cMF92J zeCaA@!4I>2a0$f2fWSmQy1SMQ>OZSqcyJ5O=_^}uk_`LW5NMPDI@{TG@b~WA-hZCM z{z(?7LWt<;S8Q`~%*2AGx4>PM6l3PoTvIxgKlAXl5C?#&j~)V%iOFGgDU}_@*Jruu z?pHE7>!C}G%3sU|^GSGQ5AoI*cUVoIe|e+6!e;iL&Fb>dK!pK@j5}pnhW&g=nVH|4 z8U1kJ9`H)D&%86p9tmd#qLIumlGWwRRJYXKwC&CPlfgSN5sACo22PDZo{`^Plu*`F zEG)5_U%pItPULFGT27LTxs3+NN z;;N;~h9e9HH?+L1Kglu^+eFKzfk4abkWT6Qyr%poz$wHDJS~R!FAu7Gg)Xl}`Z)!! zpKQ#mr~CEUgVI5&tbo5bia)X_4MW-ktIddZ7o;QBEvcX5RVI%u<4|jsdU#v7XZ6X77QV+6^`cF`w zZ=}ATH1yf1&&TVgbWbj&p)@f-R}b-!_j%W$9maAh$}HwR71Awg%n<80#Puj3)XAsi zjwcg^!L)jk9xL&;+qe$f7-;q5QtA@Li@~{hS^Q@A2)OVcqKvkdh)ASpG|G;cjqv)q zajwo_d3)L%oXYm&pRx*l8d8!eDx$yd6N=-ya;2XNB*hK)_@kCva3dui@*#70`()hB z1cOw}MI_k}IIRX?*ZO@ln6Fx1ZbGHC_O5${$>2haa0=Uu)F(-gPhIM!WvhA!ud?Ow zuS0Vw#ztra&gpRW8b5;T^+d$+NP%$723W|U?O@MZ!;!3C=~&HxJt{iD)cjx5zK;DZ z;*@Th4jCGF_W1Z=BZ(2V_^fdy#+n*gdsn=czwk;0LwinI<>#ea;DR?)OCA801D-uI zft_UCh0hP5mdyy%BF&j}|7|#K)mFw6VuXm=^aq*vv;#z<-5;V1fD!!f?e=O2pXXi( z(_Q|WCh^{mFg;pOYP73{}bk z)SQS$T6e1B+qN${mUSRU-rBt{uUJ-@t`zK)2d^B}PzIXVG;iT$4;x%Dje}gJHUoei zw^0K@WMN2Nc|N5ORcX;z8%M9ZuhQ;@&&{LxfN>}u@vH@=iqjqok|`0!swq7ij`;|* zGXXJDqCH^mdErnjXg;L2v1Q~Pf8W94A3r&(0?qL4(c@>YNV zK#Ub~9T3R#$ILmv43wAsGjqSBu7KJ8%jV7=fF%GU+Zr0hP@Q_9D3WRxIi5(7Lea#s zQ>mP#%_n~8%2U=5WYgKa_DraB*gAI?9c+voh*=AX09+)}CUA_;R7!CweMg3Ck!4Rb zua3?TK+~tZz4B#bx!h0r|GGqC83GG{Dx*O^+cg!wks!XW!) zrAASd2Fhf)?&WfPxk2Cb)9=CcvjWS&c99%t<1heNr8V2L&10}3_jZ`-lXfzBX!P75 zGHo46F?sH`)4V#TS-ecF3<7{hiUs{28)M?@xmbP9wOpl%HXjNlBu1I8T4m_D>r%R0 z_P>72&dn(<2Rr&f_#%B6=zVRhnPpSKlOKR)yvI9e7s-z6EHt)9_NzhzYuRTBuoNDx zVHgqyO36y5AY|SJcZ&0bQ3tE0<`jaIf2zCE^C%Jd*l} z3)NGvVZmk00`BDDtOU>7Co7xpZm6xsgMqHnD_-dKsgmcFgDBtsKF=(LrRh4E+h5DV z3y(V-7Nm~u?DL_I)mC)XRbQqJ>N@VtYmR1uw(27Y?FLfFghUrYm~4PnF?U|~*7r=A zn4|Jt^6F^fuwKiy>oX8MtGO=MK431&jp$g0Xx<&5F2RfOiXd7{G=W4XK$=t+Wq2#z zcwSyJzzIBHbka#(KqEGF5Kvf)h?fO4-K_vi_5uQND+0*`Y zHWKmdr~6~Gdj(0L1yQ-Dtr|X`AUH|v5E;+d|mcT?SJ6aDysw}L_2vT$nxb^da;w#&iV&TOJ zPg~GAdQtDu_Gc#HzmNu6TWG*!{s9S=Y_NV`rNzVt%%Y@Rv3%JHFFp1M4+{z`8nk6G zn(XAt@(e8`G6QVC{Rdh@tcSZ8avne;;d=M(u148>GrSC3y@2{m=JHc75z!HhZQWcj{?^9aG#a^!D2##ebz( z$2^Fk1Hp3mb9*128iRbp5_u<(V>PO`xk_=xS=$03CZ&j$87>;#>Z{t8QxRgS*Q3Ql zMjZdx5-fVL2r;0zG@6q!dXj+ipTI-Ee)T>gGV!^{ZSB$< zxN4n@V72dJ7K*OKu(m6s1CH_EBRyS?X4hYyvo!rSyw_atFd7HG#EL8t(cz&m;N@~? zPhv&I^n`y4NNK5Ok+XRF9)LD;-P4I>#$%$r*E}iEK9<&a{(9~vgLT2I>+_8zvt6xy zK=`?D0k4wWDDv`TcH7R}XDVL)lF}V0s7Ih-LYCx8B4h@F-WHPBG>hErHEZ%kBZlI+ zT|zAC<~d|9-h|BZp^~}^fzN&swP!L!N8V^(VA~Cvs{O=Zv~_wq zu^S*Jh2_~>2l`F__m-lMAd4$eFj&33*QVbPYX;^p>;&}vT+u;`Q8LT5=JV@Y;v7XkP(JB6x^~%=`DLaY)1%UrjHy zg#`SBSPLb;uy7WUl^*S1p;(`MwCQaralF6yaHrlQ8UH%W|B+l8t{K5~*>^+di;X?$ z$&|91;yyb?%)H_?q5DOZYZlqUr^&eviGnn1~?-msvO)KBZ zlyF;JA)E0kS*bjuclx^I#HafMdL!t(Zehs&F>fw#wH(Zja5ny`(Hye)xsqzX_D=9<5QznlD@;KC?g4MsW*WpAGe0we%3CaY=f`Zl z2tdc$I!<2@0h=e2#@Oi_f>YS@dOrOQl`MePq|mjXfGWo$H+=7OmD_GrL+ql=6aQI) zmFbPJ71o6Y2U&~duH1-_`TE@xA?lU{Fk}BP+ldCN$2{om!7a%E@M@?sx?Eni7C0-o z(Lu7<7i!QSpXN%~zFQ1eTbZ9MZ2JjH3b6Y*cwz5d?X-iHv|prQ@>LEE)#$2Ub`&K@ zcjtzk-{=B4+~uO1z&~H1J|D{?FiKuo6^}_Li?bU9e0zQ8E;&D z?f#3W9NG^R)zn3be3|&%FIN4m>*uNLDia_?VzdgJs9${YW4X+Khf2vRc7tf2uPqD5 zzd$s@`)jGMBSf#s{poNYDuSfI|E+BQ(>5GcDHPbM zTI1_!V>jyM7Cro7$#u#Scf+-AXbbJQLc z;D!n*rqu>)0F)R9fI)EU^cH{g=MnlMiK`d+W~J~e1Bhf=|0>)fm;2lzfoI)e#viIc zE+?f`cZu4<&zSBE+smZCW53QUnf~UAPebc=RrQ+r`K=>hivU$XJ6P%Bei-d?)vOv= zV}k_j{JJ``*q~Nwk_{a9ccQBV8<}TlmtW0mW7u>@5G6GD&%DsMB&t}qWNjd+#a3D;B4r?=U9B$VE+Sz&zCa>G`X zBb=$3aH1Xbq&|R|VZV6zsB}S~&))%eA@&KNcSdw+F7c$k6&UNq)n1pgDJP`U^MuXu z$+X8r-MpC$Ng(9s1H)e-RhV)q%XOHh+5<*?9s%XOFcCW`gH4Y1%2hT_wBw*HQ7Val zrz=uva$n_nU}2kN+TL_*D3>6clF?g|W1hzR4Dc>cwN4SN`ym@0BKctCZJ1fCqh+tz z>40j-Y*8_ca)<*U5zuZlnnWlPiWqzqm-sv%T-YF!;$l{uuv<@uqlwur&5k+5fkw4FNhj$Y#dql_& z4wycF6>=Q~TprK>n*SYJm6uEoSQagZrNE|l$5q{fem3+aLPY2(@uZXwOO8`s>r+SQ z7O7$lw&nCr2Nzz0XXcaH$Qy%#-nf3>D|D1}-N#AmS_c8_MTP-T0*TFhMyYCYYv`X& zquA4F??tKTjIZ?eOTCe%yYpYb33)1MExVCzF}ej9WzZBm37jjh3;sO(Xe`MkY~vQATkM~b(HQW95AVHzEnBa zN$oxV@_bM~Kj(AxP=EI~!O^F=vXDTC#8)RXY!1v7GyTKGEDtysJE?T?4a}`=Dqq)3 zV>9z*vCKsOx-9pArE0RYf%SK1F*cdZqw%9_WWv%}-)>!B+Moedl?&j?dpWFIfCSo=@_0hMFDj^=F{+WJKmR z1gmBN+Uo{5q1a2(X z;DLhp-AvWjHdNI@Xc9`JC;)+Q=@MR4D?zVKMD$!QC@;VzGRWkT>sOFrHiryNC(22;uWygOL5y*% zxG_}|K~xwkS=DA8&)QP3n%&$gkB>e_z+uA0m$hyQ8}|GZ-(^3mO%fK%e9Cl!Sf;sQ ziv33gcrJ7p4Rup+kNKo#W@k2d)RP|2VZtussK{Y2-E!(y8Mc6zd23YGPb0oIsmtH@^STN0otLW|9*TIGtdhJ`-G zDxTR5 z%eUuCQ){ggLt#~vcAPHD)?c?$omgXWW7tW;ds!8}Vtp>7P}vM_mn4DC zUjp}VPNHYij{Gov-u6uTje4<1WPh>px_HFK(EeR|BknO5_*ZZ>1AY%=Ys1C1**V}r zYGfrD*LCu)8zJ8T>rVWrjQ9&F3Css9$YkW?y8N#&a`?8#{h4POru(&%kqODjZ}9x| zmt^|VUeDC|gEf#$u2F(=RPWtKXbSIYiI{RR*-0&F7cx?WKg*A!&p0)VP-X8B_3xOG zIry9Owaa`sECMyJ5=N=yc+>QD1uM@QeL68omY4`6-=myIg|ru|H~+1{b8Cw;F8!-Z z8lMg7LZV%!+6aS^ZR)*YAT+kj-i)fV)&hAO>HPDsBih@oWkE{6*7qtY=I0<^4D!Qj z_hk-qG7F;UV;fwixGm%N7q$ZpI;x+FRxaBz9#2Q0rNxAI|GolI3}31nzKO?vq$G)> zk`V0mXSS2{5c?!v{(Qx8KkSqwSh5vnk37GtzC&A0Q;}_TnT&cfI1bf7#2Y`l1bXss zS-)a(>S;611tv3KR6Rf50q5{G)=5n>N-Ji+D{_00^d2*QTElJMJob-B;jTETvM48A z7LWWVrtlH?6n^TZ_Zcp^*v7b2FWsf+7;wuGjP9e!}0P5vPizdIHm1 zKSMKe!;?a5=24K6R;Ah>5YNYki#|MHT4tPCwj<4D^@1|!K;rn4P(3%(~ zxtGj~2o!C*So4jY9{80AW{`H;16!8w#L|5@73pPUF61?Xz=h=ZGt|f4m<}x}tY)}s z5uQ!YFlWf2cM>uRzVl^QFqg}$iIDj(KTc`|N!e9`lv%DwbRHgdl4vFUhxK!F*k!)9 zGWqUyX{yfXfsxR?M~b0sESET|ul@r;F}5jgJmU&Mw7dPsG{*jFuyz4dQy+FBj}4*J zm-UmmKGA=XcOV(JyBYDWQN zR9+`&I!xenaxG}|7}H*M?g-ZQ`9PGrP?*fnv%-s{?1IJ%Me6Sfy;#Mc!@abw!G$is zwgu;x<3`TB`Ah$tX62w?nfsU)^e##3cTN*oKD6~+DSDnFl^KJ%Ip)!#Z%>c7KG zQl21|sZ2;!pIZ)&K41ouHoK^rIA8^S{SV{DK}g>H5sx~dm$1?V?Gxw3(ToM5q`S4=@%_^Q&&qDCpPf@&39L#%iwtMH8K-*Oh{ z6)u}EDxg7h=aWkYdOKj6`|Wi5bI8@U?(1In35GW6_CSch7VZ8dt4%PSfg$S>^+{Rv z#?+StU8r7aR)yQp@iO?F{bAfyz1!#SanBeF_UZFn8Q!(}qv{WIXhQKzN5dGro!)L; z=49MoRBEIf0W}0y;DWAioVvc5Fn#*bZ?71a>is?wR2=gyVZn!FbdAzHfMsom@&mXp zb+UHGRMH}Kz7BJK2=u+U&poQx>oe`O@8=WtF^_1Izt4Dt3q16$^xr|eLF2MfF7c~D z(J?`|6^mZdH^WXxaiy?-Y(i20yWi0!d~b(Q+QJrYlGz?ONoCw1^-mKSAhu`^28>0Y zt0lVzp@qcaB3??=wdRJ{&Wu62SVJq%-L83RZ78u&F?DBQkP+0%Ja*upa;-ZpuHkGDA_v#*KcJc z;%QFI1i!sqD#B+jV9Lhd&x4wjjY{%;Gj;PTx(zG6J4YB30M)ac7UpUcYZxe(?;{6`5?qP~ei8!+C#$ywPj~IQJeR z@dfL-bj>MI$tLzgM#(r6v{4!v{3+T~|PBvGYRkb2L`LKe{?B>n{Xs1r&5k-46V02uHA)r=65u&6x$AihK;C zL}d*=(37~jX8SXq@@L&CeA_2cakFBGo5GHbz0%l#($IS!7%K7)xNZHRo7LRXat+xT zEiNOYM4=q>b>kG71gHb=$r1Ek^92R!bhpJ79_K4&p%i6;0~=&>oWF|Teyi3~bUL2@ zRWMZ9zjOgrYn1ZUdBa6Ps?E}Urcvhb zhxh+#{~#gf6S#r&O%dTNQVgP0GH_N0om$^vbm<3-Nf^U-LypM3a-*YjFNr z#?9Y$d#s<6#(ne*qh&k24$cFNg%6=&GI&*Coqk?uW;Se}0QxiE1TgN{ZHTg<<0Vl*pP8#K7d5lKXO zgFG2T_fq7?N8P5Ap5QcAf%GjOo5fX$Cy$4Dt+WCfiK(f9~aqXVd2wSY&BZoyYp%e9+9RP@4J>gTfSF z6qm}_4y=o{{mq{0F{B9Dl5d9b(M>JXBY)wG+r~GGb8U z&;IaJb4yuZ4R29emeKQxF>?E*tk_Dk8E?jU4vhr7hING5U=AqmD}S7~1KApo(GsL8 zK2F&4eXcTI$^*5)CrHKwbW3`Ykq5woRm-Q4m*xg9afxgdenqR45{`x?vsJvJwikcU z#}vLJv~q4kp@oe1JKQ`b`cS4_rf}xqbM=~Gw`otw!@z>-SQ7H}S7kkELDxp90=xW- z74k1_l7V#z^Mc#wyiex_v--)(o*%Karv8IKq&wFYKP($o{igcQlHbSNo#nHNl`Vq; z%T%a9>h61T>-daTCyJ>84g&Qb{^bYGBw!jwi)q0H&z=f_jyQpfvC@JbnkFQoTPFnZ@W>G4}U+R^Q z>B!}9!dQ`~EqL|A_SH%Mc^)kZw%x9FCti!9;qP4wH5!bY)l}A}3HhG-G(U~1Wc}Qx zurK90OZFm-)r`-|K~KM0NTOWs=VK7#lY`q5>=l336}KJK#@^RCNSAfZvgmo3k;BoX zuD7uf8Q(NxnrKHq(Q(L*C)e#8Yp+V<*9PfHUb;KE$}X__q!A>=Oe%THj~azPNaxz$ zJ5IdFT54!2w&Mf2R`3`Q=mG6HM57^D=(UG=GiTdkmXTt^%zi6vXl0P>~c&kHF)8+1JSNM$O z3TWN^FEQ-yrP;%%0g&4x<3s}2q03Z84A=XvD@n3=M9^m3EYPE>&Nfc}U*`u#X*-zz zXm*YEyQ@5y^k5LS-jEw?ebDIo`7y5eywLZ(c_u)E{RA;7hA(~ z;;H{SgrDgUz7hUpBTd!VJrHvYhROdx_1h(Ea*>=PEvF2h?6&>feNQnpFO!&H#nuXE-rKEH9y)Oh zdOv@{JEbV~hT~TlK{8B7Lz2Ugy8VXUo>jhNMA-d+T^oB9X7-oALOPO22SQK|d+#ik zoiFOCUZFuKKHEJ%nyB;#{*#0*V08}b^A63cJyJ_zjy|HHAUs>#Wf`%dnWsGs{t+>ae*=73KGHeeGVwkY!{f_1%zHz&*j6fB}&?VV5g%fr6iBIW3@&Y*WPWs z#tKU`i?hvUlS**+-`qR$gMTFHeB)MkKXXx-^D+;nymQQD)(4`TFm`c^FZk^+XyT8| zz%ZzVUd-Mr)KTo!vJ!=22X;e41Kv3jnBRgWCq{{!!)1Q;Nt-H97Iq;xV)MazRQ5jO zCPrsEU_q8)b6iJuYgan1#xLI-f3OtXgz_X)_04kLg>bQWM7l!4fyxn;8X06yKxSm` z!H4& zWh9kZe#vI_Lj+zniYr&PKxfT=l_|U^7cHtWYbk8M@m)xjU-q4?uUC%yY;1hEBVaor9igLQ}?&8n%kGRDG8EStlqpotOi?; z6Mw2U3cOzPL*STGULo9&kZm=?mmPBz#pz%ks?{n{FN&csEW$15EXN%(o) zK!%7$#_qRhWZbipT;j*;RpGy|GPV0l;1PmNM?~glucGAh?NliJoMQIu;q@AQI{dBl zq$r58s-+0G*Db4ca=YAp#%q2b%BHr$IvE)@e)ZiM=YK z=`t5N5Tdo4`~=m+{6=miLT)V{N!Gy>2hzs^u{`SUpJsVVp5F2{?j~Q@s;xy~L-ksh zXSMFnq7e?pMF|u1O||+;1nW%Ln_2=Gl?ag+e)LcFIc89F`xO~!K=?P_ZB=bvqYhv3UFqK)%ZzI~J8Hh{ zp$aDx!Odr-D~91q^e9eka=Fp%v2A_YRi>q! zvd01$>c8AfY4c#OJY0Sw+W!7nxzC$#@8g5oT6`vmxJm<9t(WQ6A@3a~9%cmnn3=YHjK0V^^3uVy|GrC(Do9YjL4!%YmF+d31B4 z9jhCl?&y;Y6yoUQ3nc_`K0N|O_t)Z3%yW5;?0$`EoHW+{*XDug_@MoCd$`lD)uJB+ zjKBrRkTg9LlZ`li6eouBBVi@z7#`4x1&tSPfWq}5qbsILPwqEo`TnlRU2pO(oIa}h z%{nUciO9sDzvslz>&F!`)T=1kKYvKGW`!C|a5udZLiF0H?P4D8oi%d5Hw`_;6R*$rG=#MO4@=CkK!Vl}6392D zkGCc`w`@?E>Fet^F=u-Xa)SioQc}OaDkmNTeLZkkSvg)V=oJw*7`Fz+OcNg?@TT+s9AR&>b(EU^8=O?0}`Ia zybg-=u2v}IoH1Z~Es`eGTP@Cx+WyM7P{O@nxy9zQM%|hWJR}-*ik@&kQ zE%yngcS^yyEH!?2ORK9dIIu?kqC%b%YOwqmcM{-uZG`GQYish)AvqXZw#D41!vMUp z2CRqhlZVRuh`rPNL0(11$Il;ue+-P8i?TVB8KfC;jr?x=zi1qK45!6=vW(4z7yn*? zK9h8?Rutno3k@sfM>nfQ@>NbfV=5PL2piR~W7 ztB1d<9wYSFarI~!goT7WDmWaE>py;8s|Jrfd7W$# z+=7Z>3PwP#ND)Rtc}{XO2mY`!{z2`L>93A#?LYQ)?(<$aBidxudDwts@n-5v(R?RG z23fnsx^*1oSs>?JsNvfl(~UiuJ0*p!HPFEZ>E=F#zgKujxgDlZqerZB^*i3w_AN}i zHhdG%kr2kkcH@y{G8{3DfH`we*m4)ox zK3k}xC+T-_$1^4djj-tfjEI|vTBFy?R|2nAF2_{<3Tq1Fs0(C#__r9aY+Y*{^$3G< zVK_&+GsE0NhK`qP3Q`E4E zoSY8VA!u>h>5#%VphVR6(HVlkp~)k=YyKYS5w|o2G}TbtlJO8CqLop&S{k}#?Xym3 zWi*-8+R`{}+CLOkjQ^Q5$6ThFA*G+ z!M_5=P6rKRwVRVH`;hv=bJXL^fkzDFMYEteIyrD$0Zcg<`$PA7(v!U5#$~G{blSGz z22{Bv1x~bjl)EkAGvD^&j>R+;%y&9fBs4HdW>|rZ^$0Fk+NbVMvpg(+F}^t79SEjuE~z~*yjwq5LuGDF z;suhP7-3yz4&911+LJ8|h&o~;4aIK{EOERW11@gFqx%|T(c9R~FX&*k`;tG0Hy21}ID*U(3q`!USOQUL;w>4@T5*sRVvYP`d%%UgSnRtuH7c;lV1Ux}sv1T}4OgMM4pDg`{7@35NB+W~*8Z-Qx zo>Gs~DY{)2alL!%_yZw8Cim{r_F2cUEQ-GCWas>cR&JDih(>3dR!S_Ke?tTT{sXsX zy}N{?h#uqhZ$1LX-smQ@D%44lY+}oR-;D&vw52Jg zKh0x3$$a3WVJy=kV>Df3)Q0DD$r1Wj4mMNfRk5cI7b11P05!OSX6m>4JmO~A60QA{hdl% zSNt0g#d6i`-I{O}efx4MlE?(x1M=)P#8|1_O$2o$WeE|DuPAMp(gnF;7qQ%?fgv4m zfITwbiO|B{nh}8psjj{%L1mPfn&E7hbTYdKnOn;r2wWfHiGVU)u|pZ=(&R3K)W@^# zdBnGHv>W{gdbjYnTx?tDBY|#w)V4LU#VwB6g+#H3@d@LQwb650PgXOk56}=9#kLkG z_&q6K7fZr?k?1zZG^aXWcaTKgfKDc68_!;lH`(0M6qN$&nZayngVDc$vI}s+JU>>^ zNIGa*2((m`5VlwUVG;4OQ0&D_=8kraVtl}^594-yrPcRi#dN$C-DcFreTy58s99`K$(Yk8u(CJ zEZPi@cb7l<9yoSk@1B-m!O0T;QaRFo+&Y?tOHhFdYLr{qI&~5@bid=X4N9Ziv1tRWg|Tl zKSY~@u1#KwLK+U={>yVhS<N*#I~ z!gz?%XOm;yJ-(tYdH@DJyc}oF6r@fmOe#t_Ou@7WU8mC&f-eC?|7$fC+ zh_46=l>O6}l#nj5O!|-~nf5_kZ3ZJQK5~>O+H)ftIasMg-slxj4%}y)#yeFC6dS$z zZjyKM+(XP$p$#g^<@e`v?^y3K%P?C~YbZW&(CdNuQIwtHdBwFVg*-tRvI2d{Ypc$27` z%8;_b4owT9pZs@{jT;?nH)~7G#|=ioX9JXH2ynZ?S#C!9AxzY0c1qq0T)DaNiuo0u zsoSeM*H$f@hmWwspW>zXYPQ9Zd8=(qVUO5@m}!_B2n$#TUX%dvR-ZSL13EHUk4pI z!^Q0Z*?BDQy6m^8<6}?W5&n{2U}_Y#H2m*f+QG0(x6eq-|KaH^1ETz%_u+e&F6ok# zE|HS%RB4ftZjkO~7m#k0ZV*vAq*GFmlXF^ZWjvcl&DZGv~})b4{ExP6p^# znOT@Kh45NTYxGJB+8ES>!!j%Z%ph9ypd%f8BuPBvRUS7+mKPIB%HV6A-Rnx;J7Gs% z)y5g+-3?i36+;uZ69>8`8YuBE26@7?2l1TkyW3Nq4;~akB##|aKHp{td~JM50Hsc` zGQR1U!xm(J*zarT1y**OTrh}2Buaj{CQBUUUJG@Wmkm^iZtWg^&b#G<>MuRWU10{S z%$u<+w_mk53J;W`k#X|(g0kWVG%zM88T_X5; zo#{d$lG+g=srpJZ^eF))jWXtCdMfarL=FEZ5v4W;g2K4u(se2$-;bBw(RQJ6-8EE{ zD~OBl)?EG-X_dO0{JULbHiH?Gph)ix?=)2SAi5g;9kDW;ucmL9T|M3Tf^_yq)M|QW z0%$M|)wk7rieedWs1tIh(K3#W-c;vAqj#RvDN*+w*fn~lEcJarH(=9tg6X0Jx1C(( z)PCFQihb4ZfpAeoJHlMMEGO^sF|S;rT`_uiX>ZtuRSymY#gGhC$vkSqI^NI6ezk~f z?AF;tFFW}YK9W}5u?8=fhyPC|FMOnx)n}|g&{2{Gru~5Cu%AetX5FYB1;DSgR3mon zqUZI3AMvzG=L<_q$ZT8nb2KdNs~23R60h>sPJ}do$PZJ?9)C-Q{l=^*t+uB}618uy zv*T#7_e#YI0HPRdt^K&UIx4!Dz(1_$1F8kPL2Z$AM;{Uw>r`3z)zNG3X*#+enAed7 zQC`wR0n9jH4!kf8QUIUHH$BKohKy5K8j|^Jz@h*-EZU^**|Mj zL>*0<)2>Yp*j3jTo?1)1M&Jx3z}#ddPZ4!Ad9YoRyYn@FB^2Xuu>vT|kPq44Rei7Qq{Ri1e9s6>uTn!Id3h!fB z6xpMuc`6AZ+A*vvE^!*L2aH-DjHcA%o};!69BS7Rp`-&#C<<+_c8qKUrn=jC z$s#|TY37OVH6hUiaV9+|8o-%m{?6VI00(`rD# z`re)^rh|5794pdBxm-OjGRs|~(^L*CL|^c9gb0vcRn-V$>M@X`f864rBll;h9bGbX zP~=tH!sOk9vK*r%PuT2fjBf6~^cnW~^I1wKii?V}v6b0|K-AhdH%pE7+C`Xl{PrB! zZ(#NkDdmOK-*}Rxd~tprimR=24So2y>)ePNFnL9dIy8IPgwfHLse5?tQzy0p_B@o) zTIq>1cV?{Kx?5xGPm{0E=?6+*rsg5sdEu4RKwpnXh~MBhl&?^9nx8N68E`MlTgf8s z!5#F<42OWLb;{BIddUWXc}%mpEs>)QFyb~)`i#6Bs5wVyp5OT$wU~`pj=D0J*)OZ< zSC+N)x4sDLWXd-&&{9h>)0$+D8|o?bL^BoxB5mtdeNVSy{9|kY?4IptQSfw6c8PDV zuQ>CenUGZ_4 zaT(_*< z0WYst$Z%TpPVF~hn7OR~SexSF;_MmVwqx2aCbpMUH9DL#c7PNuNqt*MfhQz@Tc4#Y z)Ru(HK5(l?jtMR@ydF-#QjT5dsed(8ie>1t{e+8u`F6HOe~1%HaSFH0wy)1!Ueejp z|JZ;b$Ov?j+;pgqpF>(T>(S)hez@?PWxHFBq|EEEED;O6avd`DwIlrH=R4dDPRmC0 z9=0PKPz03$OxH*!l6BjybE6*RK?w7L4I9@Q+!6^3`gWta?&EnnQ2MKv6`*UUz| z{IoU|DaGA%^vxuue)2@u-(6dS)~#6csJqFpm;2`a>K+G5a$z70_=J!_T8H#ZDMF^E>#{Ug_~BH zbkv8B#p)E2t1YacQq%hF{=XGt%Q4CQ;DzYVw6Zt!>B8iZ8t$zzxt_zLc%cml`|tG> zZr@QvndKztq1J$)4BUysFGe01IqcnE(iUKDyNgD+C$MQNyy6SFG}j8cY2#onC5jlt?u#7SIaE3G|Nd(y;zZHa5^}qI-b^LtQ8LY zS83M=J!9%q-#m4-fId0aoh0%`ZAouS5hIQ0yCZ%BxiTeDE1faBgWDcMa_p3BrNCUobRy*<{ zjc_+W;iCLGH7{xVI`&0hL=n0un+26&+dwOs08%T<1-a><=2a#eHlOig=`7f^b<;PG z)6$*8%f5_3Z(?JS}Xq}$ldd)l-8!szLjo1#v--%9ZrpuCtsnXLblRxAn zsZ(DwZ6N-k!v_HLH%J{d?&K^7tanJa21mDfE1s9(F_@!CR|=siBToiH2mQ_lMPKas z_r9FR{X?010OiuUtY2NgmZhNf1c(akS#WU_z zCN)0S!xLIj^wP1+RL zPqkkzhWeFH?-%JD#L zSY|POL^JeGt9OH%sytf$(mkh!9_m>8Cfm2&I@(NIZTk@rXSHxcast(sj)C_ zc3%a$?3bNBD2{LBJ3H1TP1otbR5ZT_s8UT|a9d#%pAnq4>hQwdp=;<_oHziDsz=jK zs(U@vdwOHX5_=lY`S0F~ylWEGBcB!&ev3NxNm^q)W3wgkaXLpnYx04o!a>1}BuoKO zQ3j|a-bb{Ejk_hBVbDEpuGWw}QjGm*Q4=z8s||bWM(@Qmz>~3sb!QPJM}<>3wu-G7OfWYH4IK~-sa$4E8xX_xoqHF<7Z?=MxzU%xT~5~)^p{roy6kjU zWa4skGe$DZOfE81u;}lwPBUu|LZR!7$(BRpFnM&PuZrw@rRH1)^**+ z4P3iKX7pF2>@ln|4@28l-^A%5TU$>#w7)-}>)RDKD&1R;-oMl0!%a@jSpTE*ZNp0_ zxmK`Z4$Wtia7263Sa_;T{uZ_)@Nka}}UV*?Y0l5|`y!yJ3~H2`biZd(FT zRdWb7WAHO)@wO0sFE69b5g3P*mtd&DS~(xQIXFdWR-MzJ9mi?_FAsbSy;SuGY>}-Q zloRO7H&KgwV?Bl3zz*?J{}b%c@|9xo;98KE#Rc<>4S+eX-_VPAa+9;E+*1O z*2+~+*;wD3GBL0gZ>am|%Vl@CpvM@^#ehTkkERxqZvRExN9EZE z5%+g4#cq@#A-G%A5TdgR!`Am$&X^9vckRBH!|4z|m7n|4t^M{NAcEy0z5V?WF9H21 z$=J>999Uf~7TJe`e+2QjM4p_att$7V7Gh@E-!J4-x~$!?6)=_pcGeO1H&5E{y@T49 zRJjZ~p8`>GfyZ=J`ww<--*chNE2}EW00(*TN;s|Sox4^t>B@0!)~vv?+=`4qc>!og zix0dhoBYeO-mYQaknlTp}cdidFPj(L-RrF$?#u5A+n0gLDG${RiuThww5!t_fxdcb3N7V%$r z7IcJ?=Tv~v;Q$aRXC7~3i;@mEX@tKu=HAG@ZQ9-tmrJ(AdSxwI>Are}P#BcRB93wP~op~}dEP@JFvHQAEVo_ZOlc{@8 zu}>{5r^ekUfsAIOn08SI-O`b*IbV5(`TGGuq;|}|Bk#x$DuPdwPNo;pH1AI}Z@+)V zcS_)Ps&kNB1auUhHn?jV$1g(3Tsx}RPoKSY)j#FVJ0%it#@y+~7A^@@BYD2D*Jl6H zT3jR1r%t}p`t!ul2^QZr2CwUoP3#q^C#KrXUM*-Q zc+{x>4_uK~@uk#9LTdh%qO8yXWG5q|zL@sfxp6@YWfFBbD}8V48iT2jhS0QHt=>TA zk>C3LsWhI0^Fj^=qXn7cOBSv^1QPFdjP;{8p6qdmU;f4I+Y(N*<+q9r2z;;(!R<4< zy9fyCdcah;XZ&h;`xzhjjck*U{Aa$T^It2^7eil_Rtje&=iO^fXNl6TtKUbrJbQ*E zANUPZ);Zr1C*^Xc*Dw2J?;a2DD^^uZnOsihU>VYXQ~S$C*I~zf`8v6XrQ)qF^Us(^GU?mS}xnv8MphO*t*C%mZsV zIKs$Q?~IC?dhP6N0vwsJ^{ENNDI*;qU8Q?M3DUEUiuQ*OC{#m0?D0^B0RKz)y0Z-= z1vb-rs%X_YVm>e*Qug=iLN1#;Pq=F^@~U%q3s+u4iB!J2m~7o9a{L&(KsS_H4(1rW zu0emdEflNJVwtU6?&vA=qa{kt#A{RbzU5ymaNFW=wEc6|(orC~PH_g%fZKh6+ox6tAzsxnEB5J{Z}Vbu&<2ta{TV7a zE2LC$r5NFgy=S`e7LuC2G8nDeWpSHg>yfh^?fI23Rn@NK0JjM1EQ~PP3Pa_VSILr9 ze!cJ|bm_8qzaYfkS-^-@Y3qC0$;e22NsU>vQcj6t09MYYwU~UEz^&i*lHt4)ljBM; zZ;nLu(%xq8p?1!whD90F3NKS6Ys-Qtk2kX%K{b}^-+A%i745Xqii)GQyDKb zf~;hgG;1T$&`T&&%lPEC%r0-zh_8!+)9^3ZqkCO#ffnE8n*IBm^^n;YKSjr;_+Fi! z_<0OY&g^eD@1rz@DnhZ#w+WZGjZTswoj*|7JNrwqA0tPF)X@^>vTPlUpu`zMS{8LwwC`wCKvU4ifz6r99v?)Cu2v za#W=bP_XA}ZIsW6r;(<;?!pZFHf$#-Np245%V{YgOu|jT-U|y z;wtgx`?*tnZP%5icFwB+0}{R;Va3AFb`}Jt`4skQE0u_2Z~2hqbu6g#tdIKzd&i7F z?$`Am7}|i>webxP#k*A4yAD+P76hKXx2KK#y#R|1u{HWzT)TqGjRJ1P0hnc_rv5La z5ar1nby#}~K_3SMf2$C}*Z!+N9v@dJqZ#9i>wV_@ec<ov5TJMRBz@Ryq`lMfs`x;O@{%? z^?;}m|Hhem?lb(0+C}5^ua;8==!!g1ae77(c@IJEMH_bf*1#0H4kLeuWL?w+IUS(2lSn+q$+EHs$w9vT9x1ekv zRTch^{dvI~{Ct?dr9JJKbr&z1`FaG-Rk2)7D^ktGP#fuUlqdE3=k<>XpvNO4U%>|C zp`$=}5MG60o2+r~_u^uw@&uzm7p=z1xT}hKezdL3>zwrUC))D*oX5+sw)z?b;{Fzm zGHcM;I$4guSSakdPRgd8Zi>z^*+=TczXadKimli$=9@6L8r#LY8u^iP{GK0#-IgVK zYHCA0^-71xr}Ly5r*)&Ns_h1wUSa9!kD2*PRe%Yo%Ec$6%YThWIGPi}9F`Qshq$tp zk578CpKqmFa5v54zt4*seG0KqRfthelJq40avKgZx_jFHGP;lM3R!UxdByB2N+l;C zvp-966h;$JNq4ugf!wv~bT5v1;)9MbSiwfNf*v(EY%SL^{Xm7&&~mNsxi#~D$eaA2 zDKF`IuqrLLQsA|u$kcpz_YueIc_c-t3h zcyj3Yt+wH8V=dpL=R)ENjs_fMr{@U%DExV^dt4F4Qzq>@N1~&Yi0%EBcEoM=$(Y}W z_ZO!h8D>dw&eb}(j>%T*{D!RyJr52PB6|3Bde7FlxGrB=W08^UlHomKk@$aw4Osaj z97&gBEqdBtTchsn@2@(-Zs&bON{+yJ$e{n-`bX$+JL5Vb^r>%|h3D0HAU-MjuF=Rh%ZYcJ1>eDvem?*l#A?4_Z|m}6av=2g_ti%D0Sd)Mi__V){H z1_nmwHgq%YRMx|1%U`r01uQczV^8G=$XPZ;TJu{}_;qEjkAhClTaE_B8((6&W&gYs z(c#3zb`SCs=|()<&n(bjqRrdyWj#5%L>v>e{w1g|+FRfJ#QCHSx_4N+I)>~t3E6LH zr#SA@)_ugZ^8e}j6{b_t9_v+oUEL8lG`Kie)f^1$73=e30Y1Rs;?;%DhU7te| z)`^ctl|9^W6OMiuztB`tR6T3t9aYI+fr(q*38L3suZ~LU6YXYp+KI zLJ-HsfuDX7)L4XGf6y)D^wOfVb?1M#p#E(rx^@WCQ1>tEh`Th3Su5qGnjx{h3IEkI z9uI7;+tNg#-WtaDB2*u-LLRI`%U+pO4IIy*BW8be9JvJ{Zk%bH*<~l7`QHMVFcv{+ z8dM*1wZ9z29#5RI{5eezmo4=LjDhtOd_#`4erQ`@yWJ7rufC;|x+mUI-b! zEG_e1ax*JO(q`RQTFkxDcJ_x}T|@vZ1Xn?WGE3!neqM%h3=pJT^%Cr| zPNto1%bKjunT#9GZWrSA`>QZ-o@CTQmD2K%cHNzZ$Z%N{Xm88bWC)t}k{MU6@*N{O zDiJ2cUazNOA50p0TY6*mF)yspD!CG#!d}Y6&QQ8~WQw-0^UOgZyt&z0F2jsuvT9@G z8Hh)>;G`8$BB`r4PE0_EgcTx!y`yi+FEg+R&yi%WWL*iax=%9d2LtPRpCz-uc;rar z(5&>=Ac-Dcj?OL0P0Y%di;8IE(07O7^0pif9nI7Dw@8rByn|=!#@-U1g%X-KCIm`_ z)0%z^Ci-~$-uR2;PakYulLDxvZX^j}?uP-g_0C{I#x1=A>&G%OXJ1_P1$kztwdK_h z&{vp`iE0Bn5IpkI&X^vlobA8PjJ2GRv~AVA_V#v14KP1iNk$`rs>DRtJW5H+heI}S z_y?Lk1}MwqUbpBfRb~@(^f^?`-eb}9wG!5x#dIJDi#{>F=K}_Fs2VZj^I{}$tpxv# z9A8urQf58j&Mb|-$}tiCJ=mYmv-m7}-%Bhxqumk}HooO3mb7o!c+wQ`oX=|GFnt$0 zZ|nC^I6U72c0-M5;jooqA;IEsIqTy!-(uIZ3HkC1Pu6Z)hxRow)A+X6!;dJdTl^+X zK1pv_vFkQ5Xd4b;WB@Mie-!?s;&-fSb%v)GX2nWUBBatsZw_ngF;0H=;gCX#EbZRZ7NE>w z!M1v;aE}o>p7xv|#T=6@d^KbM6XB!jvuc|c4GnybtL9;?)zp+b3LP+dCsFcpjMM;co~f zE1c%0QwND}KH+~oWej2oHT4gUw@32#^}|OPajWFImdzq})`Xyr>zfH0&}y}L>l>?Y z=%n3pN7K)Da`n6TU7oNSw(ZPJg_q0Z9@0U-GzWt!T?S@20`n-i9SQzDYBk>FZLaQO zPR%vZwcYKuC1TeGa=6r5GkFbW#^nKeB$B8e;jm?Lh(HB~+Pk1-y(kf~XGL~xb@)eY zeDm}>Ew;no@vIk48LPp&ek*;4@!)I{utgD#{GSmSO2T(h=;>k z3x)M;m1upTt6yn--#Fy(rrE1{zIRD0npq_8WiZ$dVU(l(h#_9xz$5N|tcd?=Y$YX` z4#~W?!T}-?q%RCtnh)D#DyF-@DU7B)61Gq$ny=7Nz6MP`IPu@i+4DVa(HEgKvT7!z ztir$CDRc)UUJ|*S-n=2zd3u~fOmwL_S1%+v)5cyX7AV1^z{epRdGf@W~ccRn9G+q_wV}#*9NLhJN?VH+zWZp)g%y{@l)Hv4#45aB266`xI+-T za4T^Sx1SaXg&Ha!pyUc(@|2~@Yv!?(@Tr8v$( zeQq9L7rRgYvRJ~31(sWOHJx48G{hUHIVmN1bz#CTGbb{*dl|(O183@RX_8$X$NM!T z_Wo4+X}+49whNV=X)M zRi5fkRl=3O<3(Uc1VU_L-6`YsKGlX zsB`N0G|B29sM=66Zzz#ehcR0QP+&A z>M7%VB90-4r`E&s9KVf0(#u) zgUN3W10us|^oQpgTx&*hul$xt9_X_uaVzVj9g*i;$QkV&)}9( z)KU*#=4@I-!c~ZRON8XtS?BC=RqNmX(n@PojTBJD&$uliHV=Oy?d#}>&E>hE zObP|5fl2WHP910M4^;3})f&0s72sgy2~43l?IWdOc5HX20|OWbrv5F}vl(G<`-dPh zHgo9oif}EaDhlrlKV+KTe zclMQw0L{=A@6%p+j7ln6qg#+>Qc z=N3}r55n}+q_BSTb%iZaro~obTK<|P6`8Nq+T|B;XP2NncF(TSKLAT z8XwfUZ+MU0X<(|3o5h3WB0~@f{%pL$sJ+gX^jXI&*mrG74?)+vB%cgbvbm-9g801% z+V&hY!qxlLT0LX5TDwW7#YPDj}S=0l~Snl!< zP{~`)L83Es=1W6$3d^#fU0qxzNwWE3M+0{^d2=hq?kbVy>)DuTB9xP_gDNO$y=u`O zbLu)|1NNNo0W<*8M`E`=!Qt3;M*HYA9I>fHQ7X1V9d8Gn4&BkvLjvw5+GxOU4(^lO7|}i2h|+QC`i-Hk`D zKVQbaeR`qwrw!*>9&U$pl5VohU&^Q?`Q?Qon%H?kVgJBYCzRU#4BwYT_>9-bNW8IB|JX8Pj^&m%RO4nc6Qq3s?bj(;AJ+COUKJ_$5_?;1!{rq4^Y8> z8kd@jXiFkOJreXvm@(kX3_rhxtn&SIgk|SbbzeQqlC=5O#W2rPH&vl+`dU=I2Gxe| zK8>TZ=uW{TMto>w7OJ2yEZ}Xb-p%FKL&mRw=#34#lFRelqq% zn&@?q3R(X6K`!w%I%X@Yf>yW4PK>imWnQdQxLfU{k4lnW#6BG5OiI{()f1NwzveJw(G{x1^b(uZ+j&`g_a zqbiB%#!vzzgag|zu^+f(bV}n@FgbqUBQ)FE2mIL)S*dH>?&P>?V%xTJ9#E&o1uH>P z7Fwo2c)H2Ep^5ohVoh#IPgR9q8Z=SggQm9>$(zQpm&V9+Da~vS#4nNg0}*1$(FBBstE6XeL+iQeuH|0?4Lm~$@?_JhBv~FTvu6LZYq@V za;D4w&RZ55!NCBKM1@PPBG^%R6M#3*G#coZz-yoF>ht{&(51)3scoGGqyKb@erOHb zSr+SE$^Hqjx>ZZ+hFomZQ3!`{CAla+{A*Vfu5fLA*~&=zE{5fL!SI9JK^{kKs|S{^ zwV$_O4@Zo1rnyeJi=Ssj7~(2R;VQNbmpIzF{-B~I0hu=6w)^UTPiKM^{hV#eXs-`wGjo%3OkgP57Gg1Gj4-H{1Gd`C7S#JcCS`+Utcrqn~s%1jTcrA5j!5H&|E$2)MxZ` z`MZ`Auhrd>*#yQ9LvG<>Elwyej<~56QaPB;u{oyC#%up5NA*v?hO!M|Zu}-|{ncff zL~BqMztoJhd}!vk%}Fip6>hRDW1i#VUz$Rse+WaO%P%*E!o$ONNCa7LjVk&)Uo7>1 zF5XM8Qwr=q#>^2D>99h>FjT@EBrtB`I6AQo9Ju0QZm&PTtZ27%fiH!|wBft#KlKfK zy6NZ#qw2Z+wP`=9pr!fkJ5{-^kHf50Ux`eHxWCq6=(-A@jThukzj$ zsp=~siGf zWY@$8@|c$j_lpRK5-OfQp^N#ER~#Bn!qyDmG3Z5>ygZ7C3=dyQG|&XxE8o3)3O*duWfL3Rk6FRQ zZK%ZCk~%wLDYT{;Sbc&g@4xdERWHl!zM{+*Ylli|yj&Jy#?cgc?q1#KzPUxbDPWWq z^AbAn@I8{U?-TgQmdtG{G&lek4Z}%4^i_12I_Ae`!|iyJTMZ_vSad%1T#u*dhP7EJ zm1(WS2;nlCrLR*63YH7%k_)}2Q!ojJEo13RGVVSUns!+2s65wGoiLK!#gwzGl*BIc z*{N`$e6C2@Lms<-E7l&SW_k-0)jZ5s$jTnlG68e$OZQR4fUN9UvX`JEr^eLlJ{!wm z1Z9OKw;|>5@!qRg@@%SMCobi9ZzN=byW8xHo|LbxSL7;VdN4O3H+SIQ0<6VMcf0npL;U>UwJ zD0dPL&e`aoD`5u=hj=Mp5(6%jL)tU#?c2g7&HK~QtAvz`EY%Eh)Zg9|swXj$*hC1v zu6#qtF-|ltCnOGusimg^?(%_%(gcop2#+{9G-QKzpXNDFIVyx8>p|Q z>*FvqtxjFvJjSP9q@vT|sC1NXs3+wcLW&4q@>c@faBIxLeVb~`P$Z=9v5A;v>-*i` zi7La*R6_8AiC-{M@v|YW;fQA=^gEf_kU>P*=nfP2+g7@Hed+mKo#u*^*LD?`GNKKn zE34-4YRXw#vF=~U;S+Kq*m(G@BB{U*^-=%`9=r1_X36zQ{OI<04D5xZC1hdaj1L!k zz=$DuEHy?neW{!-6juu9J||I(9*1<269zoDha_cWzO5A3bHOLXBsM|8f4QG*`}>{z z_;`Kb$u&o@h96plYn0(Qvl0}(B=sl>;iCp`exwF* zpiTc!bKXi>_G}1*Sl>rL&#$oeeIBqf{S)zKo{ahFs`Z5@rK+}Ic6X}Eo6jLtQtfDF zUyj)57ZM9irmTE6@T)$1AHpXtQ?Xot0_1~!u<9Jeu-RtF!m#=;92w&sneL6#PQ4trg6_*0tw%t`uTr|q%tp|%V?X2G-w*!PuI&cT=jk{JcUuK zgwjI&@QYU7Hv!zwWWSsY_!jkfRv3CE zlmqbbTWuc?ri+6Y{E6c(=h_-8p{(&GB(9&Y?`H|Q2s|O#6 zA3iu|5VLTrT_MQ8?cA zz5brp4k{^-qyM|t+WPiAiICa{B`dIFaAH3^fwaRV$*f}96C7tv#&yP=?@2-kELLZG zJfow#@p+d8iFep>rP#Rr0N*qX>C(pHunfWRdUM+fB&qMn;r}R~R`Pu-P&P#jRO1+D zA#>Ay>R{Dm#^O;K^zI7juY`WwWgZ5R+tX85u=;u|BF>vI zo{kOGsvxrzEV#D?46@ZSK;D!Rh)^f9#%{Cc?mT0q7xvn3#WttM;*zO>q2*5N za0jlD%M}V5i^+G8cf^UJU8ZR(Uc!Afq~a}Tp4{j@WVmSPeti8ka~Je!ure!E*|Q5S z$SC*jAm4wM!~Y6TgAMnS+=n=9g($MVD8^*n){EJFFUw$h?<5&0h3<=?@SLTWC;FSd z*(HZB+(Yttz|tYfZ^|$Qtmv*$M&MwH+?cDCyH$(((4y8qyceKYmq4EB*~ZRYh@MIh@VW?zKnxHl+v|v_bxn^?A!b(jju_ zfw-KsqX}2i(3IGglCqccs$F9E_)1(Yo!}(ARDkn(pB&bD{&L(x)=lG4lK0b|thbmW zr#dL0uW^)}I#rCP!-Bk_*ce%dMrlTPCz>UExnQx+)o2ul5F9G1A!A%kzXq0IJ5=wC zrnBd%c~x8ox43e0M`{WUA_QgVEYFG zz(pg$9$-F2`5IM-B2BsImXHq-b|_Y>JDvwM&#pPGXvq^iNE62WECJ3(kGBa(P4ahkz$v*2c0~FvlA|iZ8`E@*x zo~586=dmeI%}-cR!C!(X2G^R5fy>=Q1XKFzpu{3uuZ+cu>w(x1CEJfrbu5IQeAN(z zU1MHe`bYbCu4DivM2#kNROzDLHLaZRaLz6YrM}0*R08nu$C65Ez7IDVa1gFo^Yknm zwsqGOU}XD=_tXTlemx~>{PA$vdUGk((+_J(iayDW4wJTJ_}a-4>nxbHI$MGy>hq$r zHBbIq?`ZKsKObh7Pa3uY_Lz1LD8YY!ZUNZdx;GHh@Gof^?kt!J%*1i-`6qHn()dx9x(H zeVLm22Lq>BZ2UzX&?TwPUSQzitB0koQz?qLy~PEGetqo$>lVkrq%us$OnRpPevjPBmg~@i+ahHND%*xw6xh;+K-0 zWKAUd#{1tV+fC2jvokACh-0i3Ugs#fuc88Kc0%iyzi%ZTKOQDuCP|FgC)NaW9mpss!DRIl9kR^r`rt02zZsm zo~4X;ect@H?|umkaJLSp5Y9IQ0K_s1d8-FmGyP{b2I`H7&eFWh^{arepAusfJR(aP zir{CS2+;nRVpaq;@?u*-i?Ak*SXI=NqOdBC}T@O7ECTjoDx@;N^8ymMbcDz zSG#FSB;16oj7b1bfV7AT_SZg)fiIFKeZ!uYhsMGY2~3-|CRjOR;pKMPqa)^$;8(13 ze)a-0`p}LHERcA2Cq2xsFxDS3WagB=9ZbQhpIo+Us_esz@(%LWr~4O|=Wla&DC3R& z5J9=#xME}*te#`jDyPpk}b%UVZJR*5tDLcS$ zWrf5i)Yppb|ChTs?A_Oo&^4}t<0t?v@fbJ;hclp`p2vTnt%3+)*oA4@tWde2ef4@nE# ztl;2%%$}EngZi0ezh(c89z5(+FyXTX<~FU4RApsJ9P||wHZUV1oDkt$Fx0~Ykn1K{`!Tc$sUw?qv=Q0=LM`}sLZ!}Et zNAQb~z6g!JK)RAToKwx%K{adCeY6fSxp`*LF;Go$NNDk2RowQ>RFnYTrtyrJx@-!Y zKESUgSUnLOj3X*U((Y5PzPtt+l2YgF%WM?Lsx7r+eniHTFb?FyBRaLfKMifMm!8-5BLRjCy_|*!xHU4I-o~ zW|gL7)UC~RSD(zHchH!#D7z@Y!a zKK$=?G8jg4J5z2`9CA}WnHQy^qx(l!@7Z{0$-3G9Z^t@x;Oe4H-B>s-fvM1reRm+W zuqfIg`A$(y1BNOdgukC_aAfqXCir*n?Jq2v*AUNN{25&wUDh+rT#daOz!=6>o=7O@ zy;vjH7$A7acR69<;U35T$_8WXkinN3asHIL>>>&=a}%iptIKo=!T;^b{kUT~prJOW zu<7lfUsxDsQH;+#_Z*F70FTkvn!w=oVv&5)%Suw>f()7A#a%ym8HkZ511rF9Io;f+mB zM!dvX);Q+`LU8VCC`%Y*(l6DCG6xx&*rvnerwX`74~f9QvqlVW0c?Vn7@4AZr-`y` z6#$Yp{>;xbw!Z7%tmtZ6jlS@!^`9=FvJ$)e)ycN`e9>6qfUNW4=VuF`njx2`;zfVU z-rs1=k+X6huUFEt!7cMUngwwcU@bw3!Gbihe5itev8R zr6T@`0l+t~Gte|Mn#LIx>RQH+<`LQI!j;GzhzS(~aeape_3P3>#UF<$iCT47;-}nlM z@s;?DOWLO*)6OyJA^Ibql9Og@GXr}a(yXm7{}7!DIn_I=k)W6}#K?QjiCchs&jv4wV!(H&iOd7`bHLE0cor^K7e6$B>8(2>Gl1|H zsQJqzkb%Y>r!Fz3lA)R6BLY#IXa!EBo7=#wn8oqb^k7bHG?+Ci))N8KMp=pu_^7?^ z92JhFZy{>$3UMAR6yOAgTyCnmK4zd_C|6;#Gp~geLd`GwIqDT`%xydBMxuA*6Oe)6 zhbN!{Wy}~RgQVe?tL;5#s6op;sC`LYk41=ZsG19z|GFH zak0-y3=99%-N#Z_Ii4(9zI|S^G-g+&Q<@%^hP;CgCPx%d!x%Ds?Q_ua@!c~QxRt2x zC|-Oss&$zJ2IOBDcFe*+0=>>M^inHLsvOBY$>siK^p+^jm>k2EC(g^VY7T9YfM|@s zWDv7)EZ6bM8=^)2qa7KS;Wtu>P4^Y^pI*y!7=czAlT z!Vi}veUFCF)O_~4db78l?93AY$?&+_;6_$RcsQr#cEqj<0@dB7dd!_bvI*&z_*Q%x z8Pn&8rEp}f>f4-_H}oCFr3=1vP3hGfr1m*TSs-7$9X9V|fW&{b;U>eL6Q%+4y3ZIk zQdZj8a4c)UZV=)(1qP=)G&2jKe_twL;2Fe37cj)CYkBU^2tP+`3&ZlGUNd$aA9Ftj zjvy=G!?j&73I*4~m=`|y>P=cTeGFhh1;=^&+0;w=jK4I+yqxeu8DERn`=t&7-9P3kzMHi!`f5Bkp$*$5|s4i%Y>(%aD97)gU^0CUyd@zpAd)qcjk-@}CY=hlY&Lr^M7+ik3JnyHvk>K!f z2kO6%1~q}dz*`fX3N#odZoZ{B^lYUz+I|hDVu$EIJ-pX;0P7k5A4yjk5cSi9?`Wiv z?vRoWY3ULW>F(|h0V(O0F6mafySokqBqc?}u2+7@NtsQ9evXIEb5&cV@x1V@mb!_l9BebD?sy;(qJ21Tr~eSqW0 zmbsd*JeAcwbbp@t*IfM^vWE_+_2xw09q`;S_xUVbRCqK82ly#8Vc!tyJ}UQWs}sTw zF97R5YHHmP(<4+71F&hU3H)@{kCh9%DixL1Nkuu9BnLL-{RKi1bb5mC3Y$*k|Gjz> z9}%%kn=&zZ!lS^^b4vC?XF3W@oCd%i``4j2&Gaa6BE7)BDXA8aF=7Rst{}6)%>C*h z7Uoh$(J{rg+nr=%HCUh-4LJ#2dahX>10G6)CUPnRT3~l2I^5ex5#+*A<1Zdpn5((Y z@P>U7_Edr;=C^)!pDum%&YNK~O5}aA!%2YxN9NGb>c!?)94w*njxz(5WDos6=O8n80S84RsW4uy|iMGUjsT5uW6k z>9((?(-K#njIr`*p8EJV^KsQb+Mc{3965Dh?5KeSjB%OqP1|Jjh`Iv^V!oaRcSD#2 zNjfTc7}`((4elo3a;~q@$OMCLZe(~FXRezpT-U!L1VSE>XBG=Sc-k-Jty9P^ zR7*7gHK~_C^PaBdhu>9WR&6ps@|DIj*|Gwx6Gz2sUchww_uF;{F#I~XVYz`3h&~~* zOOW`}FEvSpE2johYk6-+VWv3d0_Ml7*-tR?QgLY2!tw1D27vAivUWIDPUDZyJ9(7= z^4u|OlK%~gWQh1)69W2M3^Sr4Y=e}U((`cN(u04QZQeXdF8E>omt**uQfZ@g=-m(V z)zFVa(dvB7ej@Hbp6@wArL1QpleXEs`O4H@3{{DRWl4=fOL~J@+`#&EV z1zaWNJ{28b0y`v?XoIy=fOzk2;W0F<@5V&=YN!jMt*s4uoG6k~tayhsHy-SMPyi((l5C{N$8SI638{wmftbBwS!tf(q_U3v=EFRb?$t) zH()Bk+>2!2t!2g36pK(Q^&8(Hzw6p&zCL4Y>Q@~}@24WIn|VIw%Bq+j9aiP#js^lT z%K4es3&hV3ROOR1AK@6Rm%li!!hDPIx@or{`RU8eN3c8U9j|ivvdH@aQn^Gpu37fZ zcYQVf7;jqXJ3&Wxrf*~SOviUF$}yk@eTsISc86}ZV8EhW*2E(IBY?9N=J_yD)rIHk zVJ3kiXd?bWB!=Qh2>-Tsk$iND?V(!~)-s_* z#xXb=O=8Fu4@*@gd1@$L)t`JD;krjMA45nS3rZe ze}0DJ%IKy7M{HI!(X9l!`=!@!qy_rS;0KD>GyRk!e9!k-7iYtNxK0gx+f8RGep0vq zF-!f@k##@-j8adK9mq5IGis7IM9=UZIrUGZWq|kR`>sPs+uMEmICA-9k;Nb_CH2Q5Gs=G*I$kdhrMloe8pT;&6qU-{;VrYO zk+`CFw-`=6pFtCjDWJG{zW+R>)a$k?+=z>pneW_4bX{| zzD{=&mYHss^=(L`BdGFNJE4+WA~uIyL~^}8C?KSh(bX1`fs(o_zlGdAbTs700 zB+`!U&V?TCB|;r9ISwDOL3dnH*Khwk8bL48V7s!S4>LCqK!+WE3%_MbR+gc@LO(%& zj7Y-6x&hjnP=il^$N4RyH6idctO?~h8C9eeLhh&YR7RVbg)g??7 z>-93H8$*<{6OjqtXQFVC8>CKpR57V`bfjQ*m1Z~&@0{G`V}Zs90Lr?|gFa$`E`jn} ztFp`Kr*+`EU`m-w&Bh5wHBp#iDbGC9R2ap@OSn#4{^Tn$T|HEF%0A{NoN|-}REm(Z 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 KMNUMnLSTYce+gUw literal 0 HcmV?d00001 diff --git a/AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/AdminUi/apps/admin_ui/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000000000000000000000000000000000..f44089468f4e91e4070463f02e407280b81f058a GIT binary patch literal 553 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�mChkKZbu{PgSe3TEU$`f{B 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AdminUi/apps/admin_ui/macos/Runner/Configs/AppInfo.xcconfig b/AdminUi/apps/admin_ui/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000000..5f5912888b --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = admin_ui + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.adminUi + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved. diff --git a/AdminUi/apps/admin_ui/macos/Runner/Configs/Debug.xcconfig b/AdminUi/apps/admin_ui/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000000..36b0fd9464 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/AdminUi/apps/admin_ui/macos/Runner/Configs/Release.xcconfig b/AdminUi/apps/admin_ui/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000000..dff4f49561 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/AdminUi/apps/admin_ui/macos/Runner/Configs/Warnings.xcconfig b/AdminUi/apps/admin_ui/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000000..42bcbf4780 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/AdminUi/apps/admin_ui/macos/Runner/DebugProfile.entitlements b/AdminUi/apps/admin_ui/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000000..08c3ab17cc --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + com.apple.security.network.client + + + diff --git a/AdminUi/apps/admin_ui/macos/Runner/Info.plist b/AdminUi/apps/admin_ui/macos/Runner/Info.plist new file mode 100644 index 0000000000..a2d3f23498 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Admin UI + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/AdminUi/apps/admin_ui/macos/Runner/MainFlutterWindow.swift b/AdminUi/apps/admin_ui/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000000..3cc05eb234 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/AdminUi/apps/admin_ui/macos/Runner/Release.entitlements b/AdminUi/apps/admin_ui/macos/Runner/Release.entitlements new file mode 100644 index 0000000000..ee95ab7e58 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/Runner/Release.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + + diff --git a/AdminUi/apps/admin_ui/macos/RunnerTests/RunnerTests.swift b/AdminUi/apps/admin_ui/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000..5418c9f539 --- /dev/null +++ b/AdminUi/apps/admin_ui/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/AdminUi/apps/admin_ui/pubspec.lock b/AdminUi/apps/admin_ui/pubspec.lock new file mode 100644 index 0000000000..ed3edec0a0 --- /dev/null +++ b/AdminUi/apps/admin_ui/pubspec.lock @@ -0,0 +1,569 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + admin_api_sdk: + dependency: "direct main" + description: + path: "../../packages/admin_api_sdk" + relative: true + source: path + version: "1.0.0" + admin_api_types: + dependency: "direct main" + description: + path: "../../packages/admin_api_types" + relative: true + source: path + version: "1.0.0" + archive: + dependency: transitive + description: + name: archive + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + url: "https://pub.dev" + source: hosted + version: "3.4.10" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + dio: + dependency: transitive + description: + name: dio + sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8" + url: "https://pub.dev" + source: hosted + version: "5.4.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + url: "https://pub.dev" + source: hosted + version: "0.13.1" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7 + url: "https://pub.dev" + source: hosted + version: "7.6.7" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: "170c46e237d6eb0e6e9f0e8b3f56101e14fb64f787016e42edd74c39cf8b176a" + url: "https://pub.dev" + source: hosted + version: "13.2.0" + http: + dependency: transitive + description: + name: http + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + url: "https://pub.dev" + source: hosted + version: "4.1.7" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + meta: + dependency: transitive + description: + name: meta + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + url: "https://pub.dev" + source: hosted + version: "3.7.4" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + url: "https://pub.dev" + source: hosted + version: "2.3.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + very_good_analysis: + dependency: "direct dev" + description: + name: very_good_analysis + sha256: "9ae7f3a3bd5764fb021b335ca28a34f040cd0ab6eec00a1b213b445dae58a4b8" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" + web: + dependency: transitive + description: + name: web + sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + win32: + dependency: transitive + description: + name: win32 + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + url: "https://pub.dev" + source: hosted + version: "5.2.0" + window_size: + dependency: "direct main" + description: + path: "plugins/window_size" + ref: HEAD + resolved-ref: "6c66ad23ee79749f30a8eece542cf54eaf157ed8" + url: "https://github.com/google/flutter-desktop-embedding" + source: git + version: "0.1.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.19.0" diff --git a/AdminUi/apps/admin_ui/pubspec.yaml b/AdminUi/apps/admin_ui/pubspec.yaml new file mode 100644 index 0000000000..b288f4d9a4 --- /dev/null +++ b/AdminUi/apps/admin_ui/pubspec.yaml @@ -0,0 +1,44 @@ +name: admin_ui +description: "The Enmeshed Backbone Admin UI." +publish_to: "none" +version: 0.1.0 + +environment: + sdk: ">=3.3.0 <4.0.0" + +dependencies: + admin_api_sdk: ^1.0.0 + admin_api_types: ^1.0.0 + flutter: + sdk: flutter + flutter_svg: ^2.0.10+1 + get_it: ^7.6.7 + go_router: ^13.2.0 + shared_preferences: ^2.2.2 + window_size: + git: + url: https://github.com/google/flutter-desktop-embedding + path: plugins/window_size + +dev_dependencies: + flutter_launcher_icons: ^0.13.1 + flutter_test: + sdk: flutter + very_good_analysis: ^5.1.0 + +flutter: + uses-material-design: true + assets: + - assets/logo.svg + +# dart run flutter_launcher_icons +flutter_launcher_icons: + image_path: "assets/icon.png" + windows: + generate: true + icon_size: 256 + macos: + generate: true + image_path: "assets/mac-icon.png" + web: + generate: true diff --git a/AdminUi/apps/admin_ui/web/favicon.png b/AdminUi/apps/admin_ui/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..aad90e3bd3d11439b55705ccc99d85b2e93722af GIT binary patch literal 356 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 TC#HWus(_{%Otn_!X~h2kIAKU6 literal 0 HcmV?d00001 diff --git a/AdminUi/apps/admin_ui/web/icons/Icon-maskable-192.png b/AdminUi/apps/admin_ui/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..de3354d9323cc8da190f6c83f63cd47848652062 GIT binary patch literal 4502 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 TC#HWus(_{%Otn_!X~h2kIAKU6 literal 0 HcmV?d00001 diff --git a/AdminUi/apps/admin_ui/web/index.html b/AdminUi/apps/admin_ui/web/index.html new file mode 100644 index 0000000000..27d4c4ab28 --- /dev/null +++ b/AdminUi/apps/admin_ui/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + Admin UI + + + + + + + + + + diff --git a/AdminUi/apps/admin_ui/web/manifest.json b/AdminUi/apps/admin_ui/web/manifest.json new file mode 100644 index 0000000000..2c24b25c51 --- /dev/null +++ b/AdminUi/apps/admin_ui/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "Admin UI", + "short_name": "AUI", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/AdminUi/apps/admin_ui/windows/.gitignore b/AdminUi/apps/admin_ui/windows/.gitignore new file mode 100644 index 0000000000..d492d0d98c --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/AdminUi/apps/admin_ui/windows/CMakeLists.txt b/AdminUi/apps/admin_ui/windows/CMakeLists.txt new file mode 100644 index 0000000000..31aee013f2 --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(admin_ui LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "admin_ui") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/AdminUi/apps/admin_ui/windows/flutter/CMakeLists.txt b/AdminUi/apps/admin_ui/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000000..903f4899d6 --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/AdminUi/apps/admin_ui/windows/flutter/generated_plugin_registrant.cc b/AdminUi/apps/admin_ui/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..9372fc507c --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + WindowSizePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowSizePlugin")); +} diff --git a/AdminUi/apps/admin_ui/windows/flutter/generated_plugin_registrant.h b/AdminUi/apps/admin_ui/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..dc139d85a9 --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/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 RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/AdminUi/apps/admin_ui/windows/flutter/generated_plugins.cmake b/AdminUi/apps/admin_ui/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..ff2147b2cb --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + window_size +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows 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}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/AdminUi/apps/admin_ui/windows/runner/CMakeLists.txt b/AdminUi/apps/admin_ui/windows/runner/CMakeLists.txt new file mode 100644 index 0000000000..394917c053 --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/AdminUi/apps/admin_ui/windows/runner/Runner.rc b/AdminUi/apps/admin_ui/windows/runner/Runner.rc new file mode 100644 index 0000000000..27c2e09f4d --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "admin_ui" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "admin_ui" "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "admin_ui.exe" "\0" + VALUE "ProductName", "admin_ui" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/AdminUi/apps/admin_ui/windows/runner/flutter_window.cpp b/AdminUi/apps/admin_ui/windows/runner/flutter_window.cpp new file mode 100644 index 0000000000..955ee3038f --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/AdminUi/apps/admin_ui/windows/runner/flutter_window.h b/AdminUi/apps/admin_ui/windows/runner/flutter_window.h new file mode 100644 index 0000000000..6da0652f05 --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/AdminUi/apps/admin_ui/windows/runner/main.cpp b/AdminUi/apps/admin_ui/windows/runner/main.cpp new file mode 100644 index 0000000000..996158caba --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"Admin UI", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/AdminUi/apps/admin_ui/windows/runner/resource.h b/AdminUi/apps/admin_ui/windows/runner/resource.h new file mode 100644 index 0000000000..66a65d1e4a --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/AdminUi/apps/admin_ui/windows/runner/resources/app_icon.ico b/AdminUi/apps/admin_ui/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ff39970a73c8539c9c156a6d23cb4feefdefc5c0 GIT binary patch literal 9169 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 literal 0 HcmV?d00001 diff --git a/AdminUi/apps/admin_ui/windows/runner/runner.exe.manifest b/AdminUi/apps/admin_ui/windows/runner/runner.exe.manifest new file mode 100644 index 0000000000..a42ea7687c --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/AdminUi/apps/admin_ui/windows/runner/utils.cpp b/AdminUi/apps/admin_ui/windows/runner/utils.cpp new file mode 100644 index 0000000000..b2b08734db --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/AdminUi/apps/admin_ui/windows/runner/utils.h b/AdminUi/apps/admin_ui/windows/runner/utils.h new file mode 100644 index 0000000000..3879d54755 --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/AdminUi/apps/admin_ui/windows/runner/win32_window.cpp b/AdminUi/apps/admin_ui/windows/runner/win32_window.cpp new file mode 100644 index 0000000000..60608d0fe5 --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/AdminUi/apps/admin_ui/windows/runner/win32_window.h b/AdminUi/apps/admin_ui/windows/runner/win32_window.h new file mode 100644 index 0000000000..e901dde684 --- /dev/null +++ b/AdminUi/apps/admin_ui/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/AdminUi/config.local.json b/AdminUi/config.local.json new file mode 100644 index 0000000000..503a804465 --- /dev/null +++ b/AdminUi/config.local.json @@ -0,0 +1,3 @@ +{ + "base_url": "http://localhost:8082" +} diff --git a/AdminUi/melos.yaml b/AdminUi/melos.yaml new file mode 100644 index 0000000000..d29445c173 --- /dev/null +++ b/AdminUi/melos.yaml @@ -0,0 +1,28 @@ +name: enmeshed +repository: https://github.com/nmshd/backbone + +packages: + - "apps/*" + - "packages/**" + +ide: + intellij: + enabled: false + +scripts: + format: + run: melos exec -- "dart format . --set-exit-if-changed -l 150" + description: Run `dart format .` in all packages + + test: + # Only run the test command when the package has a test directory + run: melos exec --dir-exists=test --flutter -- "flutter test" && melos exec --dir-exists=test --no-flutter -- "dart test" + description: Run `flutter test` in all packages + + integration_test: + run: melos exec --dir-exists=integration_test --flutter -- "flutter test --dart-define-from-file=../../config.json integration_test/suite_test.dart" + description: Run `integration tests` in all packages that have the folder `integration_test`` + + outdated: + run: melos exec -c 1 --no-flutter -- "dart pub outdated" && melos exec -c 1 --flutter -- "flutter pub outdated" + description: Run `dart pub outdated` in all packages diff --git a/AdminUi/packages/admin_api_sdk/.gitignore b/AdminUi/packages/admin_api_sdk/.gitignore new file mode 100644 index 0000000000..a4ac5e717f --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/.gitignore @@ -0,0 +1,10 @@ +# 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 + +# schemes +schemes/*.json diff --git a/AdminUi/packages/admin_api_sdk/analysis_options.yaml b/AdminUi/packages/admin_api_sdk/analysis_options.yaml new file mode 100644 index 0000000000..f04c6cf0f3 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options.yaml diff --git a/AdminUi/packages/admin_api_sdk/example/admin_api_sdk_example.dart b/AdminUi/packages/admin_api_sdk/example/admin_api_sdk_example.dart new file mode 100644 index 0000000000..971a89231c --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/example/admin_api_sdk_example.dart @@ -0,0 +1,39 @@ +// ignore_for_file: avoid_print + +import 'dart:io'; + +import 'package:admin_api_sdk/admin_api_sdk.dart'; + +void main() async { + final baseUrl = Platform.environment['BASE_URL']!; + final apiKey = Platform.environment['API_KEY']!; + + await AdminApiClient.validateApiKey(baseUrl: baseUrl, apiKey: apiKey); + + final client = await AdminApiClient.create(baseUrl: baseUrl, apiKey: apiKey); + + final basicTierId = (await client.tiers.getTiers()).data.firstWhere((element) => element.name == 'Basic').id; + + final clients = await client.clients.getClients(); + print(clients.data.length); + + final newClient = await client.clients.createClient( + defaultTier: basicTierId, + ); + print(newClient.data.clientId); + + final clientInfo = await client.clients.getClient(newClient.data.clientId); + print(clientInfo.data.displayName); + + final updatedClient = await client.clients.updateClient( + newClient.data.clientId, + defaultTier: basicTierId, + maxIdentities: 100, + ); + print(updatedClient.data.maxIdentities); + + await client.clients.deleteClient(newClient.data.clientId); + + final identitiesPaged = await client.identities.getIdentities(pageSize: 2); + print(identitiesPaged.isPaged ? identitiesPaged.pagination : 'Not paged'); +} diff --git a/AdminUi/packages/admin_api_sdk/lib/admin_api_sdk.dart b/AdminUi/packages/admin_api_sdk/lib/admin_api_sdk.dart new file mode 100644 index 0000000000..27933967b2 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/admin_api_sdk.dart @@ -0,0 +1,2 @@ +export 'src/admin_api_sdk_base.dart'; +export 'src/types/types.dart'; diff --git a/AdminUi/packages/admin_api_sdk/lib/src/admin_api_sdk_base.dart b/AdminUi/packages/admin_api_sdk/lib/src/admin_api_sdk_base.dart new file mode 100644 index 0000000000..89d29487eb --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/admin_api_sdk_base.dart @@ -0,0 +1,60 @@ +import 'package:dio/dio.dart'; + +import 'endpoints/endpoints.dart'; + +class AdminApiClient { + late final Dio _dio; + + late final ClientsEndpoint clients; + late final TiersEndpoint tiers; + late final QuotasEndpoint quotas; + late final IdentitiesEndpoint identities; + late final RelationshipsEndpoint relationships; + + AdminApiClient._(String baseUrl, String apiKey) { + final dio = Dio( + BaseOptions( + baseUrl: baseUrl, + headers: {'X-API-KEY': apiKey}, + validateStatus: (_) => true, + ), + ); + _dio = dio; + + clients = ClientsEndpoint(dio); + tiers = TiersEndpoint(dio); + quotas = QuotasEndpoint(dio); + identities = IdentitiesEndpoint(dio); + relationships = RelationshipsEndpoint(dio); + } + + static Future create({required String baseUrl, required String apiKey}) async { + final client = AdminApiClient._(baseUrl, apiKey); + await client._setupXsrf(); + return client; + } + + Future _setupXsrf() async { + final xsrf = await _dio.get('/api/v1/xsrf'); + final xsrfToken = xsrf.data!; + final xsrfCookie = xsrf.headers.value('Set-Cookie'); + + _dio.options.headers['X-XSRF-TOKEN'] = xsrfToken; + _dio.options.headers['Cookie'] = xsrfCookie; + } + + static Future validateApiKey({required String baseUrl, required String apiKey}) async { + final isValidResponse = await Dio( + BaseOptions( + baseUrl: baseUrl, + validateStatus: (status) => status == 200, + ), + ).post>( + '/api/v1/validateApiKey', + data: {'apiKey': apiKey}, + ); + + final isValid = isValidResponse.data!['isValid'] as bool; + return isValid; + } +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/builders/builders.dart b/AdminUi/packages/admin_api_sdk/lib/src/builders/builders.dart new file mode 100644 index 0000000000..ab1852a91d --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/builders/builders.dart @@ -0,0 +1 @@ +export 'identity_overview_filter_builder.dart'; diff --git a/AdminUi/packages/admin_api_sdk/lib/src/builders/identity_overview_filter_builder.dart b/AdminUi/packages/admin_api_sdk/lib/src/builders/identity_overview_filter_builder.dart new file mode 100644 index 0000000000..231801fc6d --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/builders/identity_overview_filter_builder.dart @@ -0,0 +1,107 @@ +class IdentityOverviewFilterBuilder { + final IdentityOverviewFilter filter; + + String _filter = ''; + + IdentityOverviewFilterBuilder(this.filter); + + String build() { + if (filter.address != null) { + _appendFilter("contains(address, '${filter.address}')"); + } + + if (filter.tiers != null) { + final tiersFilter = filter.tiers!.map((tier) => "tier/Id eq '$tier'").join(' or '); + _appendFilter('($tiersFilter)'); + } + + if (filter.clients != null) { + final clientsFilter = filter.clients!.map((client) => "createdWithClient eq '$client'").join(' or '); + _appendFilter('($clientsFilter)'); + } + + if (filter.createdAt != null) { + _appendFilter('createdAt ${_getOperatorString(filter.createdAt!.operator)} ${filter.createdAt!.value.substring(0, 10)}'); + } + + if (filter.lastLoginAt != null) { + _appendFilter('lastLoginAt ${_getOperatorString(filter.lastLoginAt!.operator)} ${filter.lastLoginAt!.value.substring(0, 10)}'); + } + + if (filter.numberOfDevices != null) { + _appendFilter('numberOfDevices ${_getOperatorString(filter.numberOfDevices!.operator)} ${filter.numberOfDevices!.value}'); + } + + if (filter.datawalletVersion != null) { + _appendFilter('datawalletVersion ${_getOperatorString(filter.datawalletVersion!.operator)} ${filter.datawalletVersion!.value}'); + } + + if (filter.identityVersion != null) { + _appendFilter('identityVersion ${_getOperatorString(filter.identityVersion!.operator)} ${filter.identityVersion!.value}'); + } + + return _filter; + } + + void _appendFilter(String filter) { + if (_filter.isNotEmpty) { + _filter += ' and '; + } + _filter += '($filter)'; + } + + String _getOperatorString(FilterOperator operator) { + switch (operator) { + case FilterOperator.equal: + return 'eq'; + case FilterOperator.notEqual: + return 'ne'; + case FilterOperator.greaterThan: + return 'gt'; + case FilterOperator.greaterThanOrEqual: + return 'ge'; + case FilterOperator.lessThan: + return 'lt'; + case FilterOperator.lessThanOrEqual: + return 'le'; + } + } +} + +enum FilterOperator { + equal, + notEqual, + greaterThan, + greaterThanOrEqual, + lessThan, + lessThanOrEqual, +} + +class IdentityOverviewFilter { + final String? address; + final List? tiers; + final List? clients; + final FilterOperatorValue? createdAt; + final FilterOperatorValue? lastLoginAt; + final FilterOperatorValue? numberOfDevices; + final FilterOperatorValue? datawalletVersion; + final FilterOperatorValue? identityVersion; + + IdentityOverviewFilter({ + this.address, + this.tiers, + this.clients, + this.createdAt, + this.lastLoginAt, + this.numberOfDevices, + this.datawalletVersion, + this.identityVersion, + }); +} + +class FilterOperatorValue { + final FilterOperator operator; + final String value; + + FilterOperatorValue(this.operator, this.value); +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/endpoints/clients_endpoint.dart b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/clients_endpoint.dart new file mode 100644 index 0000000000..506eafe6ce --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/clients_endpoint.dart @@ -0,0 +1,76 @@ +import 'package:admin_api_types/admin_api_types.dart'; + +import '../types/types.dart'; +import 'endpoint.dart'; + +class ClientsEndpoint extends Endpoint { + ClientsEndpoint(super.dio); + + Future>> getClients() => get( + '/api/v1/Clients', + transformer: (e) => (e as List).map(Clients.fromJson).toList(), + ); + + Future> createClient({ + required String defaultTier, + String? clientId, + String? clientSecret, + String? displayName, + int? maxIdentities, + }) => + post( + '/api/v1/Clients', + data: { + 'defaultTier': defaultTier, + 'clientId': clientId, + 'clientSecret': clientSecret, + 'displayName': displayName, + 'maxIdentities': maxIdentities, + }, + transformer: Client.fromJson, + ); + + Future> getClient( + String clientId, + ) => + get( + '/api/v1/Clients/$clientId', + transformer: Client.fromJson, + ); + + Future> changeClientSecret( + String clientId, { + required String? newSecret, + }) => + patch( + '/api/v1/Clients/$clientId/ChangeSecret', + data: { + 'newSecret': newSecret, + }, + transformer: Client.fromJson, + ); + + Future> updateClient( + String clientId, { + required String defaultTier, + required int? maxIdentities, + }) => + put( + '/api/v1/Clients/$clientId', + data: { + 'defaultTier': defaultTier, + 'maxIdentities': maxIdentities, + }, + transformer: Client.fromJson, + ); + + Future> deleteClient( + String clientId, + ) => + delete( + '/api/v1/Clients/$clientId', + expectedStatus: 204, + transformer: (e) {}, + allowEmptyResponse: true, + ); +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/endpoints/endpoint.dart b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/endpoint.dart new file mode 100644 index 0000000000..d8fb17a9ad --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/endpoint.dart @@ -0,0 +1,138 @@ +import 'package:dio/dio.dart'; +import 'package:meta/meta.dart'; + +import '../types/types.dart'; + +abstract class Endpoint { + final Dio _dio; + + Endpoint(this._dio); + + @protected + Future getPlain(String path) async { + final response = await _dio.get(path); + if (response.data == null) { + throw Exception('Invalid response type'); + } + + return response.data!; + } + + @protected + Future> get(String path, {required T Function(dynamic) transformer, Map? query}) async { + final response = await _dio.get>( + path, + queryParameters: query, + options: Options(headers: {'Accept': 'application/json'}), + ); + return _makeResult(response, transformer); + } + + @protected + Future> post( + String path, { + required T Function(dynamic) transformer, + Object? data, + int? expectedStatus, + Map? params, + }) async { + final response = await _dio.post>(path, data: data, queryParameters: params); + return _makeResult(response, transformer, expectedStatus: expectedStatus); + } + + @protected + Future> put(String path, {required T Function(dynamic) transformer, Object? data}) async { + final response = await _dio.put>(path, data: data); + return _makeResult(response, transformer); + } + + @protected + Future> patch(String path, {required T Function(dynamic) transformer, Object? data}) async { + final response = await _dio.patch>(path, data: data); + return _makeResult(response, transformer); + } + + @protected + Future> delete( + String path, { + required T Function(dynamic) transformer, + required int expectedStatus, + bool allowEmptyResponse = false, + }) async { + final response = await _dio.delete>(path); + return _makeResult(response, transformer, expectedStatus: expectedStatus, allowEmptyResponse: allowEmptyResponse); + } + + ApiResponse _makeResult( + Response> httpResponse, + T Function(dynamic) transformer, { + int? expectedStatus, + bool allowEmptyResponse = false, + }) { + expectedStatus ??= switch (httpResponse.requestOptions.method.toUpperCase()) { 'POST' => 201, _ => 200 }; + + final payload = httpResponse.data; + + if (httpResponse.statusCode != expectedStatus) { + if (payload == null) { + throw Exception('Invalid response type'); + } + + final errorPayload = payload['error'] as Map; + return ApiResponse.fromError(ApiError.fromJson(errorPayload)); + } + + if (payload == null) { + if (allowEmptyResponse) { + return ApiResponse.success(transformer(null)); + } + + throw Exception('Invalid response type'); + } + + final pagination = payload['pagination'] != null ? Pagination.fromJson(Map.from(payload['pagination'] as Map)) : null; + return ApiResponse.success(transformer(payload['result']), pagination); + } + + @protected + Future> getOData( + String path, { + required T Function(dynamic) transformer, + required int pageNumber, + required int pageSize, + Map? query, + }) async { + final response = await _dio.get>( + path, + queryParameters: { + r'$top': '$pageSize', + r'$skip': '${pageNumber * pageSize}', + r'$count': 'true', + ...query ?? {}, + }, + options: Options(headers: {'Accept': 'application/json'}), + ); + return _makeODataResult(response, transformer, pageNumber: pageNumber, pageSize: pageSize); + } + + ApiResponse _makeODataResult( + Response> httpResponse, + T Function(dynamic) transformer, { + required int pageNumber, + required int pageSize, + }) { + final payload = httpResponse.data; + if (payload == null) throw Exception('Invalid response type'); + + final count = payload['@odata.count'] as int; + + final pagination = Pagination( + pageNumber: pageNumber, + pageSize: pageSize, + totalPages: count ~/ pageSize + (count % pageSize == 0 ? 0 : 1), + totalRecords: count, + ); + + return ApiResponse.success(transformer(payload['value']), pagination); + } +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/endpoints/endpoints.dart b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/endpoints.dart new file mode 100644 index 0000000000..88230f7d18 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/endpoints.dart @@ -0,0 +1,5 @@ +export 'clients_endpoint.dart'; +export 'identity_endpoint.dart'; +export 'quotas_endpoint.dart'; +export 'relationships_endpoint.dart'; +export 'tiers_endpoint.dart'; diff --git a/AdminUi/packages/admin_api_sdk/lib/src/endpoints/identity_endpoint.dart b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/identity_endpoint.dart new file mode 100644 index 0000000000..e20d6a86b5 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/identity_endpoint.dart @@ -0,0 +1,49 @@ +import 'package:admin_api_types/admin_api_types.dart'; + +import '../builders/builders.dart'; +import '../types/types.dart'; +import 'endpoint.dart'; + +class IdentitiesEndpoint extends Endpoint { + IdentitiesEndpoint(super._dio); + + Future> getIdentity( + String address, + ) => + get( + '/api/v1/Identities/$address', + transformer: Identity.fromJson, + ); + + Future> updateIdentity( + String address, { + required String tierId, + }) => + put( + '/api/v1/Identities/$address', + data: { + 'tierId': tierId, + }, + transformer: (e) {}, + ); + + Future>> getIdentities({ + IdentityOverviewFilter? filter, + int pageNumber = 0, + int pageSize = 10, + }) { + final queryParameters = {r'$expand': 'Tier'}; + + if (filter != null) { + queryParameters[r'$filter'] = IdentityOverviewFilterBuilder(filter).build(); + } + + return getOData( + '/odata/Identities', + query: queryParameters, + transformer: (e) => (e as List).map(IdentityOverview.fromJson).toList(), + pageNumber: pageNumber, + pageSize: pageSize, + ); + } +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/endpoints/quotas_endpoint.dart b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/quotas_endpoint.dart new file mode 100644 index 0000000000..a6baf1d429 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/quotas_endpoint.dart @@ -0,0 +1,67 @@ +import 'package:admin_api_types/admin_api_types.dart'; + +import '../types/types.dart'; +import 'endpoint.dart'; + +class QuotasEndpoint extends Endpoint { + QuotasEndpoint(super.dio); + + Future> createTierQuota({ + required String tierId, + required String metricKey, + required int max, + required String period, + }) => + post( + '/api/v1/Tiers/$tierId/Quotas', + data: { + 'metricKey': metricKey, + 'max': max, + 'period': period, + }, + transformer: Quota.fromJson, + ); + + Future> deleteTierQuota({ + required String tierId, + required String tierQuotaDefinitionId, + }) => + delete( + '/api/v1/Tiers/$tierId/Quotas/$tierQuotaDefinitionId', + expectedStatus: 204, + transformer: (e) {}, + allowEmptyResponse: true, + ); + + Future> createIdentityQuota({ + required String identityId, + required String metricKey, + required int max, + required String period, + }) => + post( + '/api/v1/Identities/$identityId/Quotas', + data: { + 'metricKey': metricKey, + 'max': max, + 'period': period, + }, + transformer: Quota.fromJson, + ); + + Future> deleteIdentityQuota({ + required String tierId, + required String individualQuotaId, + }) => + delete( + '/api/v1/Tiers/$tierId/Quotas/$individualQuotaId', + expectedStatus: 204, + transformer: (e) {}, + allowEmptyResponse: true, + ); + + Future>> getMetrics() => get( + '/api/v1/Metrics', + transformer: (e) => (e as List).map(Metric.fromJson).toList(), + ); +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/endpoints/relationships_endpoint.dart b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/relationships_endpoint.dart new file mode 100644 index 0000000000..660c9d14f7 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/relationships_endpoint.dart @@ -0,0 +1,26 @@ +import 'package:admin_api_types/admin_api_types.dart'; + +import '../types/types.dart'; +import 'endpoint.dart'; + +class RelationshipsEndpoint extends Endpoint { + RelationshipsEndpoint(super._dio); + + Future>> getRelationshipsByParticipantAddress( + String participant, { + int? pageNumber, + int? pageSize, + }) { + assert(pageNumber == null || pageNumber > 0, 'pageNumber must be greater than 0 when defined'); + + return get( + '/api/v1/Relationships', + query: { + 'participant': participant, + 'PageNumber': pageNumber, + 'PageSize': pageSize, + }, + transformer: (e) => (e as List).map(Relationship.fromJson).toList(), + ); + } +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/endpoints/tiers_endpoint.dart b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/tiers_endpoint.dart new file mode 100644 index 0000000000..328b92e1e6 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/endpoints/tiers_endpoint.dart @@ -0,0 +1,39 @@ +import 'package:admin_api_types/admin_api_types.dart'; + +import '../types/types.dart'; +import 'endpoint.dart'; + +class TiersEndpoint extends Endpoint { + TiersEndpoint(super.dio); + + Future>> getTiers() => get( + '/api/v1/Tiers', + transformer: (e) => (e as List).map(Tier.fromJson).toList(), + ); + + Future> createTier({ + required String name, + }) => + post( + '/api/v1/Tiers', + data: { + 'name': name, + }, + transformer: Tier.fromJson, + ); + + Future> getTier( + String tierId, + ) => + get( + '/api/v1/Tiers/$tierId', + transformer: TierOverview.fromJson, + ); + + Future> deleteTier(String tierId) => delete( + '/api/v1/Tiers/$tierId', + expectedStatus: 204, + transformer: (e) {}, + allowEmptyResponse: true, + ); +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/types/api_error.dart b/AdminUi/packages/admin_api_sdk/lib/src/types/api_error.dart new file mode 100644 index 0000000000..159ccf2358 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/types/api_error.dart @@ -0,0 +1,25 @@ +class ApiError { + final String id; + final String docs; + final String time; + final String code; + final String message; + + ApiError({ + required this.id, + required this.docs, + required this.time, + required this.code, + required this.message, + }); + + factory ApiError.fromJson(Map json) { + return ApiError( + id: json['id'] as String, + docs: json['docs'] as String, + time: json['time'] as String, + code: json['code'] as String, + message: json['message'] as String, + ); + } +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/types/api_response.dart b/AdminUi/packages/admin_api_sdk/lib/src/types/api_response.dart new file mode 100644 index 0000000000..09297cf425 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/types/api_response.dart @@ -0,0 +1,65 @@ +import 'api_error.dart'; + +class ApiResponse { + final T? _data; + final ApiError? _error; + final Pagination? _pagination; + + bool get isPaged => _pagination != null; + Pagination get pagination { + if (!isPaged) throw Exception('No pagination, check isPaged first'); + return _pagination!; + } + + T get data { + if (_data == null) { + throw Exception('${error.code}: ${error.message}'); + } + + return _data; + } + + ApiError get error { + if (_error == null) { + throw Exception('No error'); + } + + return _error; + } + + ApiResponse._(this._data, this._error, this._pagination); + + factory ApiResponse.success(T data, [Pagination? pagination]) => ApiResponse._(data, null, pagination); + factory ApiResponse.fromError(ApiError error) => ApiResponse._(null, error, null); + + bool get hasError => _error != null; + bool get hasData => _data != null; +} + +class Pagination { + final int pageNumber; + final int pageSize; + final int totalPages; + final int totalRecords; + + Pagination({ + required this.pageNumber, + required this.pageSize, + required this.totalPages, + required this.totalRecords, + }); + + factory Pagination.fromJson(Map json) { + return Pagination( + pageNumber: (json['pageNumber'] as num).toInt(), + pageSize: (json['pageSize'] as num).toInt(), + totalPages: (json['totalPages'] as num).toInt(), + totalRecords: (json['totalRecords'] as num).toInt(), + ); + } + + @override + String toString() { + return 'Pagination{pageNumber: $pageNumber, pageSize: $pageSize, totalPages: $totalPages, totalRecords: $totalRecords}'; + } +} diff --git a/AdminUi/packages/admin_api_sdk/lib/src/types/types.dart b/AdminUi/packages/admin_api_sdk/lib/src/types/types.dart new file mode 100644 index 0000000000..9c6b12707f --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/lib/src/types/types.dart @@ -0,0 +1,2 @@ +export 'api_error.dart'; +export 'api_response.dart'; diff --git a/AdminUi/packages/admin_api_sdk/pubspec.yaml b/AdminUi/packages/admin_api_sdk/pubspec.yaml new file mode 100644 index 0000000000..46cddf7489 --- /dev/null +++ b/AdminUi/packages/admin_api_sdk/pubspec.yaml @@ -0,0 +1,16 @@ +name: admin_api_sdk +version: 1.0.0 + +environment: + sdk: ^3.3.0 + +dependencies: + admin_api_types: ^1.0.0 + dio: ^5.4.0 + json_annotation: ^4.8.1 + meta: any + +dev_dependencies: + build_runner: ^2.4.7 + json_serializable: ^6.7.1 + very_good_analysis: ^5.1.0 diff --git a/AdminUi/packages/admin_api_types/.gitignore b/AdminUi/packages/admin_api_types/.gitignore new file mode 100644 index 0000000000..3cceda5578 --- /dev/null +++ b/AdminUi/packages/admin_api_types/.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/AdminUi/packages/admin_api_types/analysis_options.yaml b/AdminUi/packages/admin_api_types/analysis_options.yaml new file mode 100644 index 0000000000..f04c6cf0f3 --- /dev/null +++ b/AdminUi/packages/admin_api_types/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options.yaml diff --git a/AdminUi/packages/admin_api_types/lib/admin_api_types.dart b/AdminUi/packages/admin_api_types/lib/admin_api_types.dart new file mode 100644 index 0000000000..53f3b4a4ca --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/admin_api_types.dart @@ -0,0 +1 @@ +export 'src/admin_api_types_base.dart'; diff --git a/AdminUi/packages/admin_api_types/lib/src/admin_api_types_base.dart b/AdminUi/packages/admin_api_types/lib/src/admin_api_types_base.dart new file mode 100644 index 0000000000..8b4fcfb2af --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/admin_api_types_base.dart @@ -0,0 +1,5 @@ +export 'clients/clients.dart'; +export 'identities/identities.dart'; +export 'quotas/quotas.dart'; +export 'relationships/relationships.dart'; +export 'tiers/tiers.dart'; diff --git a/AdminUi/packages/admin_api_types/lib/src/clients/client.dart b/AdminUi/packages/admin_api_types/lib/src/clients/client.dart new file mode 100644 index 0000000000..0ceb014ba7 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/clients/client.dart @@ -0,0 +1,61 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'client.g.dart'; + +@JsonSerializable() +class Client { + final String clientId; + final String displayName; + final String defaultTier; + final String createdAt; + final int? maxIdentities; + final int? numberOfIdentities; + + Client({ + required this.clientId, + required this.displayName, + required this.defaultTier, + required this.createdAt, + required this.maxIdentities, + required this.numberOfIdentities, + }); + + factory Client.fromJson(dynamic json) => _$ClientFromJson(json as Map); + Map toJson() => _$ClientToJson(this); +} + +@JsonSerializable() +class Clients { + final String clientId; + final String displayName; + final ClientDefaultTier defaultTier; + final String createdAt; + final int? maxIdentities; + final int? numberOfIdentities; + + Clients({ + required this.clientId, + required this.displayName, + required this.defaultTier, + required this.createdAt, + required this.maxIdentities, + required this.numberOfIdentities, + }); + + factory Clients.fromJson(dynamic json) => _$ClientsFromJson(json as Map); + Map toJson() => _$ClientsToJson(this); +} + +@JsonSerializable() +class ClientDefaultTier { + final String id; + final String name; + + ClientDefaultTier({ + required this.id, + required this.name, + }); + + factory ClientDefaultTier.fromJson(Map json) => _$ClientDefaultTierFromJson(json); + Map toJson() => _$ClientDefaultTierToJson(this); +} diff --git a/AdminUi/packages/admin_api_types/lib/src/clients/client.g.dart b/AdminUi/packages/admin_api_types/lib/src/clients/client.g.dart new file mode 100644 index 0000000000..15af659371 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/clients/client.g.dart @@ -0,0 +1,53 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'client.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Client _$ClientFromJson(Map json) => Client( + clientId: json['clientId'] as String, + displayName: json['displayName'] as String, + defaultTier: json['defaultTier'] as String, + createdAt: json['createdAt'] as String, + maxIdentities: json['maxIdentities'] as int?, + numberOfIdentities: json['numberOfIdentities'] as int?, + ); + +Map _$ClientToJson(Client instance) => { + 'clientId': instance.clientId, + 'displayName': instance.displayName, + 'defaultTier': instance.defaultTier, + 'createdAt': instance.createdAt, + 'maxIdentities': instance.maxIdentities, + 'numberOfIdentities': instance.numberOfIdentities, + }; + +Clients _$ClientsFromJson(Map json) => Clients( + clientId: json['clientId'] as String, + displayName: json['displayName'] as String, + defaultTier: ClientDefaultTier.fromJson(json['defaultTier'] as Map), + createdAt: json['createdAt'] as String, + maxIdentities: json['maxIdentities'] as int?, + numberOfIdentities: json['numberOfIdentities'] as int?, + ); + +Map _$ClientsToJson(Clients instance) => { + 'clientId': instance.clientId, + 'displayName': instance.displayName, + 'defaultTier': instance.defaultTier, + 'createdAt': instance.createdAt, + 'maxIdentities': instance.maxIdentities, + 'numberOfIdentities': instance.numberOfIdentities, + }; + +ClientDefaultTier _$ClientDefaultTierFromJson(Map json) => ClientDefaultTier( + id: json['id'] as String, + name: json['name'] as String, + ); + +Map _$ClientDefaultTierToJson(ClientDefaultTier instance) => { + 'id': instance.id, + 'name': instance.name, + }; diff --git a/AdminUi/packages/admin_api_types/lib/src/clients/clients.dart b/AdminUi/packages/admin_api_types/lib/src/clients/clients.dart new file mode 100644 index 0000000000..93a3257592 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/clients/clients.dart @@ -0,0 +1 @@ +export 'client.dart'; diff --git a/AdminUi/packages/admin_api_types/lib/src/identities/identities.dart b/AdminUi/packages/admin_api_types/lib/src/identities/identities.dart new file mode 100644 index 0000000000..2fdf5e4ee9 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/identities/identities.dart @@ -0,0 +1 @@ +export 'identity.dart'; diff --git a/AdminUi/packages/admin_api_types/lib/src/identities/identity.dart b/AdminUi/packages/admin_api_types/lib/src/identities/identity.dart new file mode 100644 index 0000000000..51f404c4a8 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/identities/identity.dart @@ -0,0 +1,100 @@ +import 'package:admin_api_types/admin_api_types.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'identity.g.dart'; + +@JsonSerializable() +class Identity { + final String address; + final String clientId; + final String publicKey; + final String tierId; + final DateTime createdAt; + final int identityVersion; + final int numberOfDevices; + final List? devices; + final List? quotas; + + Identity({ + required this.address, + required this.clientId, + required this.publicKey, + required this.tierId, + required this.createdAt, + required this.identityVersion, + required this.numberOfDevices, + this.devices, + this.quotas, + }); + + factory Identity.fromJson(dynamic json) => _$IdentityFromJson(json as Map); + Map toJson() => _$IdentityToJson(this); +} + +@JsonSerializable() +class Device { + final String id; + final String username; + final DateTime createdAt; + final String createdByDevice; + final Map? lastLogin; + + Device({ + required this.id, + required this.username, + required this.createdAt, + required this.createdByDevice, + this.lastLogin, + }); + + factory Device.fromJson(dynamic json) => _$DeviceFromJson(json as Map); + Map toJson() => _$DeviceToJson(this); +} + +@JsonSerializable() +class IdentityQuota { + final String id; + final String source; + final Metric metric; + final int max; + final int usage; + final String period; + + IdentityQuota({ + required this.id, + required this.source, + required this.metric, + required this.max, + required this.usage, + required this.period, + }); + + factory IdentityQuota.fromJson(dynamic json) => _$IdentityQuotaFromJson(json as Map); + Map toJson() => _$IdentityQuotaToJson(this); +} + +@JsonSerializable() +class IdentityOverview { + final String address; + final DateTime createdAt; + final String createdWithClient; + final int identityVersion; + final int numberOfDevices; + final Tier tier; + final DateTime? lastLoginAt; + final int? datawalletVersion; + + IdentityOverview({ + required this.address, + required this.createdAt, + required this.createdWithClient, + required this.identityVersion, + required this.numberOfDevices, + required this.tier, + this.lastLoginAt, + this.datawalletVersion, + }); + + factory IdentityOverview.fromJson(dynamic json) => _$IdentityOverviewFromJson(json as Map); + Map toJson() => _$IdentityOverviewToJson(this); +} diff --git a/AdminUi/packages/admin_api_types/lib/src/identities/identity.g.dart b/AdminUi/packages/admin_api_types/lib/src/identities/identity.g.dart new file mode 100644 index 0000000000..4f3fa5c8ab --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/identities/identity.g.dart @@ -0,0 +1,87 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'identity.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Identity _$IdentityFromJson(Map json) => Identity( + address: json['address'] as String, + clientId: json['clientId'] as String, + publicKey: json['publicKey'] as String, + tierId: json['tierId'] as String, + createdAt: DateTime.parse(json['createdAt'] as String), + identityVersion: json['identityVersion'] as int, + numberOfDevices: json['numberOfDevices'] as int, + devices: (json['devices'] as List?)?.map(Device.fromJson).toList(), + quotas: (json['quotas'] as List?)?.map(IdentityQuota.fromJson).toList(), + ); + +Map _$IdentityToJson(Identity instance) => { + 'address': instance.address, + 'clientId': instance.clientId, + 'publicKey': instance.publicKey, + 'tierId': instance.tierId, + 'createdAt': instance.createdAt.toIso8601String(), + 'identityVersion': instance.identityVersion, + 'numberOfDevices': instance.numberOfDevices, + 'devices': instance.devices, + 'quotas': instance.quotas, + }; + +Device _$DeviceFromJson(Map json) => Device( + id: json['id'] as String, + username: json['username'] as String, + createdAt: DateTime.parse(json['createdAt'] as String), + createdByDevice: json['createdByDevice'] as String, + lastLogin: json['lastLogin'] as Map?, + ); + +Map _$DeviceToJson(Device instance) => { + 'id': instance.id, + 'username': instance.username, + 'createdAt': instance.createdAt.toIso8601String(), + 'createdByDevice': instance.createdByDevice, + 'lastLogin': instance.lastLogin, + }; + +IdentityQuota _$IdentityQuotaFromJson(Map json) => IdentityQuota( + id: json['id'] as String, + source: json['source'] as String, + metric: Metric.fromJson(json['metric']), + max: json['max'] as int, + usage: json['usage'] as int, + period: json['period'] as String, + ); + +Map _$IdentityQuotaToJson(IdentityQuota instance) => { + 'id': instance.id, + 'source': instance.source, + 'metric': instance.metric, + 'max': instance.max, + 'usage': instance.usage, + 'period': instance.period, + }; + +IdentityOverview _$IdentityOverviewFromJson(Map json) => IdentityOverview( + address: json['address'] as String, + createdAt: DateTime.parse(json['createdAt'] as String), + createdWithClient: json['createdWithClient'] as String, + identityVersion: json['identityVersion'] as int, + numberOfDevices: json['numberOfDevices'] as int, + tier: Tier.fromJson(json['tier']), + lastLoginAt: json['lastLoginAt'] == null ? null : DateTime.parse(json['lastLoginAt'] as String), + datawalletVersion: json['datawalletVersion'] as int?, + ); + +Map _$IdentityOverviewToJson(IdentityOverview instance) => { + 'address': instance.address, + 'createdAt': instance.createdAt.toIso8601String(), + 'createdWithClient': instance.createdWithClient, + 'identityVersion': instance.identityVersion, + 'numberOfDevices': instance.numberOfDevices, + 'tier': instance.tier, + 'lastLoginAt': instance.lastLoginAt?.toIso8601String(), + 'datawalletVersion': instance.datawalletVersion, + }; diff --git a/AdminUi/packages/admin_api_types/lib/src/quotas/quota.dart b/AdminUi/packages/admin_api_types/lib/src/quotas/quota.dart new file mode 100644 index 0000000000..15b5b91ce1 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/quotas/quota.dart @@ -0,0 +1,35 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'quota.g.dart'; + +@JsonSerializable() +class Quota { + final String id; + final Metric metric; + final int max; + final String period; + + Quota({ + required this.id, + required this.metric, + required this.max, + required this.period, + }); + + factory Quota.fromJson(dynamic json) => _$QuotaFromJson(json as Map); + Map toJson() => _$QuotaToJson(this); +} + +@JsonSerializable() +class Metric { + final String key; + final String displayName; + + Metric({ + required this.key, + required this.displayName, + }); + + factory Metric.fromJson(dynamic json) => _$MetricFromJson(json as Map); + Map toJson() => _$MetricToJson(this); +} diff --git a/AdminUi/packages/admin_api_types/lib/src/quotas/quota.g.dart b/AdminUi/packages/admin_api_types/lib/src/quotas/quota.g.dart new file mode 100644 index 0000000000..2e7cac6d92 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/quotas/quota.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'quota.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Quota _$QuotaFromJson(Map json) => Quota( + id: json['id'] as String, + metric: Metric.fromJson(json['metric']), + max: json['max'] as int, + period: json['period'] as String, + ); + +Map _$QuotaToJson(Quota instance) => { + 'id': instance.id, + 'metric': instance.metric, + 'max': instance.max, + 'period': instance.period, + }; + +Metric _$MetricFromJson(Map json) => Metric( + key: json['key'] as String, + displayName: json['displayName'] as String, + ); + +Map _$MetricToJson(Metric instance) => { + 'key': instance.key, + 'displayName': instance.displayName, + }; diff --git a/AdminUi/packages/admin_api_types/lib/src/quotas/quotas.dart b/AdminUi/packages/admin_api_types/lib/src/quotas/quotas.dart new file mode 100644 index 0000000000..5e50a72568 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/quotas/quotas.dart @@ -0,0 +1 @@ +export 'quota.dart'; diff --git a/AdminUi/packages/admin_api_types/lib/src/relationships/relationship.dart b/AdminUi/packages/admin_api_types/lib/src/relationships/relationship.dart new file mode 100644 index 0000000000..fa122a8675 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/relationships/relationship.dart @@ -0,0 +1,29 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'relationship.g.dart'; + +@JsonSerializable() +class Relationship { + final String peer; + final String requestedBy; + final String templateId; + final String status; + final DateTime creationDate; + final DateTime answeredAt; + final String createdByDevice; + final String answeredByDevice; + + Relationship({ + required this.peer, + required this.requestedBy, + required this.templateId, + required this.status, + required this.creationDate, + required this.answeredAt, + required this.createdByDevice, + required this.answeredByDevice, + }); + + factory Relationship.fromJson(dynamic json) => _$RelationshipFromJson(json as Map); + Map toJson() => _$RelationshipToJson(this); +} diff --git a/AdminUi/packages/admin_api_types/lib/src/relationships/relationship.g.dart b/AdminUi/packages/admin_api_types/lib/src/relationships/relationship.g.dart new file mode 100644 index 0000000000..bb618970d6 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/relationships/relationship.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'relationship.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Relationship _$RelationshipFromJson(Map json) => Relationship( + peer: json['peer'] as String, + requestedBy: json['requestedBy'] as String, + templateId: json['templateId'] as String, + status: json['status'] as String, + creationDate: DateTime.parse(json['creationDate'] as String), + answeredAt: DateTime.parse(json['answeredAt'] as String), + createdByDevice: json['createdByDevice'] as String, + answeredByDevice: json['answeredByDevice'] as String, + ); + +Map _$RelationshipToJson(Relationship instance) => { + 'peer': instance.peer, + 'requestedBy': instance.requestedBy, + 'templateId': instance.templateId, + 'status': instance.status, + 'creationDate': instance.creationDate.toIso8601String(), + 'answeredAt': instance.answeredAt.toIso8601String(), + 'createdByDevice': instance.createdByDevice, + 'answeredByDevice': instance.answeredByDevice, + }; diff --git a/AdminUi/packages/admin_api_types/lib/src/relationships/relationships.dart b/AdminUi/packages/admin_api_types/lib/src/relationships/relationships.dart new file mode 100644 index 0000000000..8b29f0c8b1 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/relationships/relationships.dart @@ -0,0 +1 @@ +export 'relationship.dart'; diff --git a/AdminUi/packages/admin_api_types/lib/src/tiers/tier.dart b/AdminUi/packages/admin_api_types/lib/src/tiers/tier.dart new file mode 100644 index 0000000000..0d4d9c1156 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/tiers/tier.dart @@ -0,0 +1,35 @@ +import 'package:json_annotation/json_annotation.dart'; + +import '../quotas/quota.dart'; + +part 'tier.g.dart'; + +@JsonSerializable() +class Tier { + final String id; + final String name; + + Tier({ + required this.id, + required this.name, + }); + + factory Tier.fromJson(dynamic json) => _$TierFromJson(json as Map); + Map toJson() => _$TierToJson(this); +} + +@JsonSerializable() +class TierOverview { + final String id; + final String name; + final List quotas; + + TierOverview({ + required this.id, + required this.name, + required this.quotas, + }); + + factory TierOverview.fromJson(dynamic json) => _$TierOverviewFromJson(json as Map); + Map toJson() => _$TierOverviewToJson(this); +} diff --git a/AdminUi/packages/admin_api_types/lib/src/tiers/tier.g.dart b/AdminUi/packages/admin_api_types/lib/src/tiers/tier.g.dart new file mode 100644 index 0000000000..5b2ca31c43 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/tiers/tier.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tier.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Tier _$TierFromJson(Map json) => Tier( + id: json['id'] as String, + name: json['name'] as String, + ); + +Map _$TierToJson(Tier instance) => { + 'id': instance.id, + 'name': instance.name, + }; + +TierOverview _$TierOverviewFromJson(Map json) => TierOverview( + id: json['id'] as String, + name: json['name'] as String, + quotas: (json['quotas'] as List).map(Quota.fromJson).toList(), + ); + +Map _$TierOverviewToJson(TierOverview instance) => { + 'id': instance.id, + 'name': instance.name, + 'quotas': instance.quotas, + }; diff --git a/AdminUi/packages/admin_api_types/lib/src/tiers/tiers.dart b/AdminUi/packages/admin_api_types/lib/src/tiers/tiers.dart new file mode 100644 index 0000000000..a793bc9c39 --- /dev/null +++ b/AdminUi/packages/admin_api_types/lib/src/tiers/tiers.dart @@ -0,0 +1 @@ +export 'tier.dart'; diff --git a/AdminUi/packages/admin_api_types/pubspec.yaml b/AdminUi/packages/admin_api_types/pubspec.yaml new file mode 100644 index 0000000000..6d50f5bebd --- /dev/null +++ b/AdminUi/packages/admin_api_types/pubspec.yaml @@ -0,0 +1,14 @@ +name: admin_api_types +description: The types used by the Admin API. +version: 1.0.0 + +environment: + sdk: ^3.3.0 + +dependencies: + json_annotation: ^4.8.1 + +dev_dependencies: + build_runner: ^2.4.7 + json_serializable: ^6.7.1 + very_good_analysis: ^5.1.0 diff --git a/AdminUi/pubspec.lock b/AdminUi/pubspec.lock new file mode 100644 index 0000000000..65616aa097 --- /dev/null +++ b/AdminUi/pubspec.lock @@ -0,0 +1,333 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + ansi_styles: + dependency: transitive + description: + name: ansi_styles + sha256: "9c656cc12b3c27b17dd982b2cc5c0cfdfbdabd7bc8f3ae5e8542d9867b47ce8a" + url: "https://pub.dev" + source: hosted + version: "0.3.2+1" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" + source: hosted + version: "1.3.1" + cli_launcher: + dependency: transitive + description: + name: cli_launcher + sha256: "5e7e0282b79e8642edd6510ee468ae2976d847a0a29b3916e85f5fa1bfe24005" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + conventional_commit: + dependency: transitive + description: + name: conventional_commit + sha256: dec15ad1118f029c618651a4359eb9135d8b88f761aa24e4016d061cd45948f2 + url: "https://pub.dev" + source: hosted + version: "0.6.0+1" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + http: + dependency: transitive + description: + name: http + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + melos: + dependency: "direct dev" + description: + name: melos + sha256: a2d3807c45ed7381a010c9feab8038f5eeb12163be900bba4a26f54d10e9da0b + url: "https://pub.dev" + source: hosted + version: "5.0.0" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + mustache_template: + dependency: transitive + description: + name: mustache_template + sha256: a46e26f91445bfb0b60519be280555b06792460b27b19e2b19ad5b9740df5d1c + url: "https://pub.dev" + source: hosted + version: "2.0.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + process: + dependency: transitive + description: + name: process + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + prompts: + dependency: transitive + description: + name: prompts + sha256: "3773b845e85a849f01e793c4fc18a45d52d7783b4cb6c0569fad19f9d0a774a1" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pub_updater: + dependency: transitive + description: + name: pub_updater + sha256: "54e8dc865349059ebe7f163d6acce7c89eb958b8047e6d6e80ce93b13d7c9e60" + url: "https://pub.dev" + source: hosted + version: "0.4.0" + pubspec: + dependency: transitive + description: + name: pubspec + sha256: f534a50a2b4d48dc3bc0ec147c8bd7c304280fff23b153f3f11803c4d49d927e + url: "https://pub.dev" + source: hosted + version: "2.3.0" + quiver: + dependency: transitive + description: + name: quiver + sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 + url: "https://pub.dev" + source: hosted + version: "3.2.1" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + uri: + dependency: transitive + description: + name: uri + sha256: "889eea21e953187c6099802b7b4cf5219ba8f3518f604a1033064d45b1b8268a" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + very_good_analysis: + dependency: "direct dev" + description: + name: very_good_analysis + sha256: "9ae7f3a3bd5764fb021b335ca28a34f040cd0ab6eec00a1b213b445dae58a4b8" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + web: + dependency: transitive + description: + name: web + sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + yaml_edit: + dependency: transitive + description: + name: yaml_edit + sha256: c566f4f804215d84a7a2c377667f546c6033d5b34b4f9e60dfb09d17c4e97826 + url: "https://pub.dev" + source: hosted + version: "2.2.0" +sdks: + dart: ">=3.3.0 <4.0.0" diff --git a/AdminUi/pubspec.yaml b/AdminUi/pubspec.yaml new file mode 100644 index 0000000000..9c40e8a44e --- /dev/null +++ b/AdminUi/pubspec.yaml @@ -0,0 +1,12 @@ +name: enmeshed +publish_to: none + +repository: https://github.com/nmshd/backbone +homepage: https://enmeshed.eu + +environment: + sdk: ^3.2.0 + +dev_dependencies: + melos: ^5.0.0 + very_good_analysis: ^5.1.0 diff --git a/docker-compose/docker-compose.services.yml b/docker-compose/docker-compose.services.yml index 3c86f2e3ff..7298f0cce4 100644 --- a/docker-compose/docker-compose.services.yml +++ b/docker-compose/docker-compose.services.yml @@ -7,9 +7,9 @@ services: - ASPNETCORE_ENVIRONMENT=Local - Modules__Files__Infrastructure__BlobStorage__ConnectionInfo="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;" - + ports: - - "8082:8080" + - "8081:8080" depends_on: # - ms-sql-server - rabbitmq @@ -24,6 +24,6 @@ services: container_name: admin-ui hostname: adminUi ports: - - "8080:8080" + - "8082:8080" volumes: - ./adminui.appsettings.override.json:/app/appsettings.override.json