From dbec1776e65f6d9015a981615abf7bf4c9578f71 Mon Sep 17 00:00:00 2001 From: Renee Vandervelde Date: Sun, 17 Aug 2025 10:57:18 -0500 Subject: [PATCH] Update Readme to direct users to open source repo. The GPL dependencies on this project will be removed before continuing to publish this repo as proprietary. Thanks to everyone for helping support the project during its initial development phase. Sources for the app will remain available in this repos history, as well as the previous releases. --- LICENSE | 339 -------------- README.md | 16 + android-application/build.gradle.kts | 144 ------ .../compose_compiler_config.conf | 2 - android-application/proguard-rules.pro | 27 -- .../ack/android/maps/MapsImplementation.kt | 5 - .../src/main/AndroidManifest.xml | 50 --- .../src/main/ic_launcher-playstore.png | Bin 13924 -> 0 bytes .../ack/android/AnalyticsEvents.kt | 12 - .../ack/android/AprsApplication.kt | 18 - .../ack/android/ExternalModule.kt | 32 -- .../ack/android/capture/CaptureActivity.kt | 206 --------- .../ack/android/capture/CaptureEvents.kt | 166 ------- .../android/capture/CaptureNavController.kt | 62 --- .../ack/android/capture/CaptureScreen.kt | 421 ------------------ .../capture/CaptureScreenStateFactory.kt | 51 --- .../ack/android/capture/CaptureViewModel.kt | 44 -- .../ack/android/capture/ControlPanelState.kt | 62 --- .../ack/android/capture/TransmitPrototype.kt | 21 - .../capture/insights/InsightsController.kt | 13 - .../capture/insights/InsightsScreen.kt | 198 -------- .../capture/insights/InsightsStatsState.kt | 32 -- .../capture/insights/InsightsViewModel.kt | 70 --- .../capture/insights/InsightsWeatherState.kt | 53 --- .../capture/insights/NearbyStationsState.kt | 11 - .../capture/insights/StatsStateFactory.kt | 26 -- .../capture/insights/WeatherStateFactory.kt | 47 -- .../android/capture/messages/MessageData.kt | 24 - .../android/capture/messages/MessageEvents.kt | 110 ----- .../conversation/ConversationActivity.kt | 62 --- .../conversation/ConversationController.kt | 18 - .../conversation/ConversationScreen.kt | 143 ------ .../conversation/ConversationViewModel.kt | 37 -- .../conversation/ConversationViewState.kt | 52 --- .../ConversationViewStateFactory.kt | 110 ----- .../messages/conversation/MessageItemState.kt | 34 -- .../create/CreateConversationActivity.kt | 27 -- .../create/CreateConversationController.kt | 11 - .../create/CreateConversationScreen.kt | 44 -- .../messages/index/ConversationItemState.kt | 23 - .../messages/index/MessageIndexScreen.kt | 103 ----- .../messages/index/MessageIndexState.kt | 27 -- .../index/MessageIndexStateFactory.kt | 41 -- .../messages/index/MessageIndexViewModel.kt | 26 -- .../index/MessagesScreenController.kt | 20 - .../service/BackgroundCaptureService.kt | 55 --- .../service/CaptureServiceNotifications.kt | 47 -- .../android/connection/ConnectionModule.kt | 16 - .../android/connection/ConnectionSettings.kt | 119 ----- .../ack/android/connection/DriverSelection.kt | 22 - .../android/firebase/FirebaseInitializer.kt | 32 -- .../ack/android/firebase/FirebaseModule.kt | 23 - .../ack/android/firebase/FirebaseSettings.kt | 27 -- .../input/ConvertibleOptionalIntValidator.kt | 25 -- .../ack/android/input/EnumValidator.kt | 18 - .../ack/android/input/IntPrompt.kt | 89 ---- .../ack/android/input/IntegerValidator.kt | 24 - .../ack/android/input/MaxLengthValidator.kt | 14 - .../ack/android/input/MinLengthValidator.kt | 14 - .../ack/android/input/NoValidation.kt | 8 - .../ack/android/input/RegexValidator.kt | 24 - .../ack/android/input/StringPrompt.kt | 84 ---- .../ack/android/input/ValidationResult.kt | 18 - .../ack/android/input/Validator.kt | 31 -- .../ack/android/locale/LocaleModule.kt | 16 - .../ack/android/locale/LocaleSettings.kt | 24 - .../ack/android/locale/Units.kt | 37 -- .../ack/android/log/AprsLogItem.kt | 54 --- .../log/CombinedLogItemViewStateFactory.kt | 50 --- .../ack/android/log/LogEvents.kt | 70 --- .../ack/android/log/LogItemViewState.kt | 13 - .../android/log/LogItemViewStateFactory.kt | 18 - .../ack/android/log/LogModule.kt | 19 - .../ack/android/log/LogSettings.kt | 23 - .../ack/android/log/SummaryFactory.kt | 33 -- .../ack/android/log/details/LogDetailData.kt | 23 - .../android/log/details/LogDetailsActivity.kt | 57 --- .../log/details/LogDetailsController.kt | 26 -- .../android/log/details/LogDetailsScreen.kt | 163 ------- .../android/log/details/LogDetailsState.kt | 36 -- .../log/details/LogDetailsViewModel.kt | 31 -- .../log/details/LogDetailsViewStateFactory.kt | 69 --- .../android/log/index/LogIndexController.kt | 13 - .../ack/android/log/index/LogIndexData.kt | 18 - .../ack/android/log/index/LogIndexScreen.kt | 89 ---- .../ack/android/log/index/LogIndexState.kt | 23 - .../android/log/index/LogIndexStateFactory.kt | 20 - .../android/log/index/LogIndexViewModel.kt | 24 - .../ack/android/map/MapDataRepository.kt | 59 --- .../ack/android/map/MapEvents.kt | 52 --- .../ack/android/map/MapModule.kt | 22 - .../ack/android/map/MapScreen.kt | 87 ---- .../ack/android/map/MapSettings.kt | 27 -- .../ack/android/map/MapViewState.kt | 17 - .../ack/android/map/MarkerMap.kt | 25 -- .../ack/android/map/MarkerViewStateFactory.kt | 33 -- .../ack/android/onboard/OnboardActivity.kt | 77 ---- .../ack/android/onboard/OnboardScreen.kt | 28 -- .../ack/android/onboard/OnboardSettings.kt | 32 -- .../ack/android/onboard/OnboardingModule.kt | 16 - .../ack/android/onboard/OnboardingState.kt | 30 -- .../android/onboard/OnboardingStateAccess.kt | 69 --- .../android/onboard/OnboardingStateFactory.kt | 37 -- .../android/onboard/OnboardingViewModel.kt | 22 - .../android/onboard/UsageAgreementPrompt.kt | 52 --- .../onboard/UserAgreementController.kt | 6 - .../settings/CompositeSettingsProvider.kt | 14 - .../ack/android/settings/LicenseData.kt | 11 - .../ack/android/settings/LicenseViewState.kt | 36 -- .../settings/NullSettingsReadAccesss.kt | 15 - .../ack/android/settings/Passcode.kt | 7 - .../android/settings/PrioritySettingValues.kt | 29 -- .../ack/android/settings/Setting.kt | 147 ------ .../ack/android/settings/SettingRows.kt | 129 ------ .../ack/android/settings/SettingState.kt | 20 - .../ack/android/settings/SettingVisibility.kt | 21 - .../ack/android/settings/SettingsAccess.kt | 90 ---- .../ack/android/settings/SettingsActivity.kt | 85 ---- .../android/settings/SettingsController.kt | 13 - .../ack/android/settings/SettingsGroup.kt | 3 - .../ack/android/settings/SettingsListData.kt | 9 - .../android/settings/SettingsListViewState.kt | 19 - .../ack/android/settings/SettingsModule.kt | 44 -- .../ack/android/settings/SettingsProvider.kt | 8 - .../android/settings/SettingsReadAccess.kt | 35 -- .../ack/android/settings/SettingsScreen.kt | 197 -------- .../ack/android/settings/SettingsViewModel.kt | 54 --- .../settings/SettingsViewStateFactory.kt | 31 -- .../android/settings/SettingsWriteAccess.kt | 17 - .../settings/SharedPreferenceSettings.kt | 74 --- .../android/settings/TransformableSetting.kt | 18 - .../settings/agreement/UsageAgreement.kt | 74 --- .../agreement/UsageAgreementReviewScreen.kt | 29 -- .../agreement/UserAgreementActivity.kt | 22 - .../android/settings/buildinfo/BuildData.kt | 36 -- .../settings/buildinfo/BuildDataAccess.kt | 28 -- .../android/settings/buildinfo/BuildInfo.kt | 59 --- .../settings/buildinfo/BuildInfoFactory.kt | 41 -- .../settings/buildinfo/BuildInfoState.kt | 56 --- .../settings/license/LicenseEditActivity.kt | 52 --- .../settings/license/LicenseEditState.kt | 18 - .../settings/license/LicenseEditViewModel.kt | 21 - .../android/settings/license/LicensePrompt.kt | 81 ---- .../license/LicensePromptFieldValues.kt | 9 - .../license/LicensePromptValidator.kt | 49 -- .../settings/transformer/EnumTransformer.kt | 11 - .../transformer/IntFieldTransformer.kt | 9 - .../settings/transformer/MileTransformer.kt | 14 - .../transformer/MillisecondTransformer.kt | 15 - .../settings/transformer/MinuteTransformer.kt | 12 - .../transformer/OptionalIntTransformer.kt | 11 - .../transformer/PercentageTransformer.kt | 14 - .../SentinelOptionalTransformer.kt | 17 - .../transformer/StationAddressTransformer.kt | 12 - .../settings/transformer/Transformer.kt | 49 -- .../transformer/TrimmingTransformer.kt | 14 - .../android/startup/ApplicationInitializer.kt | 29 -- .../CompositeApplicationInitializer.kt | 30 -- .../ack/android/startup/InitJob.kt | 24 - .../ack/android/startup/KimchiInitializer.kt | 29 -- .../ack/android/startup/NoOpInitializer.kt | 8 - .../ack/android/startup/StartupActivity.kt | 59 --- .../ack/android/startup/StartupModule.kt | 44 -- .../ack/android/startup/StartupScreen.kt | 54 --- .../ack/android/startup/StartupViewModel.kt | 26 -- .../ack/android/station/InsightViewState.kt | 16 - .../ack/android/station/StationActivity.kt | 58 --- .../ack/android/station/StationData.kt | 11 - .../ack/android/station/StationEvents.kt | 40 -- .../station/StationInsightViewStateFactory.kt | 37 -- .../ack/android/station/StationModule.kt | 16 - .../ack/android/station/StationScreen.kt | 142 ------ .../station/StationScreenController.kt | 27 -- .../ack/android/station/StationSettings.kt | 39 -- .../ack/android/station/StationViewModel.kt | 50 --- .../ack/android/station/StationViewState.kt | 13 - .../android/symbol/AndroidSymbolFactory.kt | 46 -- .../ack/android/symbol/SymbolFactory.kt | 12 - .../ack/android/symbol/SymbolModule.kt | 13 - .../ack/android/symbol/SymbolPrompt.kt | 76 ---- .../android/symbol/SymbolResourceLocator.kt | 67 --- .../ack/android/symbol/SymbolSelector.kt | 91 ---- .../android/symbol/SymbolSelectorViewModel.kt | 23 - .../ack/android/tnc/ConnectTncActivity.kt | 71 --- .../ack/android/tnc/ConnectTncScreen.kt | 155 ------- .../ack/android/tnc/ConnectTncState.kt | 26 -- .../ack/android/tnc/ConnectTncStateFactory.kt | 45 -- .../ack/android/tnc/ConnectTncViewModel.kt | 24 - .../ack/android/tnc/DeviceItem.kt | 58 --- .../ack/android/tnc/DeviceListController.kt | 16 - .../ack/android/transmit/PathTransformer.kt | 21 - .../PreferenceDriverSettingsProvider.kt | 47 -- .../ack/android/transmit/SymbolTransformer.kt | 15 - .../ack/android/transmit/TransmitModule.kt | 20 - .../ack/android/transmit/TransmitSettings.kt | 146 ------ .../inkapplications/ack/android/ui/AckChip.kt | 51 --- .../ack/android/ui/AprsSymbol.kt | 31 -- .../ack/android/ui/CallsignChip.kt | 55 --- .../ack/android/ui/EmptyBox.kt | 43 -- .../inkapplications/ack/android/ui/IconRow.kt | 32 -- .../ack/android/ui/KeyValueRow.kt | 19 - .../ack/android/ui/LabelledIconButton.kt | 61 --- .../ack/android/ui/NavigationRow.kt | 59 --- .../ack/android/ui/SelectionRow.kt | 50 --- .../ack/android/ui/StateLabelledIconButton.kt | 48 -- .../ack/android/ui/TelemetryTable.kt | 33 -- .../ack/android/ui/theme/AckScreen.kt | 18 - .../ack/android/ui/theme/AckTheme.kt | 131 ------ .../ack/android/ui/theme/AprsFonts.kt | 16 - .../ack/android/ui/theme/ColorPalette.kt | 22 - .../ack/android/ui/theme/ColorVariant.kt | 36 -- .../ack/android/ui/theme/ShapeVariant.kt | 12 - .../ack/android/ui/theme/SizingVariant.kt | 9 - .../ack/android/ui/theme/SpacingVariant.kt | 17 - .../ack/android/ui/theme/TypographyVariant.kt | 32 -- .../src/main/res/drawable-nodpi/symbol_0.png | Bin 902 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_1.png | Bin 667 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_10.png | Bin 390 -> 0 bytes .../main/res/drawable-nodpi/symbol_100.png | Bin 686 -> 0 bytes .../main/res/drawable-nodpi/symbol_101.png | Bin 619 -> 0 bytes .../main/res/drawable-nodpi/symbol_102.png | Bin 3851 -> 0 bytes .../main/res/drawable-nodpi/symbol_103.png | Bin 2378 -> 0 bytes .../main/res/drawable-nodpi/symbol_104.png | Bin 849 -> 0 bytes .../main/res/drawable-nodpi/symbol_105.png | Bin 1906 -> 0 bytes .../main/res/drawable-nodpi/symbol_106.png | Bin 388 -> 0 bytes .../main/res/drawable-nodpi/symbol_107.png | Bin 667 -> 0 bytes .../main/res/drawable-nodpi/symbol_108.png | Bin 1415 -> 0 bytes .../main/res/drawable-nodpi/symbol_109.png | Bin 1079 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_11.png | Bin 784 -> 0 bytes .../main/res/drawable-nodpi/symbol_110.png | Bin 2328 -> 0 bytes .../main/res/drawable-nodpi/symbol_111.png | Bin 1117 -> 0 bytes .../main/res/drawable-nodpi/symbol_112.png | Bin 670 -> 0 bytes .../main/res/drawable-nodpi/symbol_113.png | Bin 665 -> 0 bytes .../main/res/drawable-nodpi/symbol_114.png | Bin 664 -> 0 bytes .../main/res/drawable-nodpi/symbol_115.png | Bin 669 -> 0 bytes .../main/res/drawable-nodpi/symbol_116.png | Bin 682 -> 0 bytes .../main/res/drawable-nodpi/symbol_117.png | Bin 690 -> 0 bytes .../main/res/drawable-nodpi/symbol_118.png | Bin 673 -> 0 bytes .../main/res/drawable-nodpi/symbol_119.png | Bin 1100 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_12.png | Bin 725 -> 0 bytes .../main/res/drawable-nodpi/symbol_120.png | Bin 1252 -> 0 bytes .../main/res/drawable-nodpi/symbol_121.png | Bin 705 -> 0 bytes .../main/res/drawable-nodpi/symbol_122.png | Bin 727 -> 0 bytes .../main/res/drawable-nodpi/symbol_123.png | Bin 682 -> 0 bytes .../main/res/drawable-nodpi/symbol_124.png | Bin 691 -> 0 bytes .../main/res/drawable-nodpi/symbol_125.png | Bin 1186 -> 0 bytes .../main/res/drawable-nodpi/symbol_126.png | Bin 723 -> 0 bytes .../main/res/drawable-nodpi/symbol_127.png | Bin 2346 -> 0 bytes .../main/res/drawable-nodpi/symbol_128.png | Bin 421 -> 0 bytes .../main/res/drawable-nodpi/symbol_129.png | Bin 1340 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_13.png | Bin 695 -> 0 bytes .../main/res/drawable-nodpi/symbol_130.png | Bin 838 -> 0 bytes .../main/res/drawable-nodpi/symbol_131.png | Bin 1046 -> 0 bytes .../main/res/drawable-nodpi/symbol_132.png | Bin 2758 -> 0 bytes .../main/res/drawable-nodpi/symbol_133.png | Bin 1007 -> 0 bytes .../main/res/drawable-nodpi/symbol_134.png | Bin 1403 -> 0 bytes .../main/res/drawable-nodpi/symbol_135.png | Bin 3428 -> 0 bytes .../main/res/drawable-nodpi/symbol_136.png | Bin 1340 -> 0 bytes .../main/res/drawable-nodpi/symbol_137.png | Bin 869 -> 0 bytes .../main/res/drawable-nodpi/symbol_138.png | Bin 1047 -> 0 bytes .../main/res/drawable-nodpi/symbol_139.png | Bin 2177 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_14.png | Bin 1420 -> 0 bytes .../main/res/drawable-nodpi/symbol_140.png | Bin 861 -> 0 bytes .../main/res/drawable-nodpi/symbol_141.png | Bin 784 -> 0 bytes .../main/res/drawable-nodpi/symbol_142.png | Bin 2232 -> 0 bytes .../main/res/drawable-nodpi/symbol_143.png | Bin 816 -> 0 bytes .../main/res/drawable-nodpi/symbol_144.png | Bin 1464 -> 0 bytes .../main/res/drawable-nodpi/symbol_145.png | Bin 852 -> 0 bytes .../main/res/drawable-nodpi/symbol_146.png | Bin 1187 -> 0 bytes .../main/res/drawable-nodpi/symbol_147.png | Bin 2121 -> 0 bytes .../main/res/drawable-nodpi/symbol_148.png | Bin 3440 -> 0 bytes .../main/res/drawable-nodpi/symbol_149.png | Bin 862 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_15.png | Bin 816 -> 0 bytes .../main/res/drawable-nodpi/symbol_150.png | Bin 899 -> 0 bytes .../main/res/drawable-nodpi/symbol_151.png | Bin 4946 -> 0 bytes .../main/res/drawable-nodpi/symbol_152.png | Bin 699 -> 0 bytes .../main/res/drawable-nodpi/symbol_153.png | Bin 695 -> 0 bytes .../main/res/drawable-nodpi/symbol_154.png | Bin 3438 -> 0 bytes .../main/res/drawable-nodpi/symbol_155.png | Bin 667 -> 0 bytes .../main/res/drawable-nodpi/symbol_156.png | Bin 684 -> 0 bytes .../main/res/drawable-nodpi/symbol_157.png | Bin 3278 -> 0 bytes .../main/res/drawable-nodpi/symbol_158.png | Bin 1141 -> 0 bytes .../main/res/drawable-nodpi/symbol_159.png | Bin 5498 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_16.png | Bin 644 -> 0 bytes .../main/res/drawable-nodpi/symbol_160.png | Bin 907 -> 0 bytes .../main/res/drawable-nodpi/symbol_161.png | Bin 3786 -> 0 bytes .../main/res/drawable-nodpi/symbol_162.png | Bin 1212 -> 0 bytes .../main/res/drawable-nodpi/symbol_163.png | Bin 2235 -> 0 bytes .../main/res/drawable-nodpi/symbol_164.png | Bin 5630 -> 0 bytes .../main/res/drawable-nodpi/symbol_165.png | Bin 2573 -> 0 bytes .../main/res/drawable-nodpi/symbol_166.png | Bin 734 -> 0 bytes .../main/res/drawable-nodpi/symbol_167.png | Bin 1162 -> 0 bytes .../main/res/drawable-nodpi/symbol_168.png | Bin 349 -> 0 bytes .../main/res/drawable-nodpi/symbol_169.png | Bin 1341 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_17.png | Bin 795 -> 0 bytes .../main/res/drawable-nodpi/symbol_170.png | Bin 2561 -> 0 bytes .../main/res/drawable-nodpi/symbol_171.png | Bin 680 -> 0 bytes .../main/res/drawable-nodpi/symbol_172.png | Bin 773 -> 0 bytes .../main/res/drawable-nodpi/symbol_173.png | Bin 652 -> 0 bytes .../main/res/drawable-nodpi/symbol_174.png | Bin 2105 -> 0 bytes .../main/res/drawable-nodpi/symbol_175.png | Bin 3935 -> 0 bytes .../main/res/drawable-nodpi/symbol_176.png | Bin 703 -> 0 bytes .../main/res/drawable-nodpi/symbol_177.png | Bin 1431 -> 0 bytes .../main/res/drawable-nodpi/symbol_178.png | Bin 624 -> 0 bytes .../main/res/drawable-nodpi/symbol_179.png | Bin 3642 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_18.png | Bin 828 -> 0 bytes .../main/res/drawable-nodpi/symbol_180.png | Bin 1032 -> 0 bytes .../main/res/drawable-nodpi/symbol_181.png | Bin 1023 -> 0 bytes .../main/res/drawable-nodpi/symbol_182.png | Bin 934 -> 0 bytes .../main/res/drawable-nodpi/symbol_183.png | Bin 681 -> 0 bytes .../main/res/drawable-nodpi/symbol_184.png | Bin 2570 -> 0 bytes .../main/res/drawable-nodpi/symbol_185.png | Bin 603 -> 0 bytes .../main/res/drawable-nodpi/symbol_186.png | Bin 2667 -> 0 bytes .../main/res/drawable-nodpi/symbol_187.png | Bin 410 -> 0 bytes .../main/res/drawable-nodpi/symbol_188.png | Bin 703 -> 0 bytes .../main/res/drawable-nodpi/symbol_189.png | Bin 568 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_19.png | Bin 750 -> 0 bytes .../main/res/drawable-nodpi/symbol_190.png | Bin 704 -> 0 bytes .../main/res/drawable-nodpi/symbol_191.png | Bin 921 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_2.png | Bin 963 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_20.png | Bin 811 -> 0 bytes .../main/res/drawable-nodpi/symbol_207.png | Bin 1211 -> 0 bytes .../main/res/drawable-nodpi/symbol_208.png | Bin 838 -> 0 bytes .../main/res/drawable-nodpi/symbol_209.png | Bin 1321 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_21.png | Bin 836 -> 0 bytes .../main/res/drawable-nodpi/symbol_210.png | Bin 1385 -> 0 bytes .../main/res/drawable-nodpi/symbol_211.png | Bin 1108 -> 0 bytes .../main/res/drawable-nodpi/symbol_212.png | Bin 1301 -> 0 bytes .../main/res/drawable-nodpi/symbol_213.png | Bin 1394 -> 0 bytes .../main/res/drawable-nodpi/symbol_214.png | Bin 1099 -> 0 bytes .../main/res/drawable-nodpi/symbol_215.png | Bin 1387 -> 0 bytes .../main/res/drawable-nodpi/symbol_216.png | Bin 1387 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_22.png | Bin 758 -> 0 bytes .../main/res/drawable-nodpi/symbol_224.png | Bin 1366 -> 0 bytes .../main/res/drawable-nodpi/symbol_225.png | Bin 1114 -> 0 bytes .../main/res/drawable-nodpi/symbol_226.png | Bin 1455 -> 0 bytes .../main/res/drawable-nodpi/symbol_227.png | Bin 1166 -> 0 bytes .../main/res/drawable-nodpi/symbol_228.png | Bin 858 -> 0 bytes .../main/res/drawable-nodpi/symbol_229.png | Bin 896 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_23.png | Bin 833 -> 0 bytes .../main/res/drawable-nodpi/symbol_230.png | Bin 1502 -> 0 bytes .../main/res/drawable-nodpi/symbol_231.png | Bin 922 -> 0 bytes .../main/res/drawable-nodpi/symbol_232.png | Bin 622 -> 0 bytes .../main/res/drawable-nodpi/symbol_233.png | Bin 1012 -> 0 bytes .../main/res/drawable-nodpi/symbol_234.png | Bin 1277 -> 0 bytes .../main/res/drawable-nodpi/symbol_235.png | Bin 776 -> 0 bytes .../main/res/drawable-nodpi/symbol_236.png | Bin 1229 -> 0 bytes .../main/res/drawable-nodpi/symbol_237.png | Bin 1166 -> 0 bytes .../main/res/drawable-nodpi/symbol_238.png | Bin 1453 -> 0 bytes .../main/res/drawable-nodpi/symbol_239.png | Bin 1076 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_24.png | Bin 997 -> 0 bytes .../main/res/drawable-nodpi/symbol_240.png | Bin 1557 -> 0 bytes .../main/res/drawable-nodpi/symbol_241.png | Bin 1153 -> 0 bytes .../main/res/drawable-nodpi/symbol_242.png | Bin 1489 -> 0 bytes .../main/res/drawable-nodpi/symbol_243.png | Bin 829 -> 0 bytes .../main/res/drawable-nodpi/symbol_244.png | Bin 1029 -> 0 bytes .../main/res/drawable-nodpi/symbol_245.png | Bin 1319 -> 0 bytes .../main/res/drawable-nodpi/symbol_246.png | Bin 1667 -> 0 bytes .../main/res/drawable-nodpi/symbol_247.png | Bin 1482 -> 0 bytes .../main/res/drawable-nodpi/symbol_248.png | Bin 1203 -> 0 bytes .../main/res/drawable-nodpi/symbol_249.png | Bin 1169 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_25.png | Bin 1536 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_26.png | Bin 2170 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_27.png | Bin 2155 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_28.png | Bin 1326 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_29.png | Bin 1409 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_3.png | Bin 929 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_30.png | Bin 3388 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_31.png | Bin 1657 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_32.png | Bin 412 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_33.png | Bin 746 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_34.png | Bin 1224 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_35.png | Bin 656 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_36.png | Bin 4396 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_37.png | Bin 3325 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_38.png | Bin 448 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_39.png | Bin 592 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_4.png | Bin 890 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_40.png | Bin 1124 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_41.png | Bin 687 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_42.png | Bin 1180 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_43.png | Bin 1367 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_44.png | Bin 1000 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_45.png | Bin 825 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_46.png | Bin 1319 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_47.png | Bin 1189 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_48.png | Bin 1478 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_49.png | Bin 920 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_5.png | Bin 816 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_50.png | Bin 1090 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_51.png | Bin 2572 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_52.png | Bin 1216 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_53.png | Bin 1947 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_54.png | Bin 985 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_55.png | Bin 1264 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_56.png | Bin 1121 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_57.png | Bin 1533 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_58.png | Bin 786 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_59.png | Bin 825 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_6.png | Bin 2151 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_60.png | Bin 2865 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_61.png | Bin 3157 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_62.png | Bin 1042 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_63.png | Bin 922 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_64.png | Bin 855 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_65.png | Bin 3826 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_66.png | Bin 749 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_67.png | Bin 722 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_68.png | Bin 3567 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_69.png | Bin 1052 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_7.png | Bin 1918 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_70.png | Bin 2961 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_71.png | Bin 429 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_72.png | Bin 1442 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_73.png | Bin 1184 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_74.png | Bin 1351 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_75.png | Bin 1378 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_76.png | Bin 1480 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_77.png | Bin 1214 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_78.png | Bin 1023 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_79.png | Bin 3510 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_8.png | Bin 855 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_80.png | Bin 461 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_81.png | Bin 3278 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_82.png | Bin 969 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_83.png | Bin 635 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_84.png | Bin 803 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_85.png | Bin 1124 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_86.png | Bin 935 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_87.png | Bin 2491 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_88.png | Bin 1372 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_89.png | Bin 551 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_9.png | Bin 3828 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_90.png | Bin 705 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_91.png | Bin 375 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_92.png | Bin 648 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_93.png | Bin 602 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_94.png | Bin 680 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_95.png | Bin 907 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_96.png | Bin 797 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_97.png | Bin 673 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_98.png | Bin 639 -> 0 bytes .../src/main/res/drawable-nodpi/symbol_99.png | Bin 819 -> 0 bytes .../drawable-v31/ic_launcher_foreground.xml | 17 - .../capture_service_notification_icon.xml | 10 - .../src/main/res/drawable/ic_humid.xml | 9 - .../res/drawable/ic_launcher_foreground.xml | 17 - .../src/main/res/drawable/ic_rain.xml | 9 - .../src/main/res/drawable/ic_snow.xml | 9 - .../src/main/res/drawable/ic_windy.xml | 9 - .../src/main/res/drawable/wave.xml | 12 - .../src/main/res/font/anonymous_pro.ttf | Bin 112072 -> 0 bytes .../src/main/res/font/anonymous_pro_bold.ttf | Bin 107624 -> 0 bytes .../src/main/res/font/lato_regular.ttf | Bin 75136 -> 0 bytes .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 - .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 1462 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 3045 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1028 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 1865 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 2217 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 4357 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 3435 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 6894 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 4688 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 9927 -> 0 bytes .../src/main/res/values-night-v23/theme.xml | 23 - .../src/main/res/values-v21/theme.xml | 10 - .../src/main/res/values-v23/theme.xml | 28 -- .../src/main/res/values-v31/theme.xml | 7 - .../src/main/res/values/application.xml | 13 - .../src/main/res/values/capture.xml | 30 -- .../src/main/res/values/colors.xml | 8 - .../src/main/res/values/connection.xml | 15 - .../src/main/res/values/content.xml | 4 - .../res/values/ic_launcher_background.xml | 4 - .../src/main/res/values/info.xml | 4 - .../src/main/res/values/insights.xml | 18 - .../src/main/res/values/locale.xml | 10 - .../src/main/res/values/log.xml | 12 - .../src/main/res/values/map.xml | 7 - .../src/main/res/values/messages.xml | 16 - .../src/main/res/values/prompt.xml | 7 - .../src/main/res/values/settings.xml | 17 - .../src/main/res/values/station.xml | 11 - .../src/main/res/values/theme.xml | 38 -- .../src/main/res/values/transmit.xml | 17 - .../src/main/res/values/usage.xml | 77 ---- .../ack/android/maps/MapsImplementation.kt | 3 - .../inkapplications/ack/android/TestData.kt | 29 -- .../ack/android/TestDoubles.kt | 103 ----- .../capture/CaptureScreenFactoryTest.kt | 286 ------------ .../capture/insights/StatsStateFactoryTest.kt | 31 -- .../insights/WeatherStateFactoryTest.kt | 184 -------- .../ConversationViewStateFactoryTest.kt | 118 ----- .../index/MessageIndexStateFactoryTest.kt | 50 --- .../ack/android/input/IntegerValidatorTest.kt | 79 ---- .../CombinedLogItemViewStateFactoryTest.kt | 242 ---------- .../ack/android/log/SummaryFactoryTest.kt | 68 --- .../details/LogDetailsViewStateFactoryTest.kt | 196 -------- .../android/map/MarkerViewStateFactoryTest.kt | 65 --- .../onboard/OnboardingStateFactoryTest.kt | 68 --- .../settings/CompositeSettingsProviderTest.kt | 31 -- .../settings/PrioritySettingValuesTest.kt | 56 --- .../android/settings/SettingsAccessTest.kt | 197 -------- .../ack/android/settings/SettingsDoubles.kt | 23 - .../settings/SettingsViewStateFactoryTest.kt | 48 -- .../buildinfo/BuildInfoFactoryTest.kt | 78 ---- .../transformer/MileTransformerTest.kt | 18 - .../transformer/MillisecondTransformerTest.kt | 21 - .../transformer/MinuteTransformerTest.kt | 21 - .../SentinelOptionalTransformerTest.kt | 25 -- .../StationAddressTransformerTest.kt | 19 - .../StationInsightViewStateFactoryTest.kt | 158 ------- .../ack/android/symbol/SymbolDoubles.kt | 9 - .../symbol/SymbolResourceLocatorTest.kt | 45 -- .../android/transmit/PathTransformerTest.kt | 52 --- .../android/transmit/PercentageTransformer.kt | 19 - .../android/transmit/SymbolTransformerTest.kt | 17 - android-extensions/build.gradle.kts | 47 -- .../src/main/AndroidManifest.xml | 7 - .../android/extensions/Activities.kt | 40 -- .../android/extensions/ApplicationModule.kt | 74 --- .../android/extensions/ExtendedActivity.kt | 48 -- .../android/extensions/IntegerResources.kt | 33 -- .../android/extensions/Notifications.kt | 16 - .../android/extensions/StringResources.kt | 34 -- .../android/extensions/ViewStateFactory.kt | 11 - .../bluetooth/AndroidBluetoothAccess.kt | 97 ---- .../bluetooth/BluetoothDeviceAccess.kt | 34 -- .../bluetooth/BluetoothDeviceData.kt | 13 - .../android/extensions/compose/Modifiers.kt | 27 -- .../extensions/control/ControlState.kt | 35 -- .../AndroidResourceDateTimeFormatter.kt | 42 -- .../extensions/format/DateTimeFormatter.kt | 13 - .../location/AndroidLocationAccess.kt | 71 --- .../location/AndroidLocationUpdate.kt | 9 - .../extensions/location/LocationAccess.kt | 16 - .../src/main/res/values/date_formats.xml | 6 - .../AndroidResourceDateTimeFormatterTest.kt | 56 --- aprs-android/build.gradle.kts | 76 ---- aprs-android/src/main/AndroidManifest.xml | 5 - aprs-android/src/main/cpp/CMakeLists.txt | 7 - aprs-android/src/main/cpp/demod_afsk12.c | 126 ------ aprs-android/src/main/cpp/filter.h | 74 --- aprs-android/src/main/cpp/hdlc.c | 125 ------ aprs-android/src/main/cpp/multimon.c | 78 ---- aprs-android/src/main/cpp/multimon.h | 75 ---- .../ack/data/AfskModulationConfiguration.kt | 11 - .../ack/data/AndroidAfskModulator.kt | 147 ------ .../ack/data/AndroidAprsModule.kt | 111 ----- .../ack/data/AndroidLocationProvider.kt | 82 ---- .../ack/data/AudioDataCapture.kt | 74 --- .../ack/data/AudioDataProcessor.kt | 57 --- .../com/inkapplications/ack/data/CaptureId.kt | 4 - .../ack/data/CapturedPacket.kt | 12 - .../ack/data/ConnectionConfiguration.kt | 20 - .../ack/data/DaoPacketStorage.kt | 135 ------ .../com/inkapplications/ack/data/Multimon.kt | 29 -- .../inkapplications/ack/data/PacketOrigin.kt | 8 - .../inkapplications/ack/data/PacketStorage.kt | 79 ---- .../com/inkapplications/ack/data/Packets.kt | 18 - .../ack/data/adapters/CallsignAdapter.kt | 12 - .../data/adapters/CaptureIdColumnAdapter.kt | 12 - .../ack/data/adapters/InstantAdapter.kt | 12 - .../ack/data/adapters/PacketOriginAdapter.kt | 12 - .../ack/data/drivers/AfskDriver.kt | 115 ----- .../data/drivers/AudioConnectionMonitor.kt | 8 - .../ack/data/drivers/ConnectTncData.kt | 25 -- .../ack/data/drivers/DriverConnectionState.kt | 8 - .../data/drivers/DriverSettingsProvider.kt | 10 - .../ack/data/drivers/InternetDriver.kt | 143 ------ .../ack/data/drivers/PacketDriver.kt | 16 - .../ack/data/drivers/PacketDrivers.kt | 7 - .../ack/data/drivers/TncDriver.kt | 156 ------- .../ack/data/kiss/KissSchema.kt | 28 -- .../inkapplications/ack/data/kiss/Streams.kt | 71 --- .../ack/data/CapturedPacketEntity.sq | 69 --- buildSrc/build.gradle.kts | 17 - buildSrc/settings.gradle.kts | 7 - buildSrc/src/main/kotlin/Properties.kt | 21 - gradle.properties | 3 - gradle/libs.versions.toml | 283 ------------ gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 7 - gradlew | 249 ----------- gradlew.bat | 92 ---- mapbox/build.gradle.kts | 37 -- .../ack/android/mapbox/MapboxMapController.kt | 140 ------ .../ack/android/mapbox/MapboxMapRenderer.kt | 74 --- .../ack/android/mapbox/MapboxMapViews.kt | 30 -- .../ack/android/mapbox/MapboxZoomLevels.kt | 16 - .../res/drawable-nodpi/default_marker.png | Bin 1420 -> 0 bytes maps/build.gradle.kts | 34 -- .../ack/android/maps/DummyMapRenderer.kt | 19 - .../ack/android/maps/MapCameraPosition.kt | 20 - .../ack/android/maps/MapController.kt | 54 --- .../ack/android/maps/MapRenderer.kt | 20 - .../ack/android/maps/MapViewModel.kt | 7 - .../ack/android/maps/MarkerViewState.kt | 14 - .../ack/android/maps/ZoomLevels.kt | 14 - settings.gradle.kts | 9 - 602 files changed, 16 insertions(+), 16522 deletions(-) delete mode 100644 LICENSE create mode 100644 README.md delete mode 100644 android-application/build.gradle.kts delete mode 100644 android-application/compose_compiler_config.conf delete mode 100644 android-application/proguard-rules.pro delete mode 100644 android-application/src/functional/kotlin/com/inkapplications/ack/android/maps/MapsImplementation.kt delete mode 100644 android-application/src/main/AndroidManifest.xml delete mode 100644 android-application/src/main/ic_launcher-playstore.png delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/AnalyticsEvents.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/AprsApplication.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ExternalModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureEvents.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureNavController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreenStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/ControlPanelState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/TransmitPrototype.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsStatsState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsWeatherState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/insights/NearbyStationsState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/insights/StatsStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/insights/WeatherStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/MessageData.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/MessageEvents.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/MessageItemState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/ConversationItemState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessagesScreenController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/service/BackgroundCaptureService.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/capture/service/CaptureServiceNotifications.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/connection/ConnectionModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/connection/ConnectionSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/connection/DriverSelection.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseInitializer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/ConvertibleOptionalIntValidator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/EnumValidator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/IntPrompt.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/IntegerValidator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/MaxLengthValidator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/MinLengthValidator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/NoValidation.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/RegexValidator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/StringPrompt.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/ValidationResult.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/input/Validator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/locale/LocaleModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/locale/LocaleSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/locale/Units.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/AprsLogItem.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/CombinedLogItemViewStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/LogEvents.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/LogItemViewState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/LogItemViewStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/LogModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/LogSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/SummaryFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailData.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsViewStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexData.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/map/MapDataRepository.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/map/MapEvents.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/map/MapModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/map/MapScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/map/MapSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/map/MapViewState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/map/MarkerMap.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/map/MarkerViewStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingStateAccess.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/UsageAgreementPrompt.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/onboard/UserAgreementController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/CompositeSettingsProvider.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/LicenseData.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/LicenseViewState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/NullSettingsReadAccesss.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/Passcode.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/PrioritySettingValues.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/Setting.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingRows.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingVisibility.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsAccess.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsGroup.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsListData.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsListViewState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsProvider.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsReadAccess.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsViewStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsWriteAccess.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/SharedPreferenceSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/TransformableSetting.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UsageAgreement.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UsageAgreementReviewScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UserAgreementActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildData.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildDataAccess.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfo.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePrompt.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePromptFieldValues.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePromptValidator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/EnumTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/IntFieldTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MileTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MillisecondTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MinuteTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/OptionalIntTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/PercentageTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/SentinelOptionalTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/StationAddressTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/Transformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/TrimmingTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/ApplicationInitializer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/CompositeApplicationInitializer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/InitJob.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/KimchiInitializer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/NoOpInitializer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/StartupActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/StartupModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/StartupScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/startup/StartupViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/InsightViewState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationData.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationEvents.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationInsightViewStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationScreenController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/station/StationViewState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/symbol/AndroidSymbolFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolPrompt.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolResourceLocator.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolSelector.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolSelectorViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncActivity.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncState.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncStateFactory.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncViewModel.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/tnc/DeviceItem.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/tnc/DeviceListController.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/transmit/PathTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/transmit/PreferenceDriverSettingsProvider.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/transmit/SymbolTransformer.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/transmit/TransmitModule.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/transmit/TransmitSettings.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/AckChip.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/AprsSymbol.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/CallsignChip.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/EmptyBox.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/IconRow.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/KeyValueRow.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/LabelledIconButton.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/NavigationRow.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/SelectionRow.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/StateLabelledIconButton.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/TelemetryTable.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AckScreen.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AckTheme.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AprsFonts.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ColorPalette.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ColorVariant.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ShapeVariant.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/SizingVariant.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/SpacingVariant.kt delete mode 100644 android-application/src/main/java/com/inkapplications/ack/android/ui/theme/TypographyVariant.kt delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_0.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_1.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_10.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_100.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_101.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_102.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_103.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_104.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_105.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_106.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_107.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_108.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_109.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_11.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_110.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_111.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_112.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_113.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_114.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_115.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_116.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_117.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_118.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_119.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_12.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_120.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_121.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_122.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_123.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_124.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_125.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_126.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_127.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_128.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_129.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_13.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_130.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_131.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_132.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_133.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_134.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_135.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_136.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_137.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_138.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_139.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_14.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_140.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_141.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_142.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_143.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_144.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_145.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_146.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_147.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_148.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_149.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_15.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_150.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_151.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_152.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_153.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_154.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_155.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_156.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_157.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_158.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_159.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_16.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_160.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_161.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_162.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_163.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_164.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_165.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_166.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_167.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_168.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_169.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_17.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_170.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_171.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_172.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_173.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_174.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_175.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_176.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_177.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_178.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_179.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_18.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_180.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_181.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_182.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_183.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_184.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_185.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_186.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_187.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_188.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_189.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_19.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_190.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_191.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_2.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_20.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_207.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_208.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_209.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_21.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_210.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_211.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_212.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_213.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_214.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_215.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_216.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_22.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_224.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_225.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_226.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_227.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_228.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_229.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_23.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_230.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_231.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_232.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_233.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_234.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_235.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_236.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_237.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_238.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_239.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_24.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_240.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_241.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_242.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_243.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_244.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_245.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_246.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_247.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_248.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_249.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_25.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_26.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_27.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_28.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_29.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_3.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_30.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_31.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_32.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_33.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_34.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_35.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_36.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_37.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_38.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_39.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_4.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_40.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_41.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_42.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_43.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_44.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_45.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_46.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_47.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_48.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_49.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_5.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_50.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_51.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_52.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_53.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_54.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_55.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_56.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_57.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_58.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_59.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_6.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_60.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_61.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_62.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_63.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_64.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_65.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_66.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_67.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_68.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_69.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_7.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_70.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_71.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_72.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_73.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_74.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_75.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_76.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_77.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_78.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_79.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_8.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_80.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_81.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_82.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_83.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_84.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_85.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_86.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_87.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_88.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_89.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_9.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_90.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_91.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_92.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_93.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_94.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_95.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_96.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_97.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_98.png delete mode 100644 android-application/src/main/res/drawable-nodpi/symbol_99.png delete mode 100644 android-application/src/main/res/drawable-v31/ic_launcher_foreground.xml delete mode 100644 android-application/src/main/res/drawable/capture_service_notification_icon.xml delete mode 100644 android-application/src/main/res/drawable/ic_humid.xml delete mode 100644 android-application/src/main/res/drawable/ic_launcher_foreground.xml delete mode 100644 android-application/src/main/res/drawable/ic_rain.xml delete mode 100644 android-application/src/main/res/drawable/ic_snow.xml delete mode 100644 android-application/src/main/res/drawable/ic_windy.xml delete mode 100644 android-application/src/main/res/drawable/wave.xml delete mode 100644 android-application/src/main/res/font/anonymous_pro.ttf delete mode 100644 android-application/src/main/res/font/anonymous_pro_bold.ttf delete mode 100644 android-application/src/main/res/font/lato_regular.ttf delete mode 100644 android-application/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 android-application/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml delete mode 100644 android-application/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 android-application/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 android-application/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 android-application/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 android-application/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 android-application/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 android-application/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 android-application/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 android-application/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 android-application/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 android-application/src/main/res/values-night-v23/theme.xml delete mode 100644 android-application/src/main/res/values-v21/theme.xml delete mode 100644 android-application/src/main/res/values-v23/theme.xml delete mode 100644 android-application/src/main/res/values-v31/theme.xml delete mode 100644 android-application/src/main/res/values/application.xml delete mode 100644 android-application/src/main/res/values/capture.xml delete mode 100644 android-application/src/main/res/values/colors.xml delete mode 100644 android-application/src/main/res/values/connection.xml delete mode 100644 android-application/src/main/res/values/content.xml delete mode 100644 android-application/src/main/res/values/ic_launcher_background.xml delete mode 100644 android-application/src/main/res/values/info.xml delete mode 100644 android-application/src/main/res/values/insights.xml delete mode 100644 android-application/src/main/res/values/locale.xml delete mode 100644 android-application/src/main/res/values/log.xml delete mode 100644 android-application/src/main/res/values/map.xml delete mode 100644 android-application/src/main/res/values/messages.xml delete mode 100644 android-application/src/main/res/values/prompt.xml delete mode 100644 android-application/src/main/res/values/settings.xml delete mode 100644 android-application/src/main/res/values/station.xml delete mode 100644 android-application/src/main/res/values/theme.xml delete mode 100644 android-application/src/main/res/values/transmit.xml delete mode 100644 android-application/src/main/res/values/usage.xml delete mode 100644 android-application/src/stub/kotlin/com/inkapplications/ack/android/maps/MapsImplementation.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/TestData.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/TestDoubles.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/capture/CaptureScreenFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/capture/insights/StatsStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/capture/insights/WeatherStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/input/IntegerValidatorTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/log/CombinedLogItemViewStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/log/SummaryFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/log/details/LogDetailsViewStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/map/MarkerViewStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/onboard/OnboardingStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/CompositeSettingsProviderTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/PrioritySettingValuesTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsAccessTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsDoubles.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsViewStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MileTransformerTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MillisecondTransformerTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MinuteTransformerTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/SentinelOptionalTransformerTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/StationAddressTransformerTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/station/StationInsightViewStateFactoryTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/symbol/SymbolDoubles.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/symbol/SymbolResourceLocatorTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/transmit/PathTransformerTest.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/transmit/PercentageTransformer.kt delete mode 100644 android-application/src/test/java/com/inkapplications/ack/android/transmit/SymbolTransformerTest.kt delete mode 100644 android-extensions/build.gradle.kts delete mode 100644 android-extensions/src/main/AndroidManifest.xml delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/Activities.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/ApplicationModule.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/ExtendedActivity.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/IntegerResources.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/Notifications.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/StringResources.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/ViewStateFactory.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/AndroidBluetoothAccess.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/BluetoothDeviceAccess.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/BluetoothDeviceData.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/compose/Modifiers.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/control/ControlState.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/format/AndroidResourceDateTimeFormatter.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/format/DateTimeFormatter.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/location/AndroidLocationAccess.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/location/AndroidLocationUpdate.kt delete mode 100644 android-extensions/src/main/java/com/inkapplications/android/extensions/location/LocationAccess.kt delete mode 100644 android-extensions/src/main/res/values/date_formats.xml delete mode 100644 android-extensions/src/test/java/com/inkapplications/android/extensions/format/AndroidResourceDateTimeFormatterTest.kt delete mode 100644 aprs-android/build.gradle.kts delete mode 100644 aprs-android/src/main/AndroidManifest.xml delete mode 100644 aprs-android/src/main/cpp/CMakeLists.txt delete mode 100644 aprs-android/src/main/cpp/demod_afsk12.c delete mode 100644 aprs-android/src/main/cpp/filter.h delete mode 100644 aprs-android/src/main/cpp/hdlc.c delete mode 100644 aprs-android/src/main/cpp/multimon.c delete mode 100644 aprs-android/src/main/cpp/multimon.h delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/AfskModulationConfiguration.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/AndroidAfskModulator.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/AndroidAprsModule.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/AndroidLocationProvider.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/AudioDataCapture.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/AudioDataProcessor.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/CaptureId.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/CapturedPacket.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/ConnectionConfiguration.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/DaoPacketStorage.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/Multimon.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/PacketOrigin.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/PacketStorage.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/Packets.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/adapters/CallsignAdapter.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/adapters/CaptureIdColumnAdapter.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/adapters/InstantAdapter.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/adapters/PacketOriginAdapter.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AfskDriver.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AudioConnectionMonitor.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/ConnectTncData.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/DriverConnectionState.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/DriverSettingsProvider.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/InternetDriver.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/PacketDriver.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/PacketDrivers.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/drivers/TncDriver.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/kiss/KissSchema.kt delete mode 100644 aprs-android/src/main/java/com/inkapplications/ack/data/kiss/Streams.kt delete mode 100644 aprs-android/src/main/sqldelight/com/inkapplications/ack/data/CapturedPacketEntity.sq delete mode 100644 buildSrc/build.gradle.kts delete mode 100644 buildSrc/settings.gradle.kts delete mode 100644 buildSrc/src/main/kotlin/Properties.kt delete mode 100644 gradle.properties delete mode 100644 gradle/libs.versions.toml delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat delete mode 100644 mapbox/build.gradle.kts delete mode 100644 mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapController.kt delete mode 100644 mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapRenderer.kt delete mode 100644 mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapViews.kt delete mode 100644 mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxZoomLevels.kt delete mode 100644 mapbox/src/main/res/drawable-nodpi/default_marker.png delete mode 100644 maps/build.gradle.kts delete mode 100644 maps/src/main/kotlin/com/inkapplications/ack/android/maps/DummyMapRenderer.kt delete mode 100644 maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapCameraPosition.kt delete mode 100644 maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapController.kt delete mode 100644 maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapRenderer.kt delete mode 100644 maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapViewModel.kt delete mode 100644 maps/src/main/kotlin/com/inkapplications/ack/android/maps/MarkerViewState.kt delete mode 100644 maps/src/main/kotlin/com/inkapplications/ack/android/maps/ZoomLevels.kt delete mode 100644 settings.gradle.kts diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d511905c..00000000 --- a/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 00000000..ffd20e50 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +Ack Android +=========== + +[Download] The Ack Android Application from the Google Play Store! + +---------- + +In order to support development for the open source decoding library, +the Ack Android client must now be purchased through the play store. +Any support is appreciated! + +The [Ack] open-source decoding core library remains open source! + +[Download]: https://play.google.com/store/apps/details?id=com.inkapplications.ack.android +[Ack]: https://ack.inkapplications.com + diff --git a/android-application/build.gradle.kts b/android-application/build.gradle.kts deleted file mode 100644 index 3fec3d40..00000000 --- a/android-application/build.gradle.kts +++ /dev/null @@ -1,144 +0,0 @@ -plugins { - id("com.android.application") - kotlin("android") - kotlin("kapt") - id("com.google.gms.google-services") apply false - id("com.google.android.gms.oss-licenses-plugin") - id("com.google.firebase.crashlytics") - id("com.google.dagger.hilt.android") -} - -val useGoogleServices = project.file("google-services.json").exists() - -if (useGoogleServices) { - apply(plugin = "com.google.gms.google-services") -} - -android { - compileSdk = 35 - namespace = "com.inkapplications.ack.android" - defaultConfig { - minSdk = 21 - targetSdk = 35 - multiDexEnabled = true - buildConfigField("boolean", "USE_GOOGLE_SERVICES", useGoogleServices.toString()) - buildConfigField("String", "COMMIT", optionalStringProperty("commit").buildQuote()) - versionCode = intProperty("versionCode", 1) - versionName = stringProperty("versionName", "SNAPSHOT") - javaCompileOptions.annotationProcessorOptions.arguments["dagger.hilt.disableModulesHaveInstallInCheck"] = "true" - } - buildFeatures { - compose = true - buildConfig = true - } - - signingConfigs { - create("parameterSigning") { - storeFile = project.properties.getOrDefault("signingFile", null) - ?.toString() - ?.let { File("${project.rootDir}/$it") } - keyAlias = project.properties.getOrDefault("signingAlias", null)?.toString() - keyPassword = project.properties.getOrDefault("signingKeyPassword", null)?.toString() - storePassword = project.properties.getOrDefault("signingStorePassword", null)?.toString() - } - } - - buildTypes { - getByName("debug") { - applicationIdSuffix = ".debug" - resValue("string", "app_name", "Ack: APRS*") - } - getByName("release") { - resValue("string", "app_name", "Ack: APRS") - applicationIdSuffix = if (project.booleanProperty("snapshot", false)) ".snapshot" else null - signingConfig = if (project.hasProperty("signingFile")) { - signingConfigs.getByName("parameterSigning") - } else { - signingConfigs.getByName("debug") - } - - isMinifyEnabled = true - isShrinkResources = true - proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") - } - } - flavorDimensions += "function" - productFlavors { - create("functional") { - isDefault = true - dimension = "function" - } - create("stub") { - dimension = "function" - } - } - compileOptions { - targetCompatibility = JavaVersion.VERSION_11 - sourceCompatibility = JavaVersion.VERSION_11 - isCoreLibraryDesugaringEnabled = true - } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() - freeCompilerArgs += listOf( - "-P", - "plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" + - "${project.projectDir.absolutePath}/compose_compiler_config.conf" - ) - } - - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() - } - - packaging { - resources { - excludes += "META-INF/core.kotlin_module" - excludes += "META-INF/kotlinx-coroutines-core.kotlin_module" - } - } - - testOptions { - unitTests { - isReturnDefaultValues = true - } - } -} - -dependencies { - implementation(projects.androidExtensions) - implementation(projects.aprsAndroid) - - implementation(libs.coroutines.android) - - implementation(libs.androidx.appcompat) - implementation(libs.androidx.preference) - implementation(libs.androidx.activity.ktx) - implementation(libs.bundles.androidx.compose.full) - - implementation(libs.google.material.core) - - implementation(libs.bundles.dagger.libraries) - kapt(libs.bundles.dagger.kapt) - - implementation(libs.google.license.core) - - implementation(libs.kimchi.core) - implementation(libs.kimchi.firebase.analytics) - implementation(libs.kimchi.firebase.crashlytics) - - api(libs.spondee.units) - implementation(libs.ack.client) - - implementation(libs.bundles.watermelon) - - implementation(libs.firebase.config) - implementation(libs.firebase.analytics) - - implementation(projects.maps) - "functionalImplementation"(projects.mapbox) - - testImplementation(libs.junit) - testImplementation(libs.coroutines.test) - testImplementation(libs.kotlin.test.core) - coreLibraryDesugaring(libs.android.tools.desugar.jdk) -} diff --git a/android-application/compose_compiler_config.conf b/android-application/compose_compiler_config.conf deleted file mode 100644 index 8ffa7ea4..00000000 --- a/android-application/compose_compiler_config.conf +++ /dev/null @@ -1,2 +0,0 @@ -// Consider everything stable -**.* diff --git a/android-application/proguard-rules.pro b/android-application/proguard-rules.pro deleted file mode 100644 index b914daba..00000000 --- a/android-application/proguard-rules.pro +++ /dev/null @@ -1,27 +0,0 @@ -# Kotlin --keepattributes InnerClasses # Needed for `getDeclaredClasses`. --keep public class kotlinx.serialization.* { public *; } --dontwarn kotlinx.serialization.** --keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept. - static <1>$$serializer INSTANCE; -} - -# Okhttp --keep public class org.bouncycastle.jsse.** { *; } --dontwarn org.bouncycastle.jsse.** --keep public class org.conscrypt.** { *; } --dontwarn org.conscrypt.** --keep public class org.openjsse.** { *; } --dontwarn org.openjsse.** - -# Mapbox --keep class com.mapbox.android.telemetry.** --keep class com.mapbox.android.core.location.** --keep class android.arch.lifecycle.** { *; } --keep class com.mapbox.android.core.location.** { *; } --dontnote com.mapbox.mapboxsdk.** --dontnote com.mapbox.android.gestures.** --dontnote com.mapbox.mapboxsdk.plugins.** - --keep public class com.google.android.gms.* { public *; } --dontwarn com.google.android.gms.** diff --git a/android-application/src/functional/kotlin/com/inkapplications/ack/android/maps/MapsImplementation.kt b/android-application/src/functional/kotlin/com/inkapplications/ack/android/maps/MapsImplementation.kt deleted file mode 100644 index 6ff2d232..00000000 --- a/android-application/src/functional/kotlin/com/inkapplications/ack/android/maps/MapsImplementation.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.inkapplications.ack.android.maps - -import com.inkapplications.ack.android.mapbox.MapboxMapRenderer - -val MapsImplementation = MapboxMapRenderer diff --git a/android-application/src/main/AndroidManifest.xml b/android-application/src/main/AndroidManifest.xml deleted file mode 100644 index 5717fedb..00000000 --- a/android-application/src/main/AndroidManifest.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android-application/src/main/ic_launcher-playstore.png b/android-application/src/main/ic_launcher-playstore.png deleted file mode 100644 index b28ee7c31c7a4e4511a5512ec9d2ea97e331459c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13924 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 diff --git a/android-application/src/main/java/com/inkapplications/ack/android/AnalyticsEvents.kt b/android-application/src/main/java/com/inkapplications/ack/android/AnalyticsEvents.kt deleted file mode 100644 index b404f142..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/AnalyticsEvents.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.android - -import kimchi.analytics.KimchiAnalytics -import kimchi.analytics.stringProperty - -/** - * Track navigation events within the app. - */ -fun KimchiAnalytics.trackNavigation(destination: String) = trackEvent( - name = "navigate", - properties = listOf(stringProperty("destination", destination)) -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/AprsApplication.kt b/android-application/src/main/java/com/inkapplications/ack/android/AprsApplication.kt deleted file mode 100644 index ac4b31bd..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/AprsApplication.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android - -import android.app.Application -import com.inkapplications.ack.android.startup.InitJob -import dagger.hilt.android.HiltAndroidApp -import javax.inject.Inject - -@HiltAndroidApp -class AprsApplication: Application() { - @Inject - lateinit var initJob: InitJob - - override fun onCreate() { - super.onCreate() - - initJob.init(this) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ExternalModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/ExternalModule.kt deleted file mode 100644 index 05ece7de..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ExternalModule.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.inkapplications.ack.android - -import com.google.android.gms.common.GoogleApiAvailability -import dagger.Module -import dagger.Provides -import dagger.Reusable -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import kimchi.Kimchi -import kimchi.logger.KimchiLogger -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone - -@Module -@InstallIn(SingletonComponent::class) -class ExternalModule { - @Provides - @Reusable - fun kimchi(): KimchiLogger = Kimchi - - @Provides - @Reusable - fun clock(): Clock = Clock.System - - @Provides - @Reusable - fun timezone(): TimeZone = TimeZone.currentSystemDefault() - - @Provides - @Reusable - fun googleApis(): GoogleApiAvailability = GoogleApiAvailability.getInstance() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt deleted file mode 100644 index 264572ae..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt +++ /dev/null @@ -1,206 +0,0 @@ -package com.inkapplications.ack.android.capture - -import android.Manifest -import android.content.Intent -import android.content.pm.PackageManager -import android.net.Uri -import android.os.Build -import android.provider.Settings -import androidx.activity.compose.setContent -import androidx.appcompat.app.AlertDialog -import androidx.compose.runtime.collectAsState -import androidx.core.view.WindowCompat -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import com.inkapplications.ack.android.capture.insights.InsightsController -import com.inkapplications.ack.android.capture.messages.conversation.startConversationActivity -import com.inkapplications.ack.android.capture.messages.create.CreateConversationActivity -import com.inkapplications.ack.android.capture.messages.index.MessagesScreenController -import com.inkapplications.ack.android.capture.service.BackgroundCaptureService -import com.inkapplications.ack.android.capture.service.BackgroundCaptureServiceAudio -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.android.log.details.startLogInspectActivity -import com.inkapplications.ack.android.log.index.LogIndexController -import com.inkapplications.ack.android.map.MapEvents -import com.inkapplications.ack.android.map.MapViewState -import com.inkapplications.ack.android.maps.CameraPositionDefaults -import com.inkapplications.ack.android.maps.MapViewModel -import com.inkapplications.ack.android.settings.SettingsActivity -import com.inkapplications.ack.android.station.startStationActivity -import com.inkapplications.ack.android.tnc.startConnectTncActivity -import com.inkapplications.ack.android.trackNavigation -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.android.PermissionGate -import com.inkapplications.android.extensions.ExtendedActivity -import com.inkapplications.android.startActivity -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi -import kimchi.analytics.stringProperty -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.launch -import javax.inject.Inject - -/** - * Capture controls and data exploration. - * - * This is the primary activity in the application and provides controls - * to capture APRS packets and explore the data that has been captured. - */ -@AndroidEntryPoint -class CaptureActivity: ExtendedActivity(), CaptureNavController, LogIndexController, InsightsController { - @Inject - lateinit var mapEvents: MapEvents - - @Inject - lateinit var captureEvents: CaptureEvents - - private val permissionGate = PermissionGate(this) - private val backgroundCaptureServiceIntent by lazy { Intent(this, BackgroundCaptureService::class.java) } - private val backgroundCaptureAudioServiceIntent by lazy { Intent(this, BackgroundCaptureServiceAudio::class.java) } - - override fun onCreate() { - super.onCreate() - - setContent { - val mapState = mapEvents.viewState.collectAsState(MapViewState( - mapViewModel = MapViewModel( - cameraPosition = CameraPositionDefaults.unknownLocation, - markers = emptyList(), - ) - )) - val messagesScreenController = object: MessagesScreenController { - override fun onCreateMessageClick() { - startActivity(CreateConversationActivity::class) - } - override fun onConversationClick(callsign: Callsign) { - startConversationActivity(callsign) - } - } - - CaptureScreen( - mapState = mapState, - logIndexController = this, - messagesScreenController = messagesScreenController, - insightsController = this, - controller = this, - ) - } - } - - override fun onLogMapItemClick(log: LogItemViewState) { - Kimchi.trackEvent("map_log_click") - startStationActivity(log.source) - } - - override fun onMapItemClick(captureId: CaptureId?) { - Kimchi.trackEvent("map_item_select") - mapEvents.selectedItemId.value = captureId - } - - override fun onLogListItemClick(item: LogItemViewState) { - Kimchi.trackEvent("log_item_click") - startLogInspectActivity(item.id) - } - - override fun onStationItemClicked(item: LogItemViewState) { - Kimchi.trackEvent("insights_item_click") - startLogInspectActivity(item.id) - } - - override fun onLocationEnableClick() { - Kimchi.trackEvent("location_track_enable") - foregroundScope.launch { - permissionGate.withPermissions(Manifest.permission.ACCESS_FINE_LOCATION) { - mapEvents.trackingEnabled.value = true - } - } - } - - override fun onLocationDisableClick() { - Kimchi.trackEvent("location_track_disable") - mapEvents.trackingEnabled.value = false - } - - override fun onSettingsClick() { - Kimchi.trackNavigation("settings") - startActivity(SettingsActivity::class) - } - - override fun onConnectClick() { - Kimchi.trackEvent("capture_connect") - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - val hasBackgroundLocation = checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED - - if (!hasBackgroundLocation) { - AlertDialog.Builder(this) - .setTitle("Background Location Permission Required") - .setMessage("To capture data in the background, this app needs access to your location even when the app is closed.\n\nPlease grant \"Allow all the time\" location permission in the application settings.") - .setPositiveButton("Open Settings") { _, _ -> - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { - data = Uri.fromParts("package", packageName, null) - } - startActivity(intent) - } - .setNegativeButton("Cancel", null) - .show() - return - } - } - - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.CREATED) { - permissionGate.withPermissions(*captureEvents.getDriverConnectPermissions().toTypedArray()) { - lifecycleScope.launch { - when (captureEvents.driverSelection.first()) { - DriverSelection.Tnc -> { - startConnectTncActivity(backgroundCaptureServiceIntent) - } - DriverSelection.Audio -> { - startForegroundService(backgroundCaptureAudioServiceIntent) - } - else -> { - startForegroundService(backgroundCaptureServiceIntent) - } - } - } - } - } - } - } - - override fun onDisconnectClick() { - Kimchi.trackEvent("capture_disconnect") - lifecycleScope.launch { - captureEvents.disconnectDriver() - stopService(backgroundCaptureServiceIntent) - } - } - - override fun onEnableLocationTransmitClick() { - Kimchi.trackEvent("transmit_enable") - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.CREATED) { - permissionGate.withPermissions(*captureEvents.getDriverTransmitPermissions().toTypedArray() + Manifest.permission.ACCESS_FINE_LOCATION) { - captureEvents.locationTransmitState.value = true - } - } - } - } - - override fun onDisableLocationTransmitClick() { - Kimchi.trackEvent("transmit_disable") - captureEvents.locationTransmitState.value = false - } - - override fun onDriverSelected(selection: DriverSelection) { - Kimchi.trackEvent("driver_select", listOf(stringProperty("selection", selection.name))) - lifecycleScope.launch { - stopService(backgroundCaptureServiceIntent) - captureEvents.changeDriver(selection) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureEvents.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureEvents.kt deleted file mode 100644 index fc1f4d24..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureEvents.kt +++ /dev/null @@ -1,166 +0,0 @@ -package com.inkapplications.ack.android.capture - -import com.inkapplications.ack.android.connection.ConnectionSettings -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.android.settings.* -import com.inkapplications.ack.android.transmit.TransmitSettings -import com.inkapplications.ack.data.drivers.DriverConnectionState -import com.inkapplications.ack.data.drivers.PacketDriver -import com.inkapplications.ack.data.drivers.PacketDrivers -import com.inkapplications.ack.structures.* -import com.inkapplications.android.extensions.location.LocationAccess -import com.inkapplications.coroutines.combinePair -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.isActive -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.coroutines.coroutineContext - -/** - * Provides data access to abstractions around capturing APRS packets. - */ -@Singleton -class CaptureEvents @Inject constructor( - private val drivers: PacketDrivers, - private val readSettings: SettingsReadAccess, - private val writeSettings: SettingsWriteAccess, - private val connectionSettings: ConnectionSettings, - private val transmitSettings: TransmitSettings, - private val locationAccess: LocationAccess, - private val logger: KimchiLogger, -) { - val driverSelection = readSettings.observeData(connectionSettings.driver) - - private val currentDriver = driverSelection - .map { - when (it) { - DriverSelection.Audio -> drivers.afskDriver - DriverSelection.Internet -> drivers.internetDriver - DriverSelection.Tnc -> drivers.tncDriver - } - } - - /** - * The current state of the selected APRS driver connection. - */ - val connectionState: Flow = currentDriver - .flatMapLatest { it.connectionState } - - /** - * Whether the option to repeatedly transmit the device location is enabled. - */ - val locationTransmitState = MutableStateFlow(false) - - /** - * The current audio input level, or null when not capturing. - */ - val audioInputVolume = drivers.afskDriver.volume.combine(connectionState) { volume, state -> - when (state) { - DriverConnectionState.Connected -> volume - else -> null - } - } - - /** - * Change the current APRS driver. - * - * Note: This will disconnect the current driver and location state - * if enabled, and will require a reconnection. - */ - suspend fun changeDriver(value: DriverSelection) { - currentDriver.first().disconnect() - locationTransmitState.value = false - writeSettings.setData(connectionSettings.driver, value) - } - - suspend fun getDriverConnectPermissions(): Set { - return currentDriver.first().receivePermissions - } - - suspend fun getDriverTransmitPermissions(): Set { - return currentDriver.first().transmitPermissions - } - - suspend fun connectDriver() { - currentDriver.first().connect() - } - - suspend fun disconnectDriver() { - currentDriver.first().disconnect() - } - - suspend fun locationTransmitLoop() { - locationTransmitState.combinePair(currentDriver) - .collectLatest { (transmit, driver) -> - if (transmit) transmitLoop(driver) - } - } - - /** - * Transmit an APRS packet to the specified driver at the configured interval. - */ - private suspend fun transmitLoop(driver: PacketDriver) { - logger.trace("Starting transmit loop") - readSettings.observeData(connectionSettings.address) - .filterNotNull() - .combine(readSettings.observeData(transmitSettings.digipath)) { callsign, path -> - TransmitPrototype( - path = path, - destination = transmitSettings.destination.defaultData, - callsign = callsign, - symbol = transmitSettings.symbol.defaultData, - comment = transmitSettings.comment.defaultValue, - minRate = transmitSettings.minRate.defaultData, - maxRate = transmitSettings.maxRate.defaultData, - distance = transmitSettings.distance.defaultData, - ) - } - .combine(readSettings.observeData(transmitSettings.symbol)) { prototype, symbol -> - prototype.copy(symbol = symbol) - } - .combine(readSettings.observeString(transmitSettings.comment)) { prototype, comment -> - prototype.copy(comment = comment) - } - .combine(readSettings.observeData(transmitSettings.destination)) { prototype, destination -> - prototype.copy(destination = destination) - } - .combine(readSettings.observeData(transmitSettings.minRate)) { prototype, rate -> - prototype.copy(minRate = rate) - } - .combine(readSettings.observeData(transmitSettings.maxRate)) { prototype, rate -> - prototype.copy(maxRate = rate) - } - .combine(readSettings.observeData(transmitSettings.distance)) { prototype, distance -> - prototype.copy(distance = distance) - } - .onEach { logger.debug("Location Transmit Prototype: $it") } - .flatMapLatest { prototype -> - locationAccess.observeLocationChanges(prototype.maxRate, prototype.distance) - .map { prototype to it } - .onCompletion { logger.warn("Location Transmit Stopped") } - } - .collectLatest { (prototype, update) -> - while (coroutineContext.isActive) { - val packet = AprsPacket( - route = PacketRoute( - source = prototype.callsign, - digipeaters = prototype.path, - destination = prototype.destination, - ), - data = PacketData.Position( - coordinates = update.location, - symbol = prototype.symbol, - altitude = update.altitude, - comment = prototype.comment, - ) - ) - val encodingConfig = EncodingConfig(compression = EncodingPreference.Disfavored) - - driver.transmitPacket(packet, encodingConfig) - delay(prototype.minRate) - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureNavController.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureNavController.kt deleted file mode 100644 index bfe2de44..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureNavController.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.inkapplications.ack.android.capture - -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.data.CaptureId - -/** - * Capture navigation and control panel options. - */ -interface CaptureNavController { - /** - * Invoked when the user clicks to enable location tracking on the map. - */ - fun onLocationEnableClick() - - /** - * Invoked when the user clicks to disable location tracking on the map. - */ - fun onLocationDisableClick() - - /** - * Invoked when the user clicks on the highlighted log item. - * - * Note, this is the popover overlay, not the pin click. - */ - fun onLogMapItemClick(log: LogItemViewState) - - /** - * Invoked when the user clicks on the settings button. - */ - fun onSettingsClick() - - /** - * Invoked when the user clicks on the button to enable the driver connection. - */ - fun onConnectClick() - - /** - * Invoked when the user clicks on the button to disable the driver connection. - */ - fun onDisconnectClick() - - /** - * Invoked when the user clicks on the location transmit enable button. - */ - fun onEnableLocationTransmitClick() - - /** - * Invoked when the user clicks on the location transmit disable button. - */ - fun onDisableLocationTransmitClick() - - /** - * Invoked when the user selects a new radio driver. - */ - fun onDriverSelected(selection: DriverSelection) - - /** - * Invoked when the user clicks an item on the map - */ - fun onMapItemClick(captureId: CaptureId?) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreen.kt deleted file mode 100644 index 5962bd38..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreen.kt +++ /dev/null @@ -1,421 +0,0 @@ -@file:OptIn(ExperimentalLayoutApi::class) - -package com.inkapplications.ack.android.capture - -import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable -import androidx.navigation.compose.currentBackStackEntryAsState -import androidx.navigation.compose.rememberNavController -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.capture.insights.InsightsController -import com.inkapplications.ack.android.capture.insights.InsightsScreen -import com.inkapplications.ack.android.capture.messages.MessageIndexScreen -import com.inkapplications.ack.android.capture.messages.index.MessagesScreenController -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.android.connection.readableName -import com.inkapplications.ack.android.log.index.LogIndexController -import com.inkapplications.ack.android.log.index.LogIndexScreen -import com.inkapplications.ack.android.map.MapScreen -import com.inkapplications.ack.android.map.MapViewState -import com.inkapplications.ack.android.trackNavigation -import com.inkapplications.ack.android.ui.AckChip -import com.inkapplications.ack.android.ui.SelectionRow -import com.inkapplications.ack.android.ui.StateLabelledIconButton -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.android.extensions.control.ControlState -import kimchi.Kimchi -import kotlinx.coroutines.launch - -@OptIn(ExperimentalMaterialApi::class) -@Composable -fun CaptureScreen( - mapState: State, - logIndexController: LogIndexController, - messagesScreenController: MessagesScreenController, - controller: CaptureNavController, - insightsController: InsightsController, - viewModel: CaptureViewModel = hiltViewModel(), -) = AckScreen { - val settingsSheetState = rememberBottomSheetScaffoldState() - val navController = rememberNavController() - navController.enableOnBackPressed(!settingsSheetState.bottomSheetState.isExpanded) - val captureScreenState = viewModel.controlPanelState.collectAsState() - SettingsSheetWrapper( - settingsSheetState = settingsSheetState, - controlPanelState = captureScreenState, - captureController = controller, - ) { - Column { - Scaffold( - modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars), - bottomBar = { CaptureBottomBar(navController) }, - floatingActionButton = { CaptureSettingsFab(settingsSheetState) }, - isFloatingActionButtonDocked = true, - floatingActionButtonPosition = FabPosition.Center, - ) { - CaptureNavHost( - navController = navController, - mapState = mapState, - logIndexController = logIndexController, - messagesScreenController = messagesScreenController, - captureController = controller, - insightsController = insightsController, - ) - } - } - } -} - -@Composable -private fun CaptureBottomBar( - navController: NavHostController, -) { - BottomAppBar( - backgroundColor = AckTheme.colors.background, - contentColor = contentColorFor(AckTheme.colors.surface), - cutoutShape = RoundedCornerShape(50), - contentPadding = PaddingValues(0.dp), - modifier = Modifier.fillMaxWidth(), - ) { - val currentRoute = navController.currentBackStackEntryAsState().value?.destination?.route - BottomNavigation( - backgroundColor = AckTheme.colors.surface, - contentColor = contentColorFor(AckTheme.colors.surface), - modifier = Modifier.fillMaxWidth() - ) { - BottomNavigationItem( - icon = { Icon(Icons.Default.Map, contentDescription = null) }, - label = { Text(stringResource(R.string.menu_capture_map), softWrap = false) }, - selected = currentRoute == "map", - onClick = { - Kimchi.info("Navigate to map") - Kimchi.trackNavigation("map") - if (currentRoute != "map") { - navController.navigate("map") - } - } - ) - BottomNavigationItem( - icon = { Icon(Icons.Default.List, contentDescription = null) }, - label = { Text(stringResource(R.string.menu_capture_log), softWrap = false) }, - selected = currentRoute == "log", - onClick = { - Kimchi.info("Navigate to log") - Kimchi.trackNavigation("log") - if (currentRoute != "log") { - navController.navigate("log") - } - } - ) - Spacer(Modifier.weight(1f, true)) - BottomNavigationItem( - icon = { Icon(Icons.Default.Mail, contentDescription = null) }, - label = { Text("Messages", softWrap = false) }, - selected = currentRoute == "messages", - onClick = { - Kimchi.info("Navigate to messages") - Kimchi.trackNavigation("messages") - if (currentRoute != "messages") { - navController.navigate("messages") - } - } - ) - BottomNavigationItem( - icon = { Icon(Icons.Default.Lightbulb, contentDescription = null) }, - label = { Text("Insights", softWrap = false) }, - selected = currentRoute == "insights", - onClick = { - Kimchi.info("Navigate to insights") - Kimchi.trackNavigation("insights") - if (currentRoute != "insights") { - navController.navigate("insights") - } - } - ) - } - } -} - -@OptIn(ExperimentalMaterialApi::class) -@Composable -private fun CaptureSettingsFab( - settingsSheetState: BottomSheetScaffoldState, -) { - val scope = rememberCoroutineScope() - FloatingActionButton( - onClick = { - scope.launch { - if (settingsSheetState.bottomSheetState.isExpanded) { - settingsSheetState.bottomSheetState.collapse() - } else { - settingsSheetState.bottomSheetState.expand() - } - } - }, - shape = RoundedCornerShape(50), - backgroundColor = AckTheme.colors.accent, - contentColor = AckTheme.colors.onAccent - ) { - Icon(Icons.Default.SettingsInputAntenna, stringResource(R.string.capture_controls_expand_action)) - } -} - -@OptIn(ExperimentalMaterialApi::class) -@Composable -private fun SettingsSheetWrapper( - settingsSheetState: BottomSheetScaffoldState, - controlPanelState: State, - captureController: CaptureNavController, - content: @Composable () -> Unit, -) { - BottomSheetScaffold( - sheetContent = { CaptureSettingsSheet(controlPanelState.value, captureController, settingsSheetState) }, - scaffoldState = settingsSheetState, - sheetPeekHeight = 0.dp, - ) { - content() - } -} - -@OptIn(ExperimentalMaterialApi::class) -@Composable -private fun CaptureSettingsSheet( - controlPanelState: ControlPanelState, - captureController: CaptureNavController, - settingsSheetState: BottomSheetScaffoldState, -) = Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars), -) { - val scope = rememberCoroutineScope() - BackHandler(enabled = settingsSheetState.bottomSheetState.isExpanded) { - scope.launch { settingsSheetState.bottomSheetState.collapse() } - } - Row( - horizontalArrangement = Arrangement.Center, - modifier = Modifier.fillMaxWidth(), - ) { - IconButton( - onClick = { scope.launch { settingsSheetState.bottomSheetState.collapse() } }, - ) { - Icon(Icons.Default.DragHandle, stringResource(R.string.capture_controls_collapse_action)) - } - } - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = AckTheme.spacing.gutter), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - if (controlPanelState is ControlPanelState.Loaded) { - Icon( - imageVector = Icons.Default.Badge, - contentDescription = null, - tint = AckTheme.colors.foreground, - modifier = Modifier.padding(horizontal = AckTheme.spacing.icon) - ) - Text( - text = controlPanelState.userCallsign, - style = AckTheme.typography.h1, - ) - } - } - Row { - IconButton( - onClick = { - scope.launch { - settingsSheetState.bottomSheetState.collapse() - } - captureController.onSettingsClick() - } - ) { - Icon( - imageVector = Icons.Default.Settings, - contentDescription = stringResource(R.string.capture_controls_settings_name), - tint = AckTheme.colors.foreground, - ) - } - } - } - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxWidth(), - ) { - var selector by remember { mutableStateOf(false) } - - if (selector) { - Dialog( - onDismissRequest = { selector = false }, - ) { - Card( - modifier = Modifier.fillMaxWidth(), - ) { - Column { - Text( - text = "Connection", - style = AckTheme.typography.h1, - modifier = Modifier.padding( - top = AckTheme.spacing.gutter, - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - bottom = AckTheme.spacing.content, - ) - ) - DriverSelection.values().forEach { driver -> - SelectionRow( - name = stringResource(id = driver.readableName), - selected = driver == (controlPanelState as? ControlPanelState.Loaded)?.connectionType, - onClick = { - captureController.onDriverSelected(driver) - selector = false - }, - ) - } - } - } - } - } - - AckChip( - onClick = { selector = true }, - ) { - Icon( - imageVector = Icons.Default.Tune, - contentDescription = null, - tint = AckTheme.colors.foreground, - modifier = Modifier.padding(end = AckTheme.spacing.icon), - ) - Text( - text = if (controlPanelState is ControlPanelState.Loaded) { - controlPanelState.connection - } else { - stringResource(R.string.capture_controls_connection_type_unknown) - } - ) - } - } - val volume = (controlPanelState as? ControlPanelState.Loaded)?.volumeLevel - if (volume != null) { - LinearProgressIndicator( - progress = volume, - modifier = Modifier - .fillMaxWidth() - .padding(top = AckTheme.spacing.item), - ) - } - FlowRow( - horizontalArrangement = Arrangement.Center, - ) { - Row { - StateLabelledIconButton( - icon = when (controlPanelState.connectState) { - ControlState.On -> Icons.Default.WifiTethering - ControlState.Off, - ControlState.Disabled, - ControlState.Hidden -> Icons.Default.WifiTetheringOff - }, - title = when (controlPanelState.connectState) { - ControlState.On -> stringResource(R.string.capture_controls_connection_on) - ControlState.Off, - ControlState.Disabled, - ControlState.Hidden, -> stringResource(R.string.capture_controls_connection_off) - }, - state = controlPanelState.connectState, - onClick = { - when (it) { - ControlState.On -> captureController.onDisconnectClick() - ControlState.Off -> captureController.onConnectClick() - ControlState.Disabled, - ControlState.Hidden -> {} - } - }, - ) - StateLabelledIconButton( - icon = when (controlPanelState.positionTransmitState) { - ControlState.On -> Icons.Default.ModeOfTravel - ControlState.Off, - ControlState.Disabled, - ControlState.Hidden -> Icons.Default.LocationOff - }, - title = when (controlPanelState.positionTransmitState) { - ControlState.On -> stringResource(R.string.capture_controls_position_on) - ControlState.Off, - ControlState.Disabled, - ControlState.Hidden, -> stringResource(R.string.capture_controls_position_off) - }, - state = controlPanelState.positionTransmitState, - onClick = { - when (it) { - ControlState.On -> captureController.onDisableLocationTransmitClick() - ControlState.Off -> captureController.onEnableLocationTransmitClick() - ControlState.Disabled, - ControlState.Hidden -> {} - } - }, - ) - } - } -} - -@Composable -private fun CaptureNavHost( - navController: NavHostController, - mapState: State, - logIndexController: LogIndexController, - messagesScreenController: MessagesScreenController, - captureController: CaptureNavController, - insightsController: InsightsController, -) { - NavHost( - navController = navController, - startDestination = "map", - modifier = Modifier.fillMaxSize(), - ) { - composable("map") { - MapScreen( - state = mapState.value, - onMapItemClick = captureController::onMapItemClick, - onLogItemClick = captureController::onLogMapItemClick, - onEnableLocation = captureController::onLocationEnableClick, - onDisableLocation = captureController::onLocationDisableClick, - bottomContentProtection = AckTheme.spacing.bottomBarHeight, - ) - } - composable("log") { - LogIndexScreen( - controller = logIndexController, - ) - } - composable("messages") { - MessageIndexScreen( - controller = messagesScreenController, - bottomProtection = AckTheme.spacing.bottomBarHeight, - bottomContentProtection = AckTheme.spacing.navigationProtection, - ) - } - composable("insights") { - InsightsScreen( - controller = insightsController - ) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreenStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreenStateFactory.kt deleted file mode 100644 index b400332d..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreenStateFactory.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.inkapplications.ack.android.capture - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.android.connection.readableName -import com.inkapplications.ack.android.settings.LicenseData -import com.inkapplications.ack.data.drivers.DriverConnectionState -import com.inkapplications.android.extensions.StringResources -import com.inkapplications.android.extensions.control.ControlState -import dagger.Reusable -import inkapplications.spondee.scalar.Percentage -import inkapplications.spondee.structure.toFloat -import javax.inject.Inject - -/** - * Create view state models from current state data. - */ -@Reusable -class CaptureScreenStateFactory @Inject constructor( - private val stringResources: StringResources, -) { - /** - * Create a new model from the capture data provided. - */ - fun controlPanelState( - currentDriver: DriverSelection, - driverConnectionState: DriverConnectionState, - positionTransmit: Boolean, - license: LicenseData, - inputAudioLevel: Percentage?, - ): ControlPanelState { - return ControlPanelState.Loaded( - userCallsign = license.address?.toString() ?: stringResources.getString(R.string.capture_callsign_missing), - volumeLevel = inputAudioLevel?.toDecimal()?.toFloat(), - connection = stringResources.getString(currentDriver.readableName), - connectState = when { - driverConnectionState == DriverConnectionState.Connected -> ControlState.On - currentDriver == DriverSelection.Internet && license.address == null -> ControlState.Disabled - else -> ControlState.Off - }, - connectionType = currentDriver, - positionTransmitState = when { - positionTransmit -> ControlState.On - driverConnectionState != DriverConnectionState.Connected -> ControlState.Disabled - currentDriver == DriverSelection.Internet && license.passcode == null -> ControlState.Disabled - license.address == null -> ControlState.Disabled - else -> ControlState.Off - }, - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureViewModel.kt deleted file mode 100644 index 442cdf95..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureViewModel.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.inkapplications.ack.android.capture - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.connection.ConnectionSettings -import com.inkapplications.ack.android.settings.SettingsAccess -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.observeData -import com.inkapplications.ack.data.drivers.PacketDrivers -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android ViewModel to create and store the state of the capture screen. - */ -@HiltViewModel -class CaptureViewModel @Inject constructor( - captureEvents: CaptureEvents, - settings: SettingsReadAccess, - connectionSettings: ConnectionSettings, - settingsAccess: SettingsAccess, - drivers: PacketDrivers, - captureScreenStateFactory: CaptureScreenStateFactory, -): ViewModel() { - val controlPanelState: StateFlow = combine( - settings.observeData(connectionSettings.driver), - settingsAccess.licenseData, - captureEvents.audioInputVolume, - captureEvents.connectionState, - captureEvents.locationTransmitState, - ) { driver, license, audioInputVolume, connectedState, positionTransmitState -> - captureScreenStateFactory.controlPanelState( - currentDriver = driver, - driverConnectionState = connectedState, - positionTransmit = positionTransmitState, - license = license, - inputAudioLevel = audioInputVolume, - ) - }.stateIn(viewModelScope, SharingStarted.Eagerly, ControlPanelState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/ControlPanelState.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/ControlPanelState.kt deleted file mode 100644 index 45af515a..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/ControlPanelState.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.inkapplications.ack.android.capture - -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.android.extensions.control.ControlState - -/** - * Represents the states for the capture screen's control panel. - */ -sealed interface ControlPanelState { - /** - * State of the connection toggle button. - */ - val connectState: ControlState - - /** - * State of the position toggle button. - */ - val positionTransmitState: ControlState - - /** - * Object used before any data has been loaded successfully. - */ - object Initial: ControlPanelState { - override val connectState: ControlState = ControlState.Disabled - override val positionTransmitState: ControlState = ControlState.Disabled - } - - /** - * Data for how to display the control panel based on application state. - */ - data class Loaded( - /** - * The user's current callsign, as a readable string. - */ - val userCallsign: String, - - /** - * Level of the input volume, if applicable to the connection. - */ - val volumeLevel: Float?, - - /** - * Name of the current connection type. - */ - val connection: String, - - /** - * Data type for the current connection - */ - val connectionType: DriverSelection, - - /** - * State of the connection toggle button. - */ - override val connectState: ControlState, - - /** - * State of the position toggle button. - */ - override val positionTransmitState: ControlState, - ): ControlPanelState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/TransmitPrototype.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/TransmitPrototype.kt deleted file mode 100644 index 85d8c913..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/TransmitPrototype.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.inkapplications.ack.android.capture - -import com.inkapplications.ack.structures.Digipeater -import com.inkapplications.ack.structures.Symbol -import com.inkapplications.ack.structures.station.StationAddress -import inkapplications.spondee.measure.Length -import kotlin.time.Duration - -/** - * Data used when creating a transmitted packet. - */ -data class TransmitPrototype( - val path: List, - val destination: StationAddress, - val callsign: StationAddress, - val symbol: Symbol, - val comment: String, - val minRate: Duration, - val maxRate: Duration, - val distance: Length, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsController.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsController.kt deleted file mode 100644 index 8dd11744..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsController.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -import com.inkapplications.ack.android.log.LogItemViewState - -/** - * User actions available on the insights screen. - */ -interface InsightsController { - /** - * Invoked when the user clicks on a station in the nearby frequency list. - */ - fun onStationItemClicked(item: LogItemViewState) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsScreen.kt deleted file mode 100644 index 7ff950ba..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsScreen.kt +++ /dev/null @@ -1,198 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Thermostat -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.log.AprsLogItem -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun InsightsScreen( - viewModel: InsightsViewModel = hiltViewModel(), - controller: InsightsController, -) { - AckScreen { - val weatherState = viewModel.weatherState.collectAsState() - val stationsState = viewModel.stations.collectAsState() - val statsState = viewModel.statsState.collectAsState() - - Column( - modifier = Modifier.verticalScroll(rememberScrollState()).padding( - top = AckTheme.spacing.gutter, - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - bottom = AckTheme.spacing.navigationProtection + AckTheme.spacing.gutter, - ) - ) { - Text(stringResource(R.string.insights_title), style = AckTheme.typography.h1) - Weather(weatherState.value) - NearbyStations(stationsState.value, controller) - Stats(statsState.value) - } - } -} - -@Composable -private fun NearbyStations( - state: NearbyStationsState, - controller: InsightsController, -) { - Column { - Text(stringResource(R.string.insights_stations_title), style = AckTheme.typography.h2, modifier = Modifier.padding(vertical = AckTheme.spacing.content)) - when (state) { - NearbyStationsState.Initial -> {} - NearbyStationsState.Empty -> { - Text(stringResource(id = R.string.insights_stations_empty_caption), style = AckTheme.typography.caption) - } - is NearbyStationsState.StationList -> { - state.stations.forEach { station -> - AprsLogItem(station, onClick = controller::onStationItemClicked) - } - } - } - } -} - -@Composable -private fun Stats( - state: InsightsStatsState, -) { - Column { - Text(stringResource(R.string.insights_packets_title), style = AckTheme.typography.h2, modifier = Modifier.padding(vertical = AckTheme.spacing.content)) - when (state) { - InsightsStatsState.Initial -> {} - InsightsStatsState.None -> { - Text(stringResource(id = R.string.insights_stats_placeholder), style = AckTheme.typography.body) - } - is InsightsStatsState.LoadedData -> { - Text(stringResource(R.string.insights_packets_count, state.packets), style = AckTheme.typography.body) - Text(stringResource(R.string.insights_stations_count, state.stations), style = AckTheme.typography.body) - } - } - } -} - -@Composable -private fun Weather( - state: InsightsWeatherState, -) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .fillMaxWidth() - .padding(vertical = AckTheme.spacing.content), - ) { - when (state) { - InsightsWeatherState.Initial, - InsightsWeatherState.Unknown -> WeatherPlaceholder() - is InsightsWeatherState.DisplayRecent -> WeatherData(state) - } - } -} - -@Composable -private fun WeatherData( - data: InsightsWeatherState.DisplayRecent, -) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .fillMaxWidth() - .padding(vertical = AckTheme.spacing.content), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - WeatherIcon(iconState = data.icon) - Text(data.temperature, style = AckTheme.typography.display) - } - Text( - text = stringResource( - R.string.insights_weather_report_info_template, - data.weatherReporter, - data.weatherReportTime - ), - style = AckTheme.typography.caption - ) - } -} - -@Composable -private fun WeatherPlaceholder() { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .fillMaxWidth() - .padding(vertical = AckTheme.spacing.content), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - Icon( - imageVector = Icons.Default.Thermostat, - contentDescription = stringResource(R.string.insights_weather_icon_normal), - modifier = Modifier.size(AckTheme.sizing.dispayIcon), - tint = AckTheme.colors.foreground, - ) - Text("--", style = AckTheme.typography.display) - } - Text( - text = stringResource(R.string.insights_weather_placeholder_caption), - style = AckTheme.typography.caption - ) - } -} - -@Composable -private fun WeatherIcon( - iconState: InsightsWeatherState.WeatherIcon, -) { - val iconModifier = Modifier.size(AckTheme.sizing.displayDecorationIcon) - val iconTint = AckTheme.colors.foreground - - when (iconState) { - InsightsWeatherState.WeatherIcon.Normal -> Icon( - imageVector = Icons.Default.Thermostat, - contentDescription = stringResource(R.string.insights_weather_icon_normal), - modifier = iconModifier, - tint = iconTint, - ) - InsightsWeatherState.WeatherIcon.Rain -> Icon( - painter = painterResource(id = R.drawable.ic_rain), - contentDescription = stringResource(R.string.insights_weather_icon_rain), - modifier = iconModifier, - tint = iconTint, - ) - InsightsWeatherState.WeatherIcon.Snow -> Icon( - painter = painterResource(id = R.drawable.ic_snow), - contentDescription = stringResource(R.string.insights_weather_icon_snow), - modifier = iconModifier, - tint = iconTint, - ) - InsightsWeatherState.WeatherIcon.Humid -> Icon( - painter = painterResource(id = R.drawable.ic_humid), - contentDescription = stringResource(R.string.insights_weather_icon_humid), - modifier = iconModifier, - tint = iconTint, - ) - InsightsWeatherState.WeatherIcon.Windy -> Icon( - painter = painterResource(id = R.drawable.ic_windy), - contentDescription = stringResource(R.string.insights_weather_icon_wind), - modifier = iconModifier, - tint = iconTint, - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsStatsState.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsStatsState.kt deleted file mode 100644 index deeab967..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsStatsState.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -/** - * States for the "stats" section of the insight screen. - */ -sealed interface InsightsStatsState { - /** - * Indicates that no data has been loaded yet. - */ - object Initial: InsightsStatsState - - /** - * Indicates that data has been loaded, but the user has no packets - * to generate stats from. - */ - object None: InsightsStatsState - - /** - * Loaded Stats about captured packets - */ - data class LoadedData( - /** - * Total number of captured packets. - */ - val packets: Long, - - /** - * Distinct stations that have been seen in the captured packets. - */ - val stations: Long, - ): InsightsStatsState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsViewModel.kt deleted file mode 100644 index b0e7d167..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsViewModel.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.locale.LocaleSettings -import com.inkapplications.ack.android.log.LogItemViewStateFactory -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.observeBoolean -import com.inkapplications.ack.data.PacketStorage -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.coroutines.filterItems -import dagger.hilt.android.lifecycle.HiltViewModel -import kimchi.logger.EmptyLogger -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.flow.* -import kotlinx.datetime.Clock -import javax.inject.Inject -import kotlin.time.Duration.Companion.hours - -/** - * Android Viewmodel to load various view state information for the Insights page. - */ -@HiltViewModel -class InsightsViewModel @Inject constructor( - packetStorage: PacketStorage, - settings: SettingsReadAccess, - localeSettings: LocaleSettings, - private val weatherStateFactory: WeatherStateFactory, - private val statsStateFactory: StatsStateFactory, - private val logItemViewStateFactory: LogItemViewStateFactory, - private val clock: Clock = Clock.System, - private val logger: KimchiLogger = EmptyLogger, -): ViewModel() { - /** - * State of the weather insights section. - */ - val weatherState: StateFlow = packetStorage.findMostRecentByType(PacketData.Weather::class) - .map { if (it?.received?.let { it > clock.now() - 2.hours } == true) it else null } - .combine(settings.observeBoolean(localeSettings.preferMetric)) { weatherPacket, metric -> - weatherStateFactory.createState(weatherPacket, metric) - } - .stateIn(viewModelScope, SharingStarted.Lazily, InsightsWeatherState.Initial) - - /** - * State of the packet stats section. - */ - val statsState: StateFlow = packetStorage.count() - .onEach { logger.debug("Building stats for $it packets") } - .combine(packetStorage.countStations()) { packetCount, stationCount -> - statsStateFactory.createState( - packetCount = packetCount, - stationCount = stationCount, - ) - } - .stateIn(viewModelScope, SharingStarted.Lazily, InsightsStatsState.Initial) - - /** - * State of nearby stations broadcasting contact frequencies. - */ - val stations: StateFlow = packetStorage.findByStationComments(limit = 10) - .filterItems { it.received > clock.now() - 1.hours } - .combine(settings.observeBoolean(localeSettings.preferMetric)) { stations, metric -> - logItemViewStateFactory.create(stations, metric) - } - .map { - if (it.isEmpty()) NearbyStationsState.Empty - else NearbyStationsState.StationList(it) - } - .stateIn(viewModelScope, SharingStarted.Lazily, NearbyStationsState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsWeatherState.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsWeatherState.kt deleted file mode 100644 index 641d8af9..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/InsightsWeatherState.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -/** - * States for the weather section of the insight screen. - */ -sealed interface InsightsWeatherState { - /** - * Indicates that no data has been loaded yet. - */ - object Initial: InsightsWeatherState - - /** - * Indicates that no relevant weather packets have been captured yet. - */ - object Unknown: InsightsWeatherState - - /** - * Recent Weather Information - */ - data class DisplayRecent( - /** - * Current Temperature, as a formatted string. - */ - val temperature: String, - - /** - * The reporting station callsign of the weather data. - */ - val weatherReporter: String, - - /** - * The time that the weather data was reported, as a preformatted - * string in the local time. - */ - val weatherReportTime: String, - - /** - * An indication of what iconography to display with the weather. - */ - val icon: WeatherIcon - ): InsightsWeatherState - - /** - * Iconography options that hint at the current weather conditions. - */ - enum class WeatherIcon { - Normal, - Rain, - Snow, - Humid, - Windy, - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/NearbyStationsState.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/NearbyStationsState.kt deleted file mode 100644 index 346e5351..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/NearbyStationsState.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -import com.inkapplications.ack.android.log.LogItemViewState - -sealed interface NearbyStationsState { - object Initial: NearbyStationsState - object Empty: NearbyStationsState - data class StationList( - val stations: List, - ): NearbyStationsState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/StatsStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/StatsStateFactory.kt deleted file mode 100644 index b040c812..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/StatsStateFactory.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -import dagger.Reusable -import javax.inject.Inject - -/** - * Creates stats view state models based on current data. - */ -@Reusable -class StatsStateFactory @Inject constructor() { - /** - * Generate a view state for the given statistics. - * - * @param packetCount The total number of packets that have been collected. - * @param stationCount The number of distinct stations that have reported packets. - */ - fun createState(packetCount: Long, stationCount: Long): InsightsStatsState { - return when (packetCount) { - 0L -> InsightsStatsState.None - else -> InsightsStatsState.LoadedData( - packets = packetCount, - stations = stationCount, - ) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/WeatherStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/WeatherStateFactory.kt deleted file mode 100644 index 2c9d9399..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/insights/WeatherStateFactory.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -import com.inkapplications.ack.android.locale.format -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.android.extensions.format.DateTimeFormatter -import dagger.Reusable -import inkapplications.spondee.measure.us.toFahrenheit -import inkapplications.spondee.measure.us.toInches -import inkapplications.spondee.measure.us.toMilesPerHourValue -import inkapplications.spondee.structure.toFloat -import inkapplications.spondee.structure.toInt -import javax.inject.Inject - -/** - * Generate weather view state models based on the most relevant weather packet. - */ -@Reusable -class WeatherStateFactory @Inject constructor( - private val dateTimeFormatter: DateTimeFormatter, -) { - /** - * Generate a view state for weather conditions. - * - * @param weatherPacket The most relevant weather packet seen by the user - * @param metric Whether to generate the view data in metric dimensions - */ - fun createState(weatherPacket: CapturedPacket?, metric: Boolean): InsightsWeatherState { - return when (val weatherData = weatherPacket?.parsed?.data as? PacketData.Weather) { - null -> InsightsWeatherState.Unknown - else -> InsightsWeatherState.DisplayRecent( - temperature = weatherData.temperature?.format(metric) ?: "--", - weatherReporter = weatherPacket.parsed.route.source.toString(), - weatherReportTime = weatherPacket.received.let { dateTimeFormatter.formatTimestamp(it) }, - icon = when { - weatherData.precipitation.snowLast24Hours?.toInches()?.toFloat() ?: 0f > 0 -> InsightsWeatherState.WeatherIcon.Snow - weatherData.precipitation.rainLastHour?.toInches()?.toFloat() ?: 0f > 0 -> InsightsWeatherState.WeatherIcon.Rain - weatherData.windData.speed?.toMilesPerHourValue()?.toInt() ?: 0 > 20 -> InsightsWeatherState.WeatherIcon.Windy - weatherData.windData.gust?.toMilesPerHourValue()?.toInt() ?: 0 > 20 -> InsightsWeatherState.WeatherIcon.Windy - weatherData.humidity?.toDecimal()?.toFloat() ?: 0f > .75f - && weatherData.temperature?.toFahrenheit()?.toInt() ?: 0 > 65 -> InsightsWeatherState.WeatherIcon.Humid - else -> InsightsWeatherState.WeatherIcon.Normal - } - ) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/MessageData.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/MessageData.kt deleted file mode 100644 index ef9f6a7d..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/MessageData.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.inkapplications.ack.android.capture.messages - -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.structures.station.Callsign - -/** - * Contextual information used for displaying messages. - */ -data class MessageData( - /** - * Callsign of the user of the app. Used to distinguished "my" messages. - */ - val selfCallsign: Callsign, - - /** - * Packet data for the message. - */ - val message: CapturedPacket, -) { - /** - * Whether the sender matches the users callsign. - */ - val isOutgoing = message.parsed.route.source.callsign == selfCallsign -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/MessageEvents.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/MessageEvents.kt deleted file mode 100644 index 36879619..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/MessageEvents.kt +++ /dev/null @@ -1,110 +0,0 @@ -package com.inkapplications.ack.android.capture.messages - -import com.inkapplications.ack.android.connection.ConnectionSettings -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.observeData -import com.inkapplications.ack.android.settings.observeString -import com.inkapplications.ack.android.transmit.TransmitSettings -import com.inkapplications.ack.codec.AprsCodec -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.data.PacketStorage -import com.inkapplications.ack.data.drivers.PacketDrivers -import com.inkapplications.ack.structures.* -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.ack.structures.station.StationAddress -import com.inkapplications.ack.structures.station.toStationAddress -import com.inkapplications.coroutines.filterItems -import com.inkapplications.coroutines.mapItems -import dagger.Reusable -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.flow.* -import javax.inject.Inject - -/** - * Aggregates events and settings for packet data relating to messages. - */ -@Reusable -class MessageEvents @Inject constructor( - private val packetStorage: PacketStorage, - private val settings: SettingsReadAccess, - private val connectionSettings: ConnectionSettings, - private val transmitSettings: TransmitSettings, - private val codec: AprsCodec, - private val drivers: PacketDrivers, - private val logger: KimchiLogger, -) { - /** - * Observe a list of the latest message in each distinct conversation - * by station callsign. - */ - val latestMessageByConversation = settings.observeData(connectionSettings.address) - .onEach { logger.debug("Observing conversations for addressee: $it") } - .flatMapLatest { address -> - address?.callsign?.let(packetStorage::findLatestByConversation) - ?.mapItems { MessageData(address.callsign, it) } - ?: flowOf(emptyList()) - } - .onEach { logger.debug("Found ${it.size} conversations") } - - private val currentDriver = settings.observeData(connectionSettings.driver) - .map { - when (it) { - DriverSelection.Audio -> drivers.afskDriver - DriverSelection.Internet -> drivers.internetDriver - DriverSelection.Tnc -> drivers.tncDriver - } - } - - /** - * Observe the total list of messages sent to and from a particular station. - * - * @param address The callsign of the station to find messages for. - */ - fun conversationList(address: Callsign): Flow> { - return settings.observeData(connectionSettings.address) - .flatMapLatest { self -> - (self?.callsign?.let { packetStorage.findConversation(address, it) }?.mapItems { MessageData(self.callsign, it) } ?: flowOf(emptyList())) - } - .filterItems { it.message.parsed.data is PacketData.Message } - .onEach { logger.debug("Loaded ${it.size} messages from $address") } - } - - /** - * Transmit a new message via all connected transmission drivers. - * - * This will immediately transmit the message to any connected drivers - * as well as save the message in the local database as a locally - * transmitted packet. - * - * @param addressee The callsign of the station to send the message to. - * @param message The body text of the message to be sent. - */ - suspend fun transmitMessage(addressee: Callsign, message: String) { - val packetData = PacketData.Message( - addressee = StationAddress(addressee), - message = message, - ) - - val address = settings.observeData(connectionSettings.address).first() ?: run { - logger.error("Cannot transmit without a callsign set!") - return - } - val path = settings.observeString(transmitSettings.digipath).first() - val destination = settings.observeString(transmitSettings.destination).first() - - val packet = AprsPacket( - route = PacketRoute( - source = address, - digipeaters = path.split(',').map { Digipeater(it.toStationAddress()) }, - destination = destination.toStationAddress(), - ), - data = packetData, - ) - val encodingConfig = EncodingConfig(compression = EncodingPreference.Disfavored) - - currentDriver.first().transmitPacket(packet, encodingConfig) - val encoded = codec.toString(packet) - packetStorage.save(encoded.toByteArray(), packet, PacketOrigin.Local) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationActivity.kt deleted file mode 100644 index 2364e7b5..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationActivity.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.conversation - -import android.app.Activity -import androidx.activity.compose.setContent -import com.inkapplications.ack.android.capture.messages.MessageEvents -import com.inkapplications.ack.android.trackNavigation -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.android.extensions.ExtendedActivity -import com.inkapplications.android.startActivity -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi -import kotlinx.coroutines.launch -import javax.inject.Inject - -/** - * Intent Extra used for the addressee of the conversation. - */ -const val EXTRA_ADDRESS = "aprs.conversation.extra.address" - -/** - * Activity for viewing a single conversation's messages with another station. - */ -@AndroidEntryPoint -class ConversationActivity: ExtendedActivity(), ConversationController { - @Inject - lateinit var messageEvents: MessageEvents - - private val callsign get() = intent.getStringExtra(EXTRA_ADDRESS)!!.let(::Callsign) - - override fun onCreate() { - super.onCreate() - Kimchi.trackScreen("conversation") - setContent { - ConversationScreen(this) - } - } - - override fun onNavigateUpPressed() { - finish() - } - - override fun onSendMessage(message: String) { - Kimchi.debug("Sending Message: $message") - Kimchi.trackEvent("messages_send") - foregroundScope.launch { - messageEvents.transmitMessage(callsign, message) - Kimchi.trace("Message transmit action complete") - } - } -} - -/** - * Start a conversation activity for a particular station. - * - * @param callsign The callsign of the station to load messages for. - */ -fun Activity.startConversationActivity(callsign: Callsign) { - Kimchi.trackNavigation("conversation") - startActivity(ConversationActivity::class) { - putExtra(EXTRA_ADDRESS, callsign.canonical) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationController.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationController.kt deleted file mode 100644 index 4cdc6772..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationController.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.conversation - -/** - * Actions that can be taken from the conversation screen. - */ -interface ConversationController { - /** - * Invoked when the user presses the back/up button on the navigation bar. - */ - fun onNavigateUpPressed() - - /** - * Invoked when the user presses the send button in the message box. - * - * @param message The text the user has entered in the message box. - */ - fun onSendMessage(message: String) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationScreen.kt deleted file mode 100644 index 603ff2ea..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationScreen.kt +++ /dev/null @@ -1,143 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.conversation - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.material.icons.filled.Message -import androidx.compose.material.icons.filled.Send -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.EmptyBox -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun ConversationScreen( - controller: ConversationController, - viewModel: ConversationViewModel = hiltViewModel(), -) = AckScreen { - Column { - val viewState = viewModel.conversationState.collectAsState().value - TopAppBar( - elevation = 1.dp, - ) { - IconButton( - onClick = controller::onNavigateUpPressed, - ) { - Icon(Icons.Default.ArrowBack, stringResource(R.string.navigate_up)) - } - Text(viewState.title, style = AckTheme.typography.h1) - } - when (viewState) { - is ConversationViewState.Initial -> {} - is ConversationViewState.Empty -> EmptyBox( - icon = Icons.Default.Message, - caption = stringResource(R.string.messages_conversation_empty), - modifier = Modifier.weight(1f), - ) - is ConversationViewState.MessageList -> LazyColumn( - contentPadding = PaddingValues(vertical = AckTheme.spacing.gutter), - reverseLayout = true, - modifier = Modifier.weight(1f) - ) { - items(viewState.messages.reversed()) { IncomingMessage(it) } - } - } - Surface( - shape = AckTheme.shapes.corners, - color = AckTheme.colors.surface, - modifier = Modifier - .fillMaxWidth() - .padding(AckTheme.spacing.gutter), - ) { - Column { - Text( - text = viewState.connectionText, - style = AckTheme.typography.caption, - modifier = Modifier.align(Alignment.CenterHorizontally).padding(top = AckTheme.spacing.item) - ) - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - val textFieldValue = remember { mutableStateOf("") } - OutlinedTextField( - value = textFieldValue.value, - onValueChange = { textFieldValue.value = it }, - singleLine = true, - placeholder = { Text(stringResource(R.string.messages_conversation_send_placeholder)) }, - colors = TextFieldDefaults.outlinedTextFieldColors( - backgroundColor = Color.Transparent, - focusedBorderColor = Color.Transparent, - unfocusedBorderColor = Color.Transparent, - disabledBorderColor = Color.Transparent, - ), - modifier = Modifier.weight(1f), - ) - IconButton( - onClick = { - controller.onSendMessage(textFieldValue.value) - textFieldValue.value = "" - }, - enabled = viewState.sendEnabled, - ) { - Icon(Icons.Default.Send, stringResource(R.string.messages_conversation_send_action)) - } - } - } - } - } -} - -@Composable -private fun IncomingMessage(viewModel: MessageItemState) { - Box( - contentAlignment = viewModel.alignment, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = AckTheme.spacing.gutter, vertical = AckTheme.spacing.singleItem) - ) { - Message(viewModel) - } -} - -@Composable -private fun Message(viewModel: MessageItemState) { - Card( - shape = RoundedCornerShape(16.dp), - modifier = Modifier.defaultMinSize(minWidth = 75.dp) - ) { - Column( - modifier = Modifier.padding(AckTheme.spacing.content) - ) { - Text(viewModel.message, style = AckTheme.typography.body) - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.align(Alignment.End), - ) { - Text( - text = viewModel.timestamp, - style = AckTheme.typography.caption, - modifier = Modifier.padding(end = AckTheme.spacing.item), - ) - Icon( - imageVector = viewModel.icon, - contentDescription = viewModel.iconDescription, - modifier = Modifier.size(10.dp), - ) - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewModel.kt deleted file mode 100644 index 0bf668e7..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewModel.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.conversation - -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.capture.CaptureEvents -import com.inkapplications.ack.android.capture.messages.MessageEvents -import com.inkapplications.ack.structures.station.Callsign -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android Viewmodel to load state information for the conversation with [EXTRA_ADDRESS] as the - * target addressee. - */ -@HiltViewModel -class ConversationViewModel @Inject constructor( - savedState: SavedStateHandle, - messageEvents: MessageEvents, - captureEvents: CaptureEvents, - conversationViewStateFactory: ConversationViewStateFactory, -): ViewModel() { - private val conversationAddress = savedState.get(EXTRA_ADDRESS)?.let(::Callsign)!! - - val conversationState = combine( - messageEvents.conversationList(conversationAddress), - captureEvents.driverSelection, - captureEvents.connectionState - ) { messages, driverSelection, connectionState -> - conversationViewStateFactory.createMessageList(conversationAddress, messages, connectionState, driverSelection) - }.stateIn(viewModelScope, SharingStarted.Eagerly, conversationViewStateFactory.createInitial(conversationAddress)) -} - - diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewState.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewState.kt deleted file mode 100644 index 87215ffa..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewState.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.conversation - -/** - * States for a single conversation view. - */ -sealed interface ConversationViewState { - /** - * Title of the page to display in navigation. - */ - val title: String - - /** - * Whether the send button in the message form should be clickable. - */ - val sendEnabled: Boolean - - /** - * Text displayed above the message field to signify the connection status. - */ - val connectionText: String - - /** - * Indicates that no data has been loaded yet. - */ - data class Initial( - override val title: String, - override val connectionText: String, - ): ConversationViewState { - override val sendEnabled: Boolean = false - } - - /** - * Indicates that data has been loaded, but there are no messages yet. - */ - data class Empty( - override val title: String, - override val sendEnabled: Boolean, - override val connectionText: String, - ): ConversationViewState - - /** - * Message data for the conversation. - * - * @param messages The list of message history. - */ - data class MessageList( - override val title: String, - val messages: List, - override val sendEnabled: Boolean, - override val connectionText: String, - ): ConversationViewState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewStateFactory.kt deleted file mode 100644 index 11199726..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewStateFactory.kt +++ /dev/null @@ -1,110 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.conversation - -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Bluetooth -import androidx.compose.material.icons.filled.Cloud -import androidx.compose.material.icons.filled.SettingsInputAntenna -import androidx.compose.material.icons.filled.Storage -import androidx.compose.ui.Alignment -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.capture.messages.MessageData -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.android.connection.readableName -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.data.drivers.DriverConnectionState -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.android.extensions.StringResources -import com.inkapplications.android.extensions.format.DateTimeFormatter -import dagger.Reusable -import javax.inject.Inject - -/** - * Creates Conversation state models based on a list of message packets. - */ -@Reusable -class ConversationViewStateFactory @Inject constructor( - private val dateTimeFormatter: DateTimeFormatter, - private val stringResources: StringResources, -) { - /** - * Create the initial viewstate for the view. - * - * @param adressee The callsign of the station this conversation is with. - */ - fun createInitial(adressee: Callsign): ConversationViewState { - return ConversationViewState.Initial( - title = createTitle(adressee), - connectionText = stringResources.getString(R.string.messages_conversation_disconnected) - ) - } - - /** - * Create a message list state model. - * - * @param adressee The callsign of the station this conversation is with. - * @param messages a list of message objectsto be displayed in the conversation. - */ - fun createMessageList( - addressee: Callsign, - messages: List, - connectionState: DriverConnectionState, - driverSelection: DriverSelection, - ): ConversationViewState { - val title = createTitle(addressee) - val connectionText = when (connectionState) { - DriverConnectionState.Connected -> stringResources.getString(R.string.messages_conversation_connected, stringResources.getString(driverSelection.readableName)) - else -> stringResources.getString(R.string.messages_conversation_disconnected) - } - - return when { - messages.isEmpty() -> ConversationViewState.Empty( - title = title, - sendEnabled = connectionState == DriverConnectionState.Connected, - connectionText = connectionText, - ) - else -> ConversationViewState.MessageList( - title = title, - messages = messages.map { createMessageView(it) }, - sendEnabled = connectionState == DriverConnectionState.Connected, - connectionText = connectionText, - ) - } - } - - /** - * Create a single message item's state model. - * - * @param data The message data to render into the state model - */ - private fun createMessageView(data: MessageData): MessageItemState { - return MessageItemState( - message = (data.message.parsed.data as PacketData.Message).message, - timestamp = dateTimeFormatter.formatTimestamp(data.message.received), - alignment = if (data.isOutgoing) { - Alignment.CenterEnd - } else { - Alignment.CenterStart - }, - icon = when (data.message.origin) { - PacketOrigin.Ax25 -> Icons.Default.SettingsInputAntenna - PacketOrigin.AprsIs -> Icons.Default.Cloud - PacketOrigin.Tnc -> Icons.Default.Bluetooth - PacketOrigin.Local -> Icons.Default.Storage - }, - iconDescription = when (data.message.origin) { - PacketOrigin.Ax25 -> stringResources.getString(R.string.messages_item_icon_ax25_description) - PacketOrigin.AprsIs -> stringResources.getString(R.string.messages_item_icon_internet_description) - PacketOrigin.Tnc -> stringResources.getString(R.string.messages_item_icon_tnc_description) - PacketOrigin.Local -> stringResources.getString(R.string.messages_item_icon_local_description) - }, - ) - } - - /** - * Create a readable title from a callsign object. - * - * @param callsign The callsign to be displayed. - */ - private fun createTitle(callsign: Callsign): String = callsign.canonical -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/MessageItemState.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/MessageItemState.kt deleted file mode 100644 index f2be807c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/conversation/MessageItemState.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.conversation - -import androidx.compose.ui.Alignment -import androidx.compose.ui.graphics.vector.ImageVector - -/** - * State model for a single message in a conversation. - */ -data class MessageItemState( - /** - * The content of the message that was sent. - */ - val message: String, - - /** - * Readable timestamp in local time. - */ - val timestamp: String, - - /** - * Alignment of the text bubble based on the sender. - */ - val alignment: Alignment, - - /** - * State icon used to indicate how the message was sent. - */ - val icon: ImageVector, - - /** - * Content description used for [icon]'s accessibility. - */ - val iconDescription: String, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationActivity.kt deleted file mode 100644 index 8792ded3..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationActivity.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.create - -import androidx.activity.compose.setContent -import com.inkapplications.ack.android.capture.messages.conversation.startConversationActivity -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.android.extensions.ExtendedActivity -import kimchi.Kimchi - -/** - * Screen to prompt the user to start a conversation with a specific station. - */ -class CreateConversationActivity: ExtendedActivity(), CreateConversationController { - override fun onCreate() { - super.onCreate() - - Kimchi.trackScreen("create_conversation") - setContent { - CreateConversationScreen(this) - } - } - - override fun onCreateClick(callsign: String) { - Kimchi.trackEvent("create_conversation_start") - finish() - startConversationActivity(Callsign(callsign)) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationController.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationController.kt deleted file mode 100644 index 6bb3ac19..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationController.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.create - -/** - * Actions invoked on the new message screen - */ -interface CreateConversationController { - /** - * Invoked when the user clicks the "start messaging" button. - */ - fun onCreateClick(callsign: String) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationScreen.kt deleted file mode 100644 index 78cdbeea..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/create/CreateConversationScreen.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.create - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Button -import androidx.compose.material.Text -import androidx.compose.material.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun CreateConversationScreen( - controller: CreateConversationController, -) { - AckScreen { - Column( - modifier = Modifier.padding(AckTheme.spacing.gutter) - ) { - Text(stringResource(R.string.messages_create_title), style = AckTheme.typography.h1) - - val callsign = rememberSaveable { mutableStateOf("") } - TextField( - value = callsign.value, - label = { Text(stringResource(R.string.messages_create_field_callsign_label)) }, - onValueChange = { callsign.value = it }, - modifier = Modifier.fillMaxWidth().padding(top = AckTheme.spacing.content), - ) - - Button( - onClick = { controller.onCreateClick(callsign.value.trim()) }, - modifier = Modifier.fillMaxWidth().padding(top = AckTheme.spacing.item), - ) { - Text(stringResource(R.string.messages_create_start_action, callsign.value)) - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/ConversationItemState.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/ConversationItemState.kt deleted file mode 100644 index b46d4373..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/ConversationItemState.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.index - -import com.inkapplications.ack.structures.station.Callsign - -/** - * Models the view state for a single conversation item in the index. - */ -data class ConversationItemState( - /** - * The displayable name of the correspondent. - */ - val name: String, - - /** - * A preview snippet of the latest message in the conversation. - */ - val messagePreview: String, - - /** - * The callsign of the correspondent, used as an identifier when navigating. - */ - val correspondent: Callsign, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexScreen.kt deleted file mode 100644 index 91d2d36e..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexScreen.kt +++ /dev/null @@ -1,103 +0,0 @@ -package com.inkapplications.ack.android.capture.messages - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Inbox -import androidx.compose.material.icons.filled.Message -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.Dp -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.capture.messages.index.ConversationItemState -import com.inkapplications.ack.android.capture.messages.index.MessageIndexState -import com.inkapplications.ack.android.capture.messages.index.MessageIndexViewModel -import com.inkapplications.ack.android.capture.messages.index.MessagesScreenController -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun MessageIndexScreen( - controller: MessagesScreenController, - bottomProtection: Dp, - bottomContentProtection: Dp, - viewModel: MessageIndexViewModel = hiltViewModel(), -) = AckScreen { - val screenState = viewModel.indexState.collectAsState() - - when (val state = screenState.value) { - MessageIndexState.Initial -> {} - is MessageIndexState.ConversationList -> ConversationList(state, controller, bottomContentProtection) - is MessageIndexState.Empty -> EmptyPlaceholder() - } - Box( - modifier = Modifier - .fillMaxSize() - .padding(bottom = bottomProtection), - contentAlignment = Alignment.BottomEnd, - ) { - FloatingActionButton( - onClick = controller::onCreateMessageClick, - backgroundColor = AckTheme.colors.surface, - contentColor = contentColorFor(AckTheme.colors.surface), - modifier = Modifier.padding(AckTheme.spacing.gutter) - ) { - Icon(Icons.Default.Message, stringResource(R.string.messages_compose_action)) - } - } -} - -@Composable -private fun EmptyPlaceholder() = Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .padding(bottom = AckTheme.spacing.navigationProtection) - .fillMaxSize() -) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Icon( - imageVector = Icons.Default.Inbox, - contentDescription = null, - tint = AckTheme.colors.foregroundInactive, - modifier = Modifier.size(AckTheme.sizing.dispayIcon), - ) - Text("No messages received") - } -} - -@Composable -private fun ConversationList( - state: MessageIndexState.ConversationList, - controller: MessagesScreenController, - bottomProtection: Dp, -) { - LazyColumn( - contentPadding = PaddingValues(bottom = bottomProtection) - ) { - items(state.conversations) { conversation -> - ConversationItem(conversation, controller) - } - } -} - -@Composable -@OptIn(ExperimentalMaterialApi::class) -private fun ConversationItem(viewModel: ConversationItemState, controller: MessagesScreenController) { - Card( - onClick = { controller.onConversationClick(viewModel.correspondent) }, - modifier = Modifier.padding(horizontal = AckTheme.spacing.gutter, vertical = AckTheme.spacing.singleItem) - ) { - Column(modifier = Modifier - .padding(AckTheme.spacing.content) - .fillMaxWidth()) { - Text(viewModel.name, style = AckTheme.typography.h2) - Text(viewModel.messagePreview) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexState.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexState.kt deleted file mode 100644 index ae8c9b36..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexState.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.index - -/** - * State of the list of conversations screen. - */ -sealed interface MessageIndexState { - /** - * Indicates that no data has been loaded yet. - */ - object Initial: MessageIndexState - - /** - * State that indicates that data is loaded, but no messages have been - * sent or received. - */ - object Empty: MessageIndexState - - /** - * Loaded data to display a list of conversations. - */ - data class ConversationList( - /** - * Conversation rows to display. - */ - val conversations: List, - ): MessageIndexState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexStateFactory.kt deleted file mode 100644 index b07e57a8..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexStateFactory.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.index - -import com.inkapplications.ack.android.capture.messages.MessageData -import com.inkapplications.ack.structures.PacketData -import dagger.Reusable -import javax.inject.Inject - -/** - * Create the state models for a list of message conversations. - */ -@Reusable -class MessageIndexStateFactory @Inject constructor() { - /** - * Create a state object for the conversation list. - * - * @param latestMessages A list of the latest messages in each conversation. - */ - fun createScreenState(latestMessages: List): MessageIndexState { - return when { - latestMessages.isEmpty() -> MessageIndexState.Empty - else -> MessageIndexState.ConversationList( - conversations = latestMessages.map(::createConversationItem), - ) - } - } - - /** - * Create a single conversation state model from its latest message. - * - * @param data The latest message in this conversation. - */ - private fun createConversationItem(data: MessageData): ConversationItemState { - val message = data.message.parsed.data as PacketData.Message - val correspondent = message.addressee.takeIf { data.isOutgoing } ?: data.message.parsed.route.source - return ConversationItemState( - name = correspondent.callsign.canonical, - messagePreview = message.message, - correspondent = correspondent.callsign, - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexViewModel.kt deleted file mode 100644 index c5069f35..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexViewModel.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.index - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.capture.messages.MessageEvents -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android viewmodel to load state information for the conversation list. - */ -@HiltViewModel -class MessageIndexViewModel @Inject constructor( - private val messageEvents: MessageEvents, - private val messageIndexStateFactory: MessageIndexStateFactory, -): ViewModel() { - /** - * List of conversations to be displayed. - */ - val indexState = messageEvents.latestMessageByConversation - .map { messageIndexStateFactory.createScreenState(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, MessageIndexState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessagesScreenController.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessagesScreenController.kt deleted file mode 100644 index fc934d22..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/messages/index/MessagesScreenController.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.index - -import com.inkapplications.ack.structures.station.Callsign - -/** - * Actions that can be taken on the messages screen. - */ -interface MessagesScreenController { - /** - * Invoked when the user clicks the new conversation button. - */ - fun onCreateMessageClick() - - /** - * Invoked when the user clicks on a conversation - * - * @param callsign The callsign as an identifier for the conversation that was clicked. - */ - fun onConversationClick(callsign: Callsign) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/service/BackgroundCaptureService.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/service/BackgroundCaptureService.kt deleted file mode 100644 index fe04f560..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/service/BackgroundCaptureService.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.inkapplications.ack.android.capture.service - -import android.app.Service -import android.content.Intent -import android.os.IBinder -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.capture.CaptureEvents -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi -import kotlinx.coroutines.* -import javax.inject.Inject - -/** - * Service that runs in the background to collect and transmit packets. - */ -@AndroidEntryPoint -open class BackgroundCaptureService: Service() { - private lateinit var runScope: CoroutineScope - - @Inject - lateinit var captureEvents: CaptureEvents - - @Inject - lateinit var captureServiceNotifications: CaptureServiceNotifications - private val notificationId: Int = 89 - private val notificationTitle: String get() = getString(R.string.capture_service_notification_title) - - override fun onBind(intent: Intent?): IBinder? = null - - override fun onCreate() { - super.onCreate() - Kimchi.info("onCreate BackgroundCaptureService") - Kimchi.trackEvent("background_capture_start") - runScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) - } - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - val notification = captureServiceNotifications.createServiceNotification(this, notificationTitle) - startForeground(notificationId, notification) - runScope.launch { - captureEvents.connectDriver() - captureEvents.locationTransmitLoop() - stopSelf() - } - - return super.onStartCommand(intent, flags, startId) - } - - override fun onDestroy() { - Kimchi.trackEvent("background_capture_destroy") - runScope.cancel() - super.onDestroy() - } -} - -class BackgroundCaptureServiceAudio: BackgroundCaptureService() diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/service/CaptureServiceNotifications.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/service/CaptureServiceNotifications.kt deleted file mode 100644 index 141bcb16..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/service/CaptureServiceNotifications.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.inkapplications.ack.android.capture.service - -import android.app.* -import android.app.PendingIntent.FLAG_IMMUTABLE -import android.content.Context -import android.content.Intent -import android.os.Build -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.capture.CaptureActivity -import com.inkapplications.ack.android.startup.ApplicationInitializer -import com.inkapplications.android.extensions.notificationBuilder -import kimchi.logger.KimchiLogger -import javax.inject.Inject - -private const val CHANNEL_ID = "ack.capture.services" - -/** - * Creates notification channels for use with the capture service at app start. - */ -class CaptureServiceNotifications @Inject constructor( - private val notificationManager: NotificationManager, - private val logger: KimchiLogger, -): ApplicationInitializer { - override suspend fun initialize(application: Application) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - logger.debug("Skipping notification channel setup") - return - } - logger.debug("Creating Capture Service Notification Channel") - val channel = NotificationChannel(CHANNEL_ID, application.getString(R.string.capture_service_channel_name), NotificationManager.IMPORTANCE_LOW) - channel.description = application.getString(R.string.capture_service_channel_description) - notificationManager.createNotificationChannel(channel) - } - - fun createServiceNotification(context: Context, title: String): Notification { - val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) FLAG_IMMUTABLE else 0 - val pendingIntent: PendingIntent = Intent(context, CaptureActivity::class.java).let { notificationIntent -> - PendingIntent.getActivity(context, 0, notificationIntent, flags) - } - - return context.notificationBuilder(CHANNEL_ID) - .setContentTitle(title) - .setSmallIcon(R.drawable.capture_service_notification_icon) - .setContentIntent(pendingIntent) - .build() - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/connection/ConnectionModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/connection/ConnectionModule.kt deleted file mode 100644 index c98dca9d..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/connection/ConnectionModule.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.android.connection - -import com.inkapplications.ack.android.settings.SettingsProvider -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.IntoSet - -@Module -@InstallIn(SingletonComponent::class) -abstract class ConnectionModule { - @Binds - @IntoSet - abstract fun settings(settings: ConnectionSettings): SettingsProvider -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/connection/ConnectionSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/connection/ConnectionSettings.kt deleted file mode 100644 index b17d82ae..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/connection/ConnectionSettings.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.inkapplications.ack.android.connection - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.input.IntegerValidator -import com.inkapplications.ack.android.input.RegexValidator -import com.inkapplications.ack.android.input.enumInputValidator -import com.inkapplications.ack.android.settings.* -import com.inkapplications.ack.android.settings.transformer.* -import com.inkapplications.ack.data.DEFAULT_CONNECTION_PORT -import com.inkapplications.ack.data.DEFAULT_CONNECTION_SERVER -import com.inkapplications.ack.data.DEFAULT_SEARCH_RADIUS_MILES -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import inkapplications.spondee.measure.us.miles -import javax.inject.Inject - -@Reusable -class ConnectionSettings @Inject constructor( - resources: StringResources, -): SettingsProvider { - private val callsignRegex = Regex("^[0-9a-zA-Z]{1,3}\\d[0-9a-zA-Z]{0,4}[a-zA-Z](?:-[a-zA-Z0-9]{1,2})?\$") - private val hostnameRegex = Regex("^(?=.{1,255}\$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\\.?\$") - - val address = StringBackedSetting( - key = "connection.address", - name = resources.getString(R.string.connection_setting_address_name), - categoryName = resources.getString(R.string.connection_setting_category_name), - defaultData = null, - visibility = SettingVisibility.Dev, - storageTransformer = SentinelOptionalTransformer( - sentinelValue = "", - delegate = StationAddressTransformer + TrimmingTransformer, - ), - inputValidator = RegexValidator( - regex = callsignRegex, - error = resources.getString(R.string.connection_setting_address_invalid), - allowEmpty = true, - ), - ) - - val passcode = IntBackedSetting( - key = "connection.passcode", - name = resources.getString(R.string.connection_setting_passcode_name), - categoryName = resources.getString(R.string.connection_setting_category_name), - defaultData = null, - visibility = SettingVisibility.Dev, - storageTransformer = SentinelOptionalTransformer( - sentinelValue = -1, - delegate = object: Transformer { - override fun toStorage(data: Passcode): Int = data.value - override fun toData(storage: Int): Passcode = storage.let(::Passcode) - }, - ), - inputValidator = IntegerValidator( - error = resources.getString(R.string.connection_setting_passcode_invalid), - allowSentinel = -1, - ), - fieldTransformer = OptionalIntTransformer(), - ) - - val server = StringSetting( - key = "connection.server", - name = resources.getString(R.string.connection_setting_server_name), - categoryName = resources.getString(R.string.connection_setting_category_name), - defaultValue = DEFAULT_CONNECTION_SERVER, - visibility = SettingVisibility.Advanced, - validator = RegexValidator( - regex = hostnameRegex, - error = resources.getString(R.string.connection_setting_server_invalid), - ), - ) - val port = IntSetting( - key = "connection.port", - name = resources.getString(R.string.connection_setting_port_name), - categoryName = resources.getString(R.string.connection_setting_category_name), - defaultValue = DEFAULT_CONNECTION_PORT, - visibility = SettingVisibility.Advanced, - validator = IntegerValidator( - error = resources.getString(R.string.connection_setting_port_invalid), - zeroInclusive = false, - ), - ) - - val radius = IntBackedSetting( - key = "connection.radius", - name = resources.getString(R.string.connection_setting_radius_name), - categoryName = resources.getString(R.string.connection_setting_category_name), - defaultData = DEFAULT_SEARCH_RADIUS_MILES.miles, - storageTransformer = MileTransformer, - inputValidator = IntegerValidator( - error = resources.getString(R.string.connection_setting_radius_invalid), - zeroInclusive = false, - ), - ) - - val driver = StringBackedSetting( - key = "connection.driver", - categoryName = resources.getString(R.string.connection_setting_category_name), - defaultData = DriverSelection.Audio, - name = resources.getString(R.string.transmit_settings_driver), - visibility = SettingVisibility.Dev, - storageTransformer = enumTransformer(), - inputValidator = enumInputValidator( - error = resources.getString( - R.string.settings_validation_not_in_set, - DriverSelection.values().joinToString { it.name }, - ), - ), - ) - - override val settings: List = listOf( - address, - passcode, - server, - port, - radius, - driver, - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/connection/DriverSelection.kt b/android-application/src/main/java/com/inkapplications/ack/android/connection/DriverSelection.kt deleted file mode 100644 index b54b0e71..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/connection/DriverSelection.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.inkapplications.ack.android.connection - -import androidx.annotation.StringRes -import com.inkapplications.ack.android.R - -/** - * Represents the user-selected source of APRS data. - */ -enum class DriverSelection { - Audio, - Internet, - Tnc, -} - -/** - * Resource ID of the user-readable name for the selected driver. - */ -val DriverSelection.readableName get(): @StringRes Int = when (this) { - DriverSelection.Audio -> R.string.capture_driver_selection_audio - DriverSelection.Internet -> R.string.capture_driver_selection_internet - DriverSelection.Tnc -> R.string.capture_driver_selection_tnc -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseInitializer.kt b/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseInitializer.kt deleted file mode 100644 index bdf5c6d6..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseInitializer.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.inkapplications.ack.android.firebase - -import android.app.Application -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.inkapplications.ack.android.settings.SettingsProvider -import com.inkapplications.ack.android.startup.ApplicationInitializer -import dagger.Reusable -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.suspendCancellableCoroutine -import javax.inject.Inject -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException - -@Reusable -class FirebaseInitializer @Inject constructor( - private val settingsProvider: SettingsProvider, - private val logger: KimchiLogger -): ApplicationInitializer { - override suspend fun initialize(application: Application) { - logger.trace("Initializing Firebase.") - suspendCancellableCoroutine { continuation -> - settingsProvider.settings - .map { it.key to it.defaultValue } - .toMap() - .onEach { logger.debug("Initializing <${it.key}> with default <${it.value}>") } - .run(Firebase.remoteConfig::setDefaultsAsync) - .addOnSuccessListener { continuation.resume(Unit) } - .addOnFailureListener { continuation.resumeWithException(it) } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseModule.kt deleted file mode 100644 index bb0b7a56..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.inkapplications.ack.android.firebase - -import com.inkapplications.ack.android.BuildConfig -import com.inkapplications.ack.android.startup.ApplicationInitializer -import com.inkapplications.ack.android.startup.NoOpInitializer -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.IntoSet - -@Module -@InstallIn(SingletonComponent::class) -class FirebaseModule { - @Provides - @IntoSet - fun initializer(firebaseInitializer: FirebaseInitializer): ApplicationInitializer { - if (BuildConfig.USE_GOOGLE_SERVICES) { - return firebaseInitializer - } - return NoOpInitializer - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseSettings.kt deleted file mode 100644 index 7ec04ad2..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/firebase/FirebaseSettings.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.inkapplications.ack.android.firebase - -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.inkapplications.ack.android.settings.BooleanSetting -import com.inkapplications.ack.android.settings.IntSetting -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.StringSetting -import dagger.Reusable -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf -import javax.inject.Inject - -@Reusable -class FirebaseSettings @Inject constructor(): SettingsReadAccess { - override fun observeStringState(setting: StringSetting): Flow { - return flowOf(Firebase.remoteConfig.getString(setting.key)) - } - - override fun observeIntState(setting: IntSetting): Flow { - return flowOf(Firebase.remoteConfig.getLong(setting.key).toInt()) - } - - override fun observeBooleanState(setting: BooleanSetting): Flow { - return flowOf(Firebase.remoteConfig.getBoolean(setting.key)) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/ConvertibleOptionalIntValidator.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/ConvertibleOptionalIntValidator.kt deleted file mode 100644 index 90f635b6..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/ConvertibleOptionalIntValidator.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.inkapplications.ack.android.input - -import com.inkapplications.ack.android.R -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import javax.inject.Inject - -/** - * Ensures that a string can be successfully converted to an integer, or is blank. - */ -@Reusable -class ConvertibleOptionalIntValidator @Inject constructor( - private val stringResources: StringResources, -) : Validator { - override fun validate(input: String): ValidationResult { - val result = runCatching { input.toInt() } - return when { - input.isBlank() -> ValidationResult.Valid - result.isSuccess -> ValidationResult.Valid - else -> ValidationResult.Error( - stringResources.getString(R.string.prompt_int_invalid_error) - ) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/EnumValidator.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/EnumValidator.kt deleted file mode 100644 index 56c1beea..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/EnumValidator.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.input - -/** - * Validates an input string, asserting that its value is a valid enum name. - */ -inline fun > enumInputValidator( - error: String, -): Validator { - return object: Validator { - override fun validate(input: String): ValidationResult { - return if (input in enumValues().map { it.name }) { - ValidationResult.Valid - } else { - ValidationResult.Error(error) - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/IntPrompt.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/IntPrompt.kt deleted file mode 100644 index 4de129e7..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/IntPrompt.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.inkapplications.ack.android.input - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.window.Dialog -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.theme.AckTheme - -/** - * Displays a dialog asking the user for a number input. - * - * @param title The dialog's title text. - * @param value The current value of the field. - * @param validator Asserts that the input value is valid. - * @param onDismiss Invoked when the user cancels or taps-out of the dialog. - * @param onSubmit Invoked with the entered validated value when the user saves. - */ -@Composable -fun IntPrompt( - title: String, - value: Int, - validator: Validator, - onDismiss: () -> Unit, - onSubmit: (Int) -> Unit, -) { - val inputState = remember { mutableStateOf(value.toString()) } - val errorState = remember { mutableStateOf(null) } - val inputInvalid = stringResource(R.string.prompt_int_invalid_error) - Dialog( - onDismissRequest = onDismiss, - ) { - Surface(shape = AckTheme.shapes.corners) { - Column( - modifier = Modifier.padding(AckTheme.spacing.gutter), - ) { - Text(title, style = AckTheme.typography.h2) - TextField( - value = inputState.value, - onValueChange = { inputState.value = it }, - isError = errorState.value != null, - singleLine = true, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - modifier = Modifier.padding(top = AckTheme.spacing.item).fillMaxWidth(), - ) - Text( - text = errorState.value.orEmpty(), - style = AckTheme.typography.errorCaption, - ) - - Row( - horizontalArrangement = Arrangement.End, - modifier = Modifier.fillMaxWidth().padding(top = AckTheme.spacing.item), - ) { - TextButton( - onClick = onDismiss, - colors = ButtonDefaults.textButtonColors( - contentColor = AckTheme.colors.foreground, - ), - modifier = Modifier.padding(end = AckTheme.spacing.item), - ) { - Text(stringResource(R.string.prompt_cancel)) - } - TextButton( - onClick = { - val input = inputState.value.trim().toIntOrNull() - if (input == null) { - errorState.value = inputInvalid - } else { - when (val result = validator.validate(input)) { - is ValidationResult.Error -> errorState.value = result.message - ValidationResult.Valid -> onSubmit(input) - } - } - }, - ) { - Text(stringResource(R.string.prompt_save)) - } - } - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/IntegerValidator.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/IntegerValidator.kt deleted file mode 100644 index 5abedf0f..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/IntegerValidator.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.inkapplications.ack.android.input - -/** - * Validates common constraints on positive integer values. - * - * @param error The error message to return if the regex does not match. - * @param requirePositive Whether the value must be greater than zero. - * @param zeroInclusive Whether the value can be zero. - * @param sentinelValue An arbitrary single value to consider valid, when using sentinel values. - */ -class IntegerValidator( - private val error: String, - private val zeroInclusive: Boolean = true, - private val allowSentinel: Int? = null, -): Validator { - override fun validate(input: Int): ValidationResult { - return when { - allowSentinel != null && input == allowSentinel -> ValidationResult.Valid - input < 0 -> ValidationResult.Error(error) - !zeroInclusive && input == 0 -> ValidationResult.Error(error) - else -> ValidationResult.Valid - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/MaxLengthValidator.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/MaxLengthValidator.kt deleted file mode 100644 index 0bea37d4..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/MaxLengthValidator.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.inkapplications.ack.android.input - -class MaxLengthValidator( - private val error: String, - private val maxLength: Int, -): Validator { - override fun validate(input: String): ValidationResult { - return if (input.length <= maxLength) { - ValidationResult.Valid - } else { - ValidationResult.Error(error) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/MinLengthValidator.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/MinLengthValidator.kt deleted file mode 100644 index 48f9ddc8..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/MinLengthValidator.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.inkapplications.ack.android.input - -class MinLengthValidator( - private val error: String, - private val minLength: Int, -): Validator { - override fun validate(input: String): ValidationResult { - return if (input.length >= minLength) { - ValidationResult.Valid - } else { - ValidationResult.Error(error) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/NoValidation.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/NoValidation.kt deleted file mode 100644 index 06a2bd96..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/NoValidation.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.inkapplications.ack.android.input - -/** - * Validator that always passes regardless of the input - */ -object NoValidation: Validator { - override fun validate(input: Any?) = ValidationResult.Valid -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/RegexValidator.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/RegexValidator.kt deleted file mode 100644 index 6999ed9d..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/RegexValidator.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.inkapplications.ack.android.input - -/** - * Validator that checks if a string matches a regex. - * - * @param regex The regex to consider valid input. - * @param error The error message to return if the regex does not match. - */ -class RegexValidator( - private val regex: Regex, - private val error: String, - private val trim: Boolean = true, - private val allowEmpty: Boolean = false, -): Validator { - override fun validate(input: String): ValidationResult { - if (input.isBlank() && allowEmpty) return ValidationResult.Valid - return if (regex.matches(input.let { if(trim) it.trim() else it })) { - ValidationResult.Valid - } else { - ValidationResult.Error(error) - } - } -} - diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/StringPrompt.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/StringPrompt.kt deleted file mode 100644 index d7cbe164..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/StringPrompt.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.inkapplications.ack.android.input - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.window.Dialog -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.theme.AckTheme - -/** - * Displays a dialog asking the user for an arbitrary single-line string input. - * - * @param title The dialog's title text. - * @param value The current value of the field. - * @param validator Asserts that the input value is valid. - * @param onDismiss Invoked when the user cancels or taps-out of the dialog. - * @param onSubmit Invoked with the entered validated value when the user saves. - */ -@Composable -fun StringPrompt( - title: String, - value: String, - validator: Validator, - onDismiss: () -> Unit, - onSubmit: (String) -> Unit, -) { - val inputState = remember { mutableStateOf(value) } - val errorState = remember { mutableStateOf(null) } - Dialog( - onDismissRequest = onDismiss, - ) { - Surface(shape = AckTheme.shapes.corners) { - Column( - modifier = Modifier.padding(AckTheme.spacing.gutter), - ) { - Text(title, style = AckTheme.typography.h2) - TextField( - value = inputState.value, - onValueChange = { inputState.value = it }, - isError = errorState.value != null, - singleLine = true, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii), - modifier = Modifier.padding(top = AckTheme.spacing.item).fillMaxWidth(), - ) - Text( - text = errorState.value.orEmpty(), - style = AckTheme.typography.errorCaption, - ) - - Row( - horizontalArrangement = Arrangement.End, - modifier = Modifier.fillMaxWidth().padding(top = AckTheme.spacing.item), - ) { - TextButton( - onClick = onDismiss, - colors = ButtonDefaults.textButtonColors( - contentColor = AckTheme.colors.foreground, - ), - modifier = Modifier.padding(end = AckTheme.spacing.item), - ) { - Text(stringResource(R.string.prompt_cancel)) - } - TextButton( - onClick = { - val input = inputState.value.trim() - when (val result = validator.validate(input)) { - is ValidationResult.Error -> errorState.value = result.message - ValidationResult.Valid -> onSubmit(input) - } - }, - ) { - Text(stringResource(R.string.prompt_save)) - } - } - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/ValidationResult.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/ValidationResult.kt deleted file mode 100644 index 65efdbe6..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/ValidationResult.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.input - -/** - * Results of a [Validator]'s validation check. - */ -sealed interface ValidationResult { - /** - * Indicates that the given input was valid. - */ - object Valid: ValidationResult - - /** - * Indicates that the given input was not valid, and explains why with a [message] - * - * @param message A user-readable message to explain why the input was not valid. - */ - data class Error(val message: String): ValidationResult -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/input/Validator.kt b/android-application/src/main/java/com/inkapplications/ack/android/input/Validator.kt deleted file mode 100644 index b97920f3..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/input/Validator.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.inkapplications.ack.android.input - -/** - * Checks if an input type is allowable. - */ -interface Validator { - /** - * Check if the input is allowed, returning a specific result. - */ - fun validate(input: T): ValidationResult -} - -private class CompositeValidator( - val validators: List>, -): Validator { - override fun validate(input: T): ValidationResult { - return validators - .map { it.validate(input) } - .firstOrNull { it is ValidationResult.Error } - ?: ValidationResult.Valid - } -} - -operator fun Validator.plus(other: Validator): Validator { - val validators = when (this) { - is CompositeValidator -> this.validators + other - else -> listOf(this, other) - } - - return CompositeValidator(validators) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/locale/LocaleModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/locale/LocaleModule.kt deleted file mode 100644 index a3545787..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/locale/LocaleModule.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.android.locale - -import com.inkapplications.ack.android.settings.SettingsProvider -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.IntoSet - -@Module -@InstallIn(SingletonComponent::class) -abstract class LocaleModule { - @Binds - @IntoSet - abstract fun settings(settings: LocaleSettings): SettingsProvider -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/locale/LocaleSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/locale/LocaleSettings.kt deleted file mode 100644 index feb0472b..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/locale/LocaleSettings.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.inkapplications.ack.android.locale - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.settings.BooleanSetting -import com.inkapplications.ack.android.settings.Setting -import com.inkapplications.ack.android.settings.SettingsProvider -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import javax.inject.Inject - -@Reusable -class LocaleSettings @Inject constructor( - stringResources: StringResources -): SettingsProvider { - val preferMetric = BooleanSetting( - key = "locale.metric", - name = stringResources.getString(R.string.locale_setting_metric_name), - categoryName = stringResources.getString(R.string.locale_setting_category), - defaultValue = false - ) - - - override val settings: List = listOf(preferMetric) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/locale/Units.kt b/android-application/src/main/java/com/inkapplications/ack/android/locale/Units.kt deleted file mode 100644 index d1598c2b..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/locale/Units.kt +++ /dev/null @@ -1,37 +0,0 @@ -@file:OptIn(SimpleNumberFormats::class) - -package com.inkapplications.ack.android.locale - -import inkapplications.spondee.format.SimpleNumberFormats -import inkapplications.spondee.format.formatDecimal -import inkapplications.spondee.measure.Length -import inkapplications.spondee.measure.Speed -import inkapplications.spondee.measure.Temperature -import inkapplications.spondee.measure.metric.toCelsius -import inkapplications.spondee.measure.metric.toKilometersPerHourValue -import inkapplications.spondee.measure.metric.toMetersPerSecondValue -import inkapplications.spondee.measure.us.toFahrenheit -import inkapplications.spondee.measure.us.toFeet -import inkapplications.spondee.measure.us.toMiles -import inkapplications.spondee.measure.us.toMilesPerHourValue -import inkapplications.spondee.structure.Kilo -import inkapplications.spondee.structure.compareTo -import inkapplications.spondee.structure.format - -fun Length.format(metric: Boolean) = when { - metric && toMeters() > 1000.0 -> toMeters().format(Kilo) - metric -> toMeters().format() - toFeet() > 1000 -> toMiles().format() - else -> toFeet().format() -} - -fun Speed.format(metric: Boolean) = when { - metric && toMetersPerSecondValue() >= 1000 -> "${toKilometersPerHourValue().formatDecimal()}km/h" - metric -> "${toMetersPerSecondValue().formatDecimal()}m/s" - else -> "${toMilesPerHourValue().formatDecimal()}mph" -} - -fun Temperature.format(metric: Boolean) = when { - metric -> toCelsius().format(decimals = 1) - else -> toFahrenheit().format() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/AprsLogItem.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/AprsLogItem.kt deleted file mode 100644 index 85c3df70..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/AprsLogItem.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.inkapplications.ack.android.log - -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Card -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import com.inkapplications.ack.android.capture.log.AprsSymbol -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun AprsLogItem( - log: LogItemViewState, - onClick: (LogItemViewState) -> Unit, - border: Boolean = false, -) { - Card( - border = BorderStroke(1.dp, AckTheme.colors.accent).takeIf { border }, - modifier = Modifier - .padding( - vertical = AckTheme.spacing.singleItem, - horizontal = AckTheme.spacing.gutter - ) - .fillMaxWidth() - .clickable { onClick(log) } - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(AckTheme.spacing.content) - ) { - AprsSymbol(log.symbol) - - Column( - modifier = Modifier.padding(start = AckTheme.spacing.content) - ) { - Text( - text = log.origin, - style = AckTheme.typography.h3, - ) - Text( - text = log.comment, - style = AckTheme.typography.body, - ) - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/CombinedLogItemViewStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/CombinedLogItemViewStateFactory.kt deleted file mode 100644 index 25b99865..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/CombinedLogItemViewStateFactory.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.inkapplications.ack.android.log - -import com.inkapplications.ack.android.locale.format -import com.inkapplications.ack.android.symbol.SymbolFactory -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.capabilities.Mapable -import dagger.Reusable -import javax.inject.Inject - -@Reusable -class CombinedLogItemViewStateFactory @Inject constructor( - private val symbolFactory: SymbolFactory -): LogItemViewStateFactory { - override fun create(packets: List, metric: Boolean): List { - return packets.map { create(it.id, it.parsed, metric) } - } - - override fun create( - id: CaptureId, - packet: AprsPacket, - metric: Boolean, - ): LogItemViewState { - return LogItemViewState( - id = id, - source = packet.route.source.callsign, - origin = packet.route.source.toString(), - comment = when (val data = packet.data) { - is PacketData.Position -> "Position${data.comment.append()}" - is PacketData.Weather -> "Weather${data.temperature?.format(metric).append()}" - is PacketData.ObjectReport -> "Object: ${data.name}${data.comment.append(" - ")}" - is PacketData.ItemReport -> "Item: ${data.name}${data.comment.append(" - ")}" - is PacketData.Message -> "[${data.addressee}] ${data.message}${data.messageNumber?.let { " ($it)" }.orEmpty()}" - is PacketData.TelemetryReport -> "Telemetry${data.comment.append()}" - is PacketData.StatusReport -> "Status${data.status.append()}" - is PacketData.CapabilityReport -> "Capability Report" - is PacketData.Unknown -> "Unknown data" - }, - symbol = when (val data = packet.data) { - is Mapable -> data.symbol?.let(symbolFactory::createSymbol) - else -> symbolFactory.defaultSymbol - } - ) - } - - private fun String?.append(separator: String = ": ") = this.takeIfNotEmpty()?.let { "${separator}$it" }.orEmpty() - private fun String?.takeIfNotEmpty() = this?.takeIf { it.isNotBlank() } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/LogEvents.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/LogEvents.kt deleted file mode 100644 index c2b52916..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/LogEvents.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.inkapplications.ack.android.log - -import com.inkapplications.ack.android.locale.LocaleSettings -import com.inkapplications.ack.android.log.details.LogDetailData -import com.inkapplications.ack.android.log.index.LogIndexData -import com.inkapplications.ack.android.map.MarkerViewStateFactory -import com.inkapplications.ack.android.maps.CameraPositionDefaults -import com.inkapplications.ack.android.maps.MapCameraPosition -import com.inkapplications.ack.android.maps.MapViewModel -import com.inkapplications.ack.android.maps.ZoomLevels -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.observeBoolean -import com.inkapplications.ack.android.station.StationSettings -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.data.PacketStorage -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.capabilities.Mapable -import com.inkapplications.coroutines.combinePair -import com.inkapplications.coroutines.filterItems -import dagger.Reusable -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.flow.* -import javax.inject.Inject - -@Reusable -class LogEvents @Inject constructor( - private val packetStorage: PacketStorage, - private val markerViewStateFactory: MarkerViewStateFactory, - private val settings: SettingsReadAccess, - private val localeSettings: LocaleSettings, - private val stationSettings: StationSettings, - logSettings: LogSettings, - private val logger: KimchiLogger, -) { - val logIndex = settings.observeBoolean(localeSettings.preferMetric) - .combinePair(settings.observeBoolean(logSettings.filterUnknown)) - .flatMapLatest { (metric, filterUnknown) -> - packetStorage.findRecent(500) - .filterItems { !filterUnknown || it.parsed.data !is PacketData.Unknown } - .map { LogIndexData(metric, it) } - } - - fun stateEvents(id: CaptureId): Flow { - logger.trace("Observing packet: $id") - return packetStorage.findById(id) - .filterNotNull() - .combine(settings.observeBoolean(localeSettings.preferMetric)) { packet, metric -> - LogDetailData( - packet = packet, - metric = metric, - ) - } - .combine(settings.observeBoolean(stationSettings.showDebugData)) { data, debugData -> - data.copy(debug = debugData) - } - } - - fun mapState(id: CaptureId): Flow { - return packetStorage.findById(id) - .filterNotNull() - .map { packet -> - MapViewModel( - markers = markerViewStateFactory.create(packet)?.let { listOf(it) }.orEmpty(), - cameraPosition = (packet.parsed.data as? Mapable)?.coordinates - ?.let { MapCameraPosition(it, ZoomLevels.ROADS) } - ?: CameraPositionDefaults.unknownLocation, - ) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/LogItemViewState.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/LogItemViewState.kt deleted file mode 100644 index 78ef1f46..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/LogItemViewState.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.inkapplications.ack.android.log - -import android.graphics.Bitmap -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.structures.station.Callsign - -data class LogItemViewState( - val id: CaptureId, - val source: Callsign, - val origin: String, - val comment: String, - val symbol: Bitmap? -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/LogItemViewStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/LogItemViewStateFactory.kt deleted file mode 100644 index 13c5ab5f..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/LogItemViewStateFactory.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.log - -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.structures.AprsPacket - -interface LogItemViewStateFactory { - fun create( - id: CaptureId, - packet: AprsPacket, - metric: Boolean, - ): LogItemViewState - - fun create( - packets: List, - metric: Boolean, - ): List -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/LogModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/LogModule.kt deleted file mode 100644 index 8ecb7986..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/LogModule.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.inkapplications.ack.android.log - -import com.inkapplications.ack.android.settings.SettingsProvider -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.IntoSet - -@Module -@InstallIn(SingletonComponent::class) -interface LogModule { - @Binds - @IntoSet - fun settings(settings: LogSettings): SettingsProvider - - @Binds - fun logFactory(factory: CombinedLogItemViewStateFactory): LogItemViewStateFactory -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/LogSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/LogSettings.kt deleted file mode 100644 index 5f0bba02..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/LogSettings.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.inkapplications.ack.android.log - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.settings.BooleanSetting -import com.inkapplications.ack.android.settings.Setting -import com.inkapplications.ack.android.settings.SettingsProvider -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import javax.inject.Inject - -@Reusable -class LogSettings @Inject constructor( - resources: StringResources -): SettingsProvider { - val filterUnknown = BooleanSetting( - key = "log.filter.unknown", - name = resources.getString(R.string.log_setting_filter_unknown), - categoryName = resources.getString(R.string.log_setting_category), - defaultValue = false, - ) - - override val settings: List = listOf(filterUnknown) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/SummaryFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/SummaryFactory.kt deleted file mode 100644 index 5e924802..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/SummaryFactory.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.inkapplications.ack.android.log - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.locale.format -import com.inkapplications.ack.structures.WindData -import com.inkapplications.android.extensions.StringResources -import inkapplications.spondee.spatial.toDegrees -import inkapplications.spondee.structure.format -import javax.inject.Inject - -/** - * Create readable sentence summaries from packet data. - */ -class SummaryFactory @Inject constructor( - private val stringResources: StringResources, -) { - /** - * Create a readable sentence out of various wind data, if available. - */ - fun createWindSummary(data: WindData, metric: Boolean): String? { - val direction = data.direction?.toDegrees()?.format() - val speed = data.speed?.format(metric) - val gust = data.gust?.format(metric) - - return when { - direction != null && speed != null && gust != null -> stringResources.getString(R.string.station_wind_format_full, direction, speed, gust) - direction != null && speed != null -> stringResources.getString(R.string.station_wind_format_wind_only, direction, speed) - direction != null -> stringResources.getString(R.string.station_wind_format_direction_only, direction) - speed != null -> stringResources.getString(R.string.station_wind_format_speed_only, speed) - else -> null - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailData.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailData.kt deleted file mode 100644 index b8f4474c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailData.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.inkapplications.ack.android.log.details - -import com.inkapplications.ack.data.CapturedPacket - -/** - * Raw Data required to render the Log Details UI. - */ -data class LogDetailData( - /** - * The packet that is being displayed - */ - val packet: CapturedPacket, - - /** - * Whether to display stats in metric format. - */ - val metric: Boolean = false, - - /** - * Whether debug information should be visible. - */ - val debug: Boolean = false, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsActivity.kt deleted file mode 100644 index dcfd67f2..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsActivity.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.inkapplications.ack.android.log.details - -import android.app.Activity -import android.os.Bundle -import androidx.activity.compose.setContent -import com.inkapplications.ack.android.station.startStationActivity -import com.inkapplications.ack.android.trackNavigation -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.android.extensions.ExtendedActivity -import com.inkapplications.android.startActivity -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi - -const val EXTRA_LOG_ID = "aprs.station.extra.id" - -/** - * Shows information about a particular packet received. - */ -@AndroidEntryPoint -class LogDetailsActivity: ExtendedActivity(), LogDetailsController { - private val id get() = CaptureId(intent.getLongExtra(EXTRA_LOG_ID, -1)) - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - Kimchi.trackScreen("log_details") - - setContent { - AckScreen { - LogDetailsScreen( - controller = this, - ) - } - } - } - - override fun onMapItemClicked(id: CaptureId?) { - Kimchi.trackEvent("log_details_map_item_click") - Kimchi.debug("Map Item Clicked: No-Op") - } - - override fun onViewStationDetails(station: Callsign) { - Kimchi.trackEvent("log_details_view_station") - startStationActivity(station) - } -} - -/** - * Start an Activity displaying the details for the specified packet. - */ -fun Activity.startLogInspectActivity(packetId: CaptureId) { - Kimchi.trackNavigation("log_inspect") - startActivity(LogDetailsActivity::class) { - putExtra(EXTRA_LOG_ID, packetId.value) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsController.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsController.kt deleted file mode 100644 index 33a3dcdd..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsController.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.inkapplications.ack.android.log.details - -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.structures.station.Callsign - -/** - * Actions available on the log details screen - */ -interface LogDetailsController { - /** - * Invoked when the user taps the up navigation at the top of the screen. - */ - fun onBackPressed() - - /** - * Invoked when the user clicks on the station details button. - */ - fun onViewStationDetails(station: Callsign) - - /** - * Invoked when the user clicks on a map marker. - * - * @param id The id of the map marker that was clicked. - */ - fun onMapItemClicked(id: CaptureId?) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsScreen.kt deleted file mode 100644 index 3bcf3304..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsScreen.kt +++ /dev/null @@ -1,163 +0,0 @@ -package com.inkapplications.ack.android.log.details - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Card -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.map.MarkerMap -import com.inkapplications.ack.android.ui.IconRow -import com.inkapplications.ack.android.ui.NavigationRow -import com.inkapplications.ack.android.ui.TelemetryTable -import com.inkapplications.ack.android.ui.theme.AckTheme - -/** - * Detailed display of the data for a single logged packet. - */ -@Composable -fun LogDetailsScreen( - viewModel: LogDetailsViewModel = hiltViewModel(), - controller: LogDetailsController, -) { - val viewState = viewModel.detailsState.collectAsState().value - - when (viewState) { - is LogDetailsState.Initial -> {} - is LogDetailsState.Loaded -> Details(viewState, controller) - } -} - -@Composable -private fun Details( - viewState: LogDetailsState.Loaded, - controller: LogDetailsController, -) { - Column( - modifier = Modifier.verticalScroll(rememberScrollState()), - ) { - if (viewState.mapable) { - Column { - Box { - MarkerMap( - viewModel = viewState.mapViewState, - onMapItemClicked = controller::onMapItemClicked, - interactive = false, - modifier = Modifier.aspectRatio(16f / 9f), - ) - Box( - modifier = Modifier - .padding(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()) - ) { - IconButton( - onClick = controller::onBackPressed - ) { - Icon(Icons.Default.ArrowBack, stringResource(R.string.navigate_up)) - } - } - } - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(top = AckTheme.spacing.gutter) - ) { - Text( - viewState.name, - style = AckTheme.typography.h1, - modifier = Modifier.padding( - start = AckTheme.spacing.gutter, - ), - ) - IconButton( - onClick = { controller.onViewStationDetails(viewState.callsign) }, - ) { - Icon(Icons.Default.Info, stringResource(R.string.log_details_title)) - } - } - } - } else { - Box( - Modifier - .padding( - top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), - ) - .padding( - start = AckTheme.spacing.gutter, - top = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - ) - ) { - NavigationRow( - title = { - Text( - viewState.name, - style = AckTheme.typography.h1, - modifier = Modifier.padding( - start = AckTheme.spacing.gutter, - ), - ) - IconButton( - onClick = { controller.onViewStationDetails(viewState.callsign) }, - ) { - Icon(Icons.Default.Info, stringResource(R.string.log_details_title)) - } - }, - onBackPressed = controller::onBackPressed - ) - } - } - Column( - modifier = Modifier - .padding( - bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() - ) - .padding( - top = AckTheme.spacing.content, - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - bottom = AckTheme.spacing.gutter, - ), - ) { - IconRow( - icon = viewState.receiveIcon, - viewState.timestamp, - ) - if (viewState.temperature != null) { - IconRow(Icons.Default.WbSunny, viewState.temperature) - } - if (viewState.wind != null) { - IconRow(Icons.Default.Air, viewState.wind) - } - if (viewState.altitude != null) { - IconRow(Icons.Default.Terrain, viewState.altitude) - } - if (viewState.comment != null) { - IconRow(Icons.Default.Comment, viewState.comment) - } - if (viewState.telemetryValues != null) { - TelemetryTable(viewState.telemetryValues, viewState.telemetrySequence) - } - if (viewState.rawSource != null) { - Card(modifier = Modifier - .fillMaxWidth() - .padding(vertical = AckTheme.spacing.content)) { - Column(modifier = Modifier.padding(AckTheme.spacing.content)) { - Text("Debug Info", style = AckTheme.typography.h2) - Text("Raw Data", style = AckTheme.typography.h3) - Text(viewState.rawSource, style = AckTheme.typography.caption) - Spacer(Modifier.height(AckTheme.spacing.content)) - } - } - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsState.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsState.kt deleted file mode 100644 index 8efcd062..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsState.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.inkapplications.ack.android.log.details - -import androidx.compose.ui.graphics.vector.ImageVector -import com.inkapplications.ack.android.maps.MapViewModel -import com.inkapplications.ack.structures.TelemetryValues -import com.inkapplications.ack.structures.station.Callsign - -/** - * Possible states for the Log Details Screen. - */ -sealed interface LogDetailsState { - /** - * Indicates that no data has been loaded yet. - */ - object Initial: LogDetailsState - - /** - * Log data for the packet. - */ - data class Loaded( - val callsign: Callsign, - val name: String, - val receiveIcon: ImageVector, - val receiveIconDescription: String, - val timestamp: String, - val mapable: Boolean, - val mapViewState: MapViewModel, - val comment: String? = null, - val temperature: String? = null, - val wind: String? = null, - val altitude: String? = null, - val rawSource: String? = null, - val telemetryValues: TelemetryValues? = null, - val telemetrySequence: String? = null, - ): LogDetailsState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsViewModel.kt deleted file mode 100644 index 366576fe..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsViewModel.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.inkapplications.ack.android.log.details - -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.log.LogEvents -import com.inkapplications.ack.data.CaptureId -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android viewmodel to load state for the log-details screen. - */ -@HiltViewModel -class LogDetailsViewModel @Inject constructor( - logEvents: LogEvents, - savedState: SavedStateHandle, - logDetailsViewStateFactory: LogDetailsViewStateFactory, -): ViewModel() { - private val logId = CaptureId(savedState.get(EXTRA_LOG_ID)!!) - - /** - * Detail state about the packet data. - */ - val detailsState = logEvents.stateEvents(logId) - .map { logDetailsViewStateFactory.create(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, LogDetailsState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsViewStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsViewStateFactory.kt deleted file mode 100644 index d044baa7..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsViewStateFactory.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.inkapplications.ack.android.log.details - -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Bluetooth -import androidx.compose.material.icons.filled.Cloud -import androidx.compose.material.icons.filled.SettingsInputAntenna -import androidx.compose.material.icons.filled.Storage -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.locale.format -import com.inkapplications.ack.android.log.SummaryFactory -import com.inkapplications.ack.android.maps.* -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.structures.PacketData.TelemetryReport -import com.inkapplications.ack.structures.PacketData.Weather -import com.inkapplications.ack.structures.capabilities.Commented -import com.inkapplications.ack.structures.capabilities.Mapable -import com.inkapplications.ack.structures.capabilities.Report -import com.inkapplications.android.extensions.StringResources -import com.inkapplications.android.extensions.ViewStateFactory -import com.inkapplications.android.extensions.format.DateTimeFormatter -import javax.inject.Inject - -/** - * Convert Log data into the model used to render the view for a specific packet. - */ -class LogDetailsViewStateFactory @Inject constructor( - private val summaryFactory: SummaryFactory, - private val markerViewStateFactory: ViewStateFactory, - private val timeFormatter: DateTimeFormatter, - private val stringResources: StringResources, -) { - fun create(data: LogDetailData): LogDetailsState.Loaded { - val packetData = data.packet.parsed.data - return LogDetailsState.Loaded( - callsign = data.packet.parsed.route.source.callsign, - name = data.packet.parsed.route.source.toString(), - timestamp = timeFormatter.formatTimestamp(data.packet.received) - .let { stringResources.getString(R.string.log_details_received_format, it) }, - comment = (packetData as? Commented)?.comment, - mapable = packetData is Mapable && packetData.coordinates != null, - mapViewState = MapViewModel( - markers = markerViewStateFactory.create(data.packet)?.let { listOf(it) }.orEmpty(), - cameraPosition = (data.packet.parsed.data as? Mapable)?.coordinates - ?.let { MapCameraPosition(it, ZoomLevels.ROADS) } - ?: CameraPositionDefaults.unknownLocation, - ), - temperature = (packetData as? Weather)?.temperature?.format(data.metric), - wind = (packetData as? Weather)?.let { summaryFactory.createWindSummary(it.windData, data.metric) }, - altitude = (packetData as? Report)?.altitude?.format(data.metric), - rawSource = data.packet.raw.decodeToString().takeIf { data.debug }, - telemetryValues = (packetData as? TelemetryReport)?.data, - telemetrySequence = (packetData as? TelemetryReport)?.sequenceId, - receiveIcon = when (data.packet.origin) { - PacketOrigin.AprsIs -> Icons.Default.Cloud - PacketOrigin.Ax25 -> Icons.Default.SettingsInputAntenna - PacketOrigin.Tnc -> Icons.Default.Bluetooth - PacketOrigin.Local -> Icons.Default.Storage - }, - receiveIconDescription = when (data.packet.origin) { - PacketOrigin.Ax25 -> stringResources.getString(R.string.log_icon_ax25) - PacketOrigin.AprsIs -> stringResources.getString(R.string.log_icon_aprs_is) - PacketOrigin.Tnc -> stringResources.getString(R.string.log_icon_tnc) - PacketOrigin.Local -> stringResources.getString(R.string.log_icon_local) - }, - ) - } -} - diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexController.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexController.kt deleted file mode 100644 index 3c46d1f3..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexController.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.inkapplications.ack.android.log.index - -import com.inkapplications.ack.android.log.LogItemViewState - -/** - * Actions invoked from the Log Index screen - */ -interface LogIndexController { - /** - * Invoked when the user clicks a log item in the log list. - */ - fun onLogListItemClick(item: LogItemViewState) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexData.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexData.kt deleted file mode 100644 index b87b0399..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexData.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.log.index - -import com.inkapplications.ack.data.CapturedPacket - -/** - * Data required to render the Log Index's view state. - */ -data class LogIndexData( - /** - * Whether units should be displayed in metric - */ - val metric: Boolean, - - /** - * List of packet data to be displayed in the index. - */ - val packets: List, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexScreen.kt deleted file mode 100644 index bca7adcb..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexScreen.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.inkapplications.ack.android.log.index - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Summarize -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.log.AprsLogItem -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -/** - * Screen that displays a scrolling list of log items. - */ -@Composable -fun LogIndexScreen( - viewModel: LogIndexViewModel = hiltViewModel(), - controller: LogIndexController, -) = AckScreen { - val state = viewModel.indexState.collectAsState() - - when (val currentState = state.value) { - LogIndexState.Initial -> {} - is LogIndexState.LogList -> LogList(currentState, controller) - is LogIndexState.Empty -> EmptyState() - } -} - -@Composable -private fun EmptyState() { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = Modifier - .padding(bottom = AckTheme.spacing.navigationProtection) - .fillMaxSize() - ) { - Icon( - imageVector = Icons.Default.Summarize, - contentDescription = null, - tint = AckTheme.colors.foregroundInactive, - modifier = Modifier.size(AckTheme.sizing.dispayIcon), - ) - Text(stringResource(R.string.log_index_empty)) - } -} - -@Composable -private fun LogList( - state: LogIndexState.LogList, - controller: LogIndexController, -) { - LazyColumn( - contentPadding = PaddingValues(top = AckTheme.spacing.gutter, bottom = AckTheme.spacing.navigationProtection) - ) { - val logItems = state.logs.map { LogListItem.Log(it) } - items(listOf(LogListItem.Header) + logItems) { item -> - when (item) { - LogListItem.Header -> Text( - text = "Packet Log", - style = AckTheme.typography.h1, - modifier = Modifier.padding( - top = AckTheme.spacing.gutter, - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - bottom = AckTheme.spacing.content, - ) - ) - is LogListItem.Log -> AprsLogItem(item.log, controller::onLogListItemClick) - } - - } - } -} - -private sealed interface LogListItem { - object Header: LogListItem - data class Log(val log: LogItemViewState): LogListItem -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexState.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexState.kt deleted file mode 100644 index 0777fac4..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexState.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.inkapplications.ack.android.log.index - -import com.inkapplications.ack.android.log.LogItemViewState - -/** - * Screen-state representation of the Log item screen. - */ -sealed interface LogIndexState { - /** - * Used when nothing has loaded yet. - */ - object Initial: LogIndexState - - /** - * Used when the list has been loaded, but there are no items to display. - */ - object Empty: LogIndexState - - /** - * Loaded a list of log items to be displayed to the user. - */ - data class LogList(val logs: List): LogIndexState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexStateFactory.kt deleted file mode 100644 index 3b477590..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexStateFactory.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.inkapplications.ack.android.log.index - -import com.inkapplications.ack.android.log.LogItemViewStateFactory -import dagger.Reusable -import javax.inject.Inject - -/** - * Create Index State objects from log data. - */ -@Reusable -class LogIndexStateFactory @Inject constructor( - private val stateFactory: LogItemViewStateFactory, -) { - fun create(data: LogIndexData): LogIndexState { - return data.packets - .ifEmpty { return LogIndexState.Empty } - .let { stateFactory.create(it, data.metric) } - .let { LogIndexState.LogList(it) } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexViewModel.kt deleted file mode 100644 index 3eb26fb8..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/index/LogIndexViewModel.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.inkapplications.ack.android.log.index - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.log.LogEvents -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android viewmodel to create and hold the state of the Log Index view data. - */ -@HiltViewModel -class LogIndexViewModel @Inject constructor( - logEvents: LogEvents, - stateFactory: LogIndexStateFactory, -): ViewModel() { - val indexState = logEvents.logIndex - .map { stateFactory.create(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, LogIndexState.Initial) -} - diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MapDataRepository.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MapDataRepository.kt deleted file mode 100644 index bf21d8e8..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MapDataRepository.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.inkapplications.ack.android.map - -import com.inkapplications.ack.android.locale.LocaleSettings -import com.inkapplications.ack.android.log.CombinedLogItemViewStateFactory -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.android.maps.MarkerViewState -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.observeBoolean -import com.inkapplications.ack.android.settings.observeInt -import com.inkapplications.ack.android.symbol.SymbolFactory -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.data.PacketStorage -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.coroutines.filterItemNotNull -import com.inkapplications.coroutines.mapItems -import dagger.Reusable -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import javax.inject.Inject - -/** - * Aggregate data needed to display the map. - */ -@Reusable -class MapDataRepository @Inject constructor( - private val logger: KimchiLogger, - private val aprs: PacketStorage, - private val symbolFactory: SymbolFactory, - private val logStateFactory: CombinedLogItemViewStateFactory, - private val settings: SettingsReadAccess, - private val mapSettings: MapSettings, - private val localeSettings: LocaleSettings, -) { - fun findMarkers(): Flow> { - return settings.observeInt(mapSettings.pinCount) - .flatMapLatest { pinCount -> - aprs.findRecent(pinCount.toLong()) - .map { it.distinctBy { it.parsed.route.source } } - .mapItems { packet -> - when (val data = packet.parsed.data) { - is PacketData.Position -> MarkerViewState(packet.id, data.coordinates, symbolFactory.createSymbol(data.symbol)) - else -> null - } - } - .filterItemNotNull() - .onEach { logger.info("New set of ${it.size} map markers.") } - } - } - - fun findLogItem(id: CaptureId): Flow { - return settings.observeBoolean(localeSettings.preferMetric).flatMapLatest { metric -> - aprs.findById(id).map { it?.let { logStateFactory.create(it.id, it.parsed, metric) } } - } - } -} - diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MapEvents.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MapEvents.kt deleted file mode 100644 index d0fa7a8b..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MapEvents.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.inkapplications.ack.android.map - -import android.Manifest.permission.ACCESS_COARSE_LOCATION -import android.content.Context -import android.content.pm.PackageManager.PERMISSION_GRANTED -import androidx.core.content.ContextCompat -import com.inkapplications.ack.android.maps.CameraPositionDefaults -import com.inkapplications.ack.android.maps.MapCameraPosition -import com.inkapplications.ack.android.maps.MapViewModel -import com.inkapplications.ack.android.maps.ZoomLevels -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.android.extensions.location.LocationAccess -import kotlinx.coroutines.flow.* -import javax.inject.Inject -import javax.inject.Singleton - -/** - * Provide access to map events. - */ -@Singleton -class MapEvents @Inject constructor( - private val mapData: MapDataRepository, - location: LocationAccess, - context: Context, -) { - val trackingEnabled = MutableStateFlow(false) - val selectedItemId = MutableStateFlow(null) - private val selectedItem = selectedItemId.flatMapLatest { - it?.let { mapData.findLogItem(it) } ?: flowOf(null) - } - private val lastLocation = if (ContextCompat.checkSelfPermission(context, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED) { - location.lastKnownLocation?.location - } else null - - - val viewState = combine( - mapData.findMarkers(), - trackingEnabled, - selectedItem, - ) { markers, tracking, selected -> - MapViewState( - MapViewModel( - cameraPosition = (lastLocation ?: markers.firstOrNull()?.coordinates) - ?.let { MapCameraPosition(it, ZoomLevels.RIVERS) } - ?: CameraPositionDefaults.unknownLocation, - markers = markers, - enablePositionTracking = tracking - ), - selectedItem = selected, - ) - }.distinctUntilChanged() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MapModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MapModule.kt deleted file mode 100644 index 29b6aa38..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MapModule.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.inkapplications.ack.android.map - -import com.inkapplications.ack.android.maps.MarkerViewState -import com.inkapplications.ack.android.settings.SettingsProvider -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.android.extensions.ViewStateFactory -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.IntoSet - -@Module -@InstallIn(SingletonComponent::class) -interface MapModule { - @Binds - @IntoSet - fun settings(mapSettings: MapSettings): SettingsProvider - - @Binds - fun markerViewStateFactory(factory: MarkerViewStateFactory): ViewStateFactory -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MapScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MapScreen.kt deleted file mode 100644 index edde0b9b..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MapScreen.kt +++ /dev/null @@ -1,87 +0,0 @@ -package com.inkapplications.ack.android.map - -import androidx.compose.foundation.layout.* -import androidx.compose.material.FloatingActionButton -import androidx.compose.material.Icon -import androidx.compose.material.contentColorFor -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.LocationDisabled -import androidx.compose.material.icons.filled.MyLocation -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.Dp -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.log.AprsLogItem -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.ack.data.CaptureId - -@Composable -fun MapScreen( - state: MapViewState, - onMapItemClick: (CaptureId?) -> Unit, - onLogItemClick: (LogItemViewState) -> Unit, - onEnableLocation: () -> Unit, - onDisableLocation: () -> Unit, - bottomContentProtection: Dp, -) = AckScreen { - MarkerMap( - viewModel = state.mapViewModel, - onMapItemClicked = onMapItemClick, - bottomProtection = dimensionResource(R.dimen.mapbox_logo_padding_bottom), - modifier = Modifier.fillMaxSize() - ) - val logState = state.selectedItem - if (state.selectedItemVisible && logState != null) { - Row ( - modifier = Modifier - .padding(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()) - .padding(top = AckTheme.spacing.gutter) - ) { - AprsLogItem( - log = logState, - onClick = onLogItemClick, - border = true, - ) - } - } - Box( - modifier = Modifier - .fillMaxSize() - .padding(bottom = bottomContentProtection), - contentAlignment = Alignment.BottomEnd, - ) { - LocationStateButton(state.mapViewModel.enablePositionTracking, onEnableLocation, onDisableLocation) - } -} - -@Composable -fun LocationStateButton( - isTracking: Boolean, - onEnableTrackingClick: () -> Unit, - onDisableTrackingClick: () -> Unit -) { - if (isTracking) { - FloatingActionButton( - onClick = onDisableTrackingClick, - backgroundColor = AckTheme.colors.surface, - contentColor = AckTheme.colors.accent, - modifier = Modifier.padding(AckTheme.spacing.gutter) - ) { - Icon(Icons.Default.MyLocation, stringResource(R.string.map_location_tracking_stop_action)) - } - } else { - FloatingActionButton( - onClick = onEnableTrackingClick, - backgroundColor = AckTheme.colors.surface, - contentColor = contentColorFor(AckTheme.colors.surface), - modifier = Modifier.padding(AckTheme.spacing.gutter) - ) { - Icon(Icons.Default.LocationDisabled, stringResource(R.string.map_location_tracking_start_action)) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MapSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MapSettings.kt deleted file mode 100644 index 9cbee874..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MapSettings.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.inkapplications.ack.android.map - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.input.IntegerValidator -import com.inkapplications.ack.android.settings.IntSetting -import com.inkapplications.ack.android.settings.Setting -import com.inkapplications.ack.android.settings.SettingsProvider -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import javax.inject.Inject - -@Reusable -class MapSettings @Inject constructor( - resources: StringResources -): SettingsProvider { - val pinCount = IntSetting( - key = "map.pins", - name = resources.getString(R.string.map_settings_pins_title), - categoryName = resources.getString(R.string.map_settings_category), - defaultValue = 500, - validator = IntegerValidator( - error = resources.getString(R.string.input_validator_positive_integer_error), - ) - ) - - override val settings: List = listOf(pinCount) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MapViewState.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MapViewState.kt deleted file mode 100644 index 1d9a3a61..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MapViewState.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.inkapplications.ack.android.map - -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.android.maps.MapViewModel - -/** - * Model the state of the entire map page. - * - * This can't include events that are dependent on the map, which loads - * separately. - */ -data class MapViewState( - val mapViewModel: MapViewModel, - val selectedItem: LogItemViewState? = null, -) { - val selectedItemVisible = selectedItem != null -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MarkerMap.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MarkerMap.kt deleted file mode 100644 index af13da3c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MarkerMap.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.inkapplications.ack.android.map - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import com.inkapplications.ack.android.maps.MapViewModel -import com.inkapplications.ack.android.maps.MapsImplementation -import com.inkapplications.ack.data.CaptureId - - -@Composable -fun MarkerMap( - viewModel: MapViewModel, - onMapItemClicked: (CaptureId?) -> Unit, - bottomProtection: Dp = 0.dp, - interactive: Boolean = true, - modifier: Modifier, -) = MapsImplementation.renderMarkerMap( - viewModel = viewModel, - onMapItemClicked = onMapItemClicked, - bottomProtection = 0.dp, - interactive = interactive, - modifier = modifier, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MarkerViewStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MarkerViewStateFactory.kt deleted file mode 100644 index b4df2c53..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MarkerViewStateFactory.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.inkapplications.ack.android.map - -import com.inkapplications.ack.android.maps.MarkerViewState -import com.inkapplications.ack.android.symbol.SymbolFactory -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.capabilities.Mapable -import com.inkapplications.ack.structures.symbolOf -import com.inkapplications.android.extensions.ViewStateFactory -import javax.inject.Inject - -/** - * Convert packet data into the model used to render the marker on a map. - * - * If the packet is not mapable for whatever reason, this will return a - * null marker. - */ -class MarkerViewStateFactory @Inject constructor( - private val symbolFactory: SymbolFactory, -): ViewStateFactory { - private val defaultWeatherSymbol = symbolOf('W', '/') - - override fun create(data: CapturedPacket): MarkerViewState? { - val mapable = data.parsed.data as? Mapable ?: return null - val coordinates = mapable.coordinates ?: return null - val symbol = mapable.symbol - ?: defaultWeatherSymbol.takeIf { data.parsed.data is PacketData.Weather } - ?: return null - val symbolBitmap = symbolFactory.createSymbol(symbol) ?: return null - - return MarkerViewState(data.id, coordinates, symbolBitmap) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardActivity.kt deleted file mode 100644 index 7a878b7f..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardActivity.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import androidx.activity.compose.setContent -import androidx.compose.runtime.LaunchedEffect -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.capture.CaptureActivity -import com.inkapplications.ack.android.settings.SettingsAccess -import com.inkapplications.ack.android.settings.license.LicensePromptFieldValues -import com.inkapplications.ack.android.settings.license.LicensePromptValidator -import com.inkapplications.android.extensions.ExtendedActivity -import com.inkapplications.android.startActivity -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi -import kimchi.analytics.Property -import kotlinx.coroutines.flow.first -import javax.inject.Inject - -/** - * Screen that shows required agreements and setup at first launch. - */ -@AndroidEntryPoint -class OnboardActivity: ExtendedActivity(), UserAgreementController { - @Inject - lateinit var stateAccess: OnboardingStateAccess - - @Inject - lateinit var settingsAccess: SettingsAccess - - @Inject - lateinit var licensePromptValidator: LicensePromptValidator - - override fun onCreate() { - super.onCreate() - Kimchi.trackScreen("onboard") - - setContent { - val viewModel: OnboardingViewModel = hiltViewModel() - - OnboardScreen( - viewModel = viewModel, - userAgreementController = this, - licenseValidator = licensePromptValidator, - onLicenseContinueClick = ::onLicenseContinueClick, - ) - - LaunchedEffect(null) { - viewModel.screenState.first { it is OnboardingState.Complete } - onCompleted() - } - } - } - - private fun onLicenseContinueClick(values: LicensePromptFieldValues) { - Kimchi.trackEvent("onboard_license", listOf( - Property.IntProperty("license_callsign_provided", if (values.callsign.isBlank()) 0 else 1), - Property.IntProperty("license_passcode_provided", if (values.passcode.isBlank()) 0 else 1), - )) - settingsAccess.setLicense(values) - stateAccess.setLicensePromptCompleted() - } - - private fun onCompleted() { - Kimchi.trackEvent("onboard_complete") - startActivity(CaptureActivity::class) - finish() - } - - override fun onTermsAgreeClick() { - Kimchi.trackEvent("onboard_terms_agreement") - stateAccess.setUserAgreed() - } - - override fun onTermsDeclineClick() { - // Intentionally no logging. - finish() - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardScreen.kt deleted file mode 100644 index f3de7c37..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardScreen.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import com.inkapplications.ack.android.settings.license.LicensePromptFieldValues -import com.inkapplications.ack.android.settings.license.LicensePromptScreen -import com.inkapplications.ack.android.settings.license.LicensePromptValidator -import com.inkapplications.ack.android.ui.theme.AckScreen - -@Composable -fun OnboardScreen( - viewModel: OnboardingViewModel, - userAgreementController: UserAgreementController, - licenseValidator: LicensePromptValidator, - onLicenseContinueClick: (LicensePromptFieldValues) -> Unit, -) = AckScreen { - val state = viewModel.screenState.collectAsState() - when (val onboardingState = state.value) { - OnboardingState.Complete -> {} - OnboardingState.Initial -> {} - is OnboardingState.LicensePrompt -> LicensePromptScreen( - initialValues = onboardingState.initialValues, - validator = licenseValidator, - onContinue = onLicenseContinueClick, - ) - OnboardingState.UserAgreement -> UsageAgreementPrompt(userAgreementController) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardSettings.kt deleted file mode 100644 index 1bb74262..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardSettings.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.settings.* -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import javax.inject.Inject - -@Reusable -class OnboardSettings @Inject constructor( - resources: StringResources -): SettingsProvider { - val agreementRevision = IntSetting( - key = "onboarding.agreement", - name = resources.getString(R.string.settings_onboard_license), - categoryName = resources.getString(R.string.settings_onboard_category), - defaultValue = 0, - visibility = SettingVisibility.Dev, - ) - val completedLicensePrompt = BooleanSetting( - key = "onboarding.license", - name = resources.getString(R.string.settings_onboard_license), - categoryName = resources.getString(R.string.settings_onboard_category), - defaultValue = false, - visibility = SettingVisibility.Dev, - ) - - override val settings: List = listOf( - agreementRevision, - completedLicensePrompt, - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingModule.kt deleted file mode 100644 index fafd8965..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingModule.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import com.inkapplications.ack.android.settings.SettingsProvider -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.IntoSet - -@Module -@InstallIn(SingletonComponent::class) -abstract class OnboardingModule { - @Binds - @IntoSet - abstract fun settings(settings: OnboardSettings): SettingsProvider -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingState.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingState.kt deleted file mode 100644 index df1f5b5e..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingState.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import com.inkapplications.ack.android.settings.license.LicensePromptFieldValues - -/** - * Possible states of the onboarding screen. - */ -sealed interface OnboardingState { - /** - * Initial state, before any data is loaded. - */ - object Initial: OnboardingState - - /** - * Screen prompting the user to agree to the usage agreement. - */ - object UserAgreement: OnboardingState - - /** - * Screen prompting the user to enter their callsign information. - */ - class LicensePrompt( - val initialValues: LicensePromptFieldValues, - ): OnboardingState - - /** - * Screen state after all data has been completed. - */ - object Complete: OnboardingState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingStateAccess.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingStateAccess.kt deleted file mode 100644 index cdf670ee..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingStateAccess.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.connection.ConnectionSettings -import com.inkapplications.ack.android.settings.* -import com.inkapplications.android.extensions.IntegerResources -import dagger.Reusable -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map -import javax.inject.Inject - -/** - * Provides information access relevant to onboarding in the application. - */ -@Reusable -class OnboardingStateAccess @Inject constructor( - readSettings: SettingsReadAccess, - private val writeSettings: SettingsWriteAccess, - private val onboardingSettings: OnboardSettings, - connectionSettings: ConnectionSettings, - integers: IntegerResources, -) { - private val latestRevision = integers.getInteger(R.integer.usage_revision) - private val agreementRevision = readSettings.observeInt(onboardingSettings.agreementRevision) - private val completedLicensePrompt = readSettings.observeBoolean(onboardingSettings.completedLicensePrompt) - private val address = readSettings.observeData(connectionSettings.address) - private val passcode = readSettings.observeData(connectionSettings.passcode) - - /** - * Data needed to render the onboarding screens. - */ - val onboardingData = agreementRevision - .map { agreed -> - OnboardingStateFactory.OnboardingData( - latestRevision = latestRevision, - agreementRevision = agreed, - ) - } - .combine(completedLicensePrompt) { data, completedLicense -> - data.copy(completedLicense = completedLicense) - } - .combine(address) { data, address -> - data.copy(currentAddress = address) - } - .combine(passcode) { data, passcode -> - data.copy(currentPasscode = passcode) - } - - /** - * Whether onboarding is considered completed. - */ - val finished = combine(agreementRevision, completedLicensePrompt) { agreement, licenseComplete -> - agreement == latestRevision && licenseComplete - } - - /** - * Update the latest policy agreement to the current revision. - */ - fun setUserAgreed() { - writeSettings.setInt(onboardingSettings.agreementRevision, latestRevision) - } - - /** - * Set the license prompt flag as completed. - */ - fun setLicensePromptCompleted() { - writeSettings.setBoolean(onboardingSettings.completedLicensePrompt, true) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingStateFactory.kt deleted file mode 100644 index d5b2e3ca..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingStateFactory.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import com.inkapplications.ack.android.settings.Passcode -import com.inkapplications.ack.android.settings.license.LicensePromptFieldValues -import com.inkapplications.ack.structures.station.StationAddress -import dagger.Reusable -import javax.inject.Inject - -/** - * Create onboarding state objects from the current data. - */ -@Reusable -class OnboardingStateFactory @Inject constructor() { - fun screenState(data: OnboardingData): OnboardingState { - return when { - data.agreementRevision != data.latestRevision -> OnboardingState.UserAgreement - !data.completedLicense -> OnboardingState.LicensePrompt( - initialValues = LicensePromptFieldValues( - callsign = data.currentAddress?.toString().orEmpty(), - passcode = data.currentPasscode?.value?.toString().orEmpty(), - ) - ) - else -> OnboardingState.Complete - } - } - - /** - * Data required to render the onboarding screens. - */ - data class OnboardingData( - val latestRevision: Int, - val agreementRevision: Int? = null, - val completedLicense: Boolean = false, - val currentAddress: StationAddress? = null, - val currentPasscode: Passcode? = null, - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingViewModel.kt deleted file mode 100644 index 81543470..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/OnboardingViewModel.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android viewmodel containing the current state of an onboarding screen. - */ -@HiltViewModel -class OnboardingViewModel @Inject constructor( - stateAccess: OnboardingStateAccess, - onboardingStateFactory: OnboardingStateFactory, -): ViewModel() { - val screenState = stateAccess.onboardingData - .map { onboardingStateFactory.screenState(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, OnboardingState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/UsageAgreementPrompt.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/UsageAgreementPrompt.kt deleted file mode 100644 index dccef758..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/UsageAgreementPrompt.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Button -import androidx.compose.material.ButtonDefaults -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.settings.agreement.UsageAgreement -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun UsageAgreementPrompt( - controller: UserAgreementController, -) { - Column( - modifier = Modifier - .padding( - top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), - bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() - ) - .padding(AckTheme.spacing.gutter) - .fillMaxHeight() - .verticalScroll(rememberScrollState()), - ) { - Text( - stringResource(R.string.usage_title), - style = AckTheme.typography.h1, - ) - Spacer(Modifier.height(AckTheme.spacing.content)) - UsageAgreement() - Spacer(Modifier.weight(1f).defaultMinSize(minHeight = AckTheme.spacing.content)) - Button( - onClick = controller::onTermsDeclineClick, - colors = ButtonDefaults.outlinedButtonColors(), - modifier = Modifier.fillMaxWidth().padding(top = AckTheme.spacing.content), - ) { - Text(stringResource(R.string.usage_decline_action)) - } - Spacer(Modifier.height(AckTheme.spacing.item)) - Button( - onClick = controller::onTermsAgreeClick, - modifier = Modifier.fillMaxWidth(), - ) { - Text(stringResource(R.string.usage_agree_action)) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/UserAgreementController.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/UserAgreementController.kt deleted file mode 100644 index 0e7f6530..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/UserAgreementController.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.inkapplications.ack.android.onboard - -interface UserAgreementController { - fun onTermsAgreeClick() - fun onTermsDeclineClick() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/CompositeSettingsProvider.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/CompositeSettingsProvider.kt deleted file mode 100644 index 15e49567..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/CompositeSettingsProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.inkapplications.ack.android.settings - -import dagger.Reusable -import javax.inject.Inject - -/** - * Combines all the settings providers in the application into a single provider. - */ -@Reusable -class CompositeSettingsProvider @Inject constructor( - providers: @JvmSuppressWildcards Set -): SettingsProvider { - override val settings: List = providers.map { it.settings }.flatten() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/LicenseData.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/LicenseData.kt deleted file mode 100644 index 9c8a039f..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/LicenseData.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.inkapplications.ack.android.settings - -import com.inkapplications.ack.structures.station.StationAddress - -/** - * Station Address + Passcode data pair. - */ -data class LicenseData( - val address: StationAddress? = null, - val passcode: Passcode? = null, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/LicenseViewState.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/LicenseViewState.kt deleted file mode 100644 index 99390a8f..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/LicenseViewState.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.inkapplications.ack.android.settings - -/** - * Models the state the user's license information displayed in settings. - */ -sealed interface LicenseViewState { - /** - * The initial state before data is loaded. - */ - object Initial: LicenseViewState - - /** - * Indicates that the user has not set a callsign or passcode. - */ - object Unconfigured: LicenseViewState - - /** - * Indicates that the user has a callsign for their license configured. - */ - sealed interface CallsignConfigured: LicenseViewState { - /** - * Readable Callsign to display on the screen. - */ - val callsign: String - } - - /** - * Indicates that the user has configured both a callsign, but not a passcode. - */ - data class Registered(override val callsign: String): CallsignConfigured - - /** - * Indicates that the user has configured both a callsign and passcode. - */ - data class Verified(override val callsign: String): CallsignConfigured -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/NullSettingsReadAccesss.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/NullSettingsReadAccesss.kt deleted file mode 100644 index 3802fc20..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/NullSettingsReadAccesss.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.inkapplications.ack.android.settings - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf - -/** - * Read access to settings that always returns a null result. - * - * This can be used for testing or as a stand-in for disabled services. - */ -object NullSettingsReadAccesss: SettingsReadAccess { - override fun observeStringState(setting: StringSetting): Flow = flowOf(null) - override fun observeIntState(setting: IntSetting): Flow = flowOf(null) - override fun observeBooleanState(setting: BooleanSetting): Flow = flowOf(null) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/Passcode.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/Passcode.kt deleted file mode 100644 index b526ff62..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/Passcode.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.inkapplications.ack.android.settings - -/** - * Wrapping class for the user's license passcode. - */ -@JvmInline -value class Passcode(val value: Int) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/PrioritySettingValues.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/PrioritySettingValues.kt deleted file mode 100644 index fe0ecb1f..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/PrioritySettingValues.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.inkapplications.ack.android.settings - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine - -/** - * Provides read access to a collection of settings provider by taking the first one with a - * successful result. - */ -class PrioritySettingValues(private vararg val delegates: SettingsReadAccess): SettingsReadAccess { - override fun observeStringState(setting: StringSetting): Flow { - return delegates.map { it.observeStringState(setting) }.flattenFirst { it != null } - } - - override fun observeIntState(setting: IntSetting): Flow { - return delegates.map { it.observeIntState(setting) }.flattenFirst { it != null } - } - - override fun observeBooleanState(setting: BooleanSetting): Flow { - return delegates.map { it.observeBooleanState(setting) }.flattenFirst { it != null } - } - - /** - * Merge a list of flows taking the first flow's latest result that matches a [predicate] - */ - private inline fun List>.flattenFirst(crossinline predicate: (T) -> Boolean): Flow = combine(*this.toTypedArray()) { - it.firstOrNull { predicate(it) } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/Setting.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/Setting.kt deleted file mode 100644 index 2a6cc003..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/Setting.kt +++ /dev/null @@ -1,147 +0,0 @@ -package com.inkapplications.ack.android.settings - -import com.inkapplications.ack.android.input.NoValidation -import com.inkapplications.ack.android.input.ValidationResult -import com.inkapplications.ack.android.input.Validator -import com.inkapplications.ack.android.settings.transformer.IntFieldTransformer -import com.inkapplications.ack.android.settings.transformer.Transformer - -/** - * Definition of an individual configuration aspect of the application. - */ -sealed interface Setting { - /** - * A Unique Identifier for the setting, used for storage. - */ - val key: String - - /** - * A user-readable name for the setting. - */ - val name: String - - /** - * A user-readable name for the category of the setting. - */ - val categoryName: String - - /** - * The value that should be used if no provider has overridden it. - */ - val defaultValue: Any - - /** - * Identifies a setting that should be hidden from the user. - */ - @Deprecated("Use visibility instead", ReplaceWith("visibility == Visibility.Advanced")) - val advanced: Boolean get() { return visibility == SettingVisibility.Advanced } - - /** - * An object to check whether an input value can be allowed for this setting. - */ - val validator: Validator<*> - - /** - * How/when to display the setting in the UI. - */ - val visibility: SettingVisibility -} - -/** - * Plain string setting. - */ -open class StringSetting( - override val key: String, - override val name: String, - override val categoryName: String, - override val defaultValue: String, - override val visibility: SettingVisibility = SettingVisibility.Visible, - override val validator: Validator = NoValidation, -): Setting - -/** - * A plain number setting. - */ -open class IntSetting( - override val key: String, - override val name: String, - override val categoryName: String, - override val defaultValue: Int, - override val visibility: SettingVisibility = SettingVisibility.Visible, - override val validator: Validator = NoValidation, -): Setting - -/** - * A plain boolean setting. - */ -data class BooleanSetting( - override val key: String, - override val name: String, - override val categoryName: String, - override val defaultValue: Boolean, - override val visibility: SettingVisibility = SettingVisibility.Visible, - override val validator: Validator = NoValidation, -): Setting - -/** - * Complex data type that is based on a [StringSetting] for storage. - * - * @param storageTransformer Used to convert to/from the data structure and a string. - * @param inputValidator Used to validate plain input from the user. - * @param dataValidator Used to validate input from the user, but after it has been transformed by the [storageTransformer]. - */ -class StringBackedSetting( - key: String, - name: String, - categoryName: String, - override val defaultData: T, - override val visibility: SettingVisibility = SettingVisibility.Visible, - override val storageTransformer: Transformer, - val inputValidator: Validator = NoValidation, - val dataValidator: Validator = NoValidation, -): StringSetting( - key = key, - name = name, - categoryName = categoryName, - defaultValue = storageTransformer.toStorage(defaultData), - visibility = visibility, - validator = object: Validator { - override fun validate(input: String): ValidationResult { - val inputResult = inputValidator.validate(input) - if (inputResult !is ValidationResult.Valid) return inputResult - return storageTransformer.toData(input).run(dataValidator::validate) - } - } -), TransformableSetting - -/** - * Complex data type that is based on a [IntSetting] for storage. - * - * @param storageTransformer Used to convert to/from the data structure and an integer. - * @param inputValidator Used to validate plain input from the user. - * @param dataValidator Used to validate input from the user, but after it has been transformed by the [storageTransformer]. - */ -class IntBackedSetting( - key: String, - name: String, - categoryName: String, - override val defaultData: T, - override val visibility: SettingVisibility = SettingVisibility.Visible, - override val storageTransformer: Transformer, - val inputValidator: Validator = NoValidation, - val dataValidator: Validator = NoValidation, - val fieldTransformer: Transformer = IntFieldTransformer, -): IntSetting( - key = key, - name = name, - categoryName = categoryName, - defaultValue = storageTransformer.toStorage(defaultData), - visibility = visibility, - validator = object: Validator { - override fun validate(input: Int): ValidationResult { - val inputResult = inputValidator.validate(input) - if (inputResult !is ValidationResult.Valid) return inputResult - return storageTransformer.toData(input).run(dataValidator::validate) - } - } -), TransformableSetting diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingRows.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingRows.kt deleted file mode 100644 index e8630aaa..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingRows.kt +++ /dev/null @@ -1,129 +0,0 @@ -package com.inkapplications.ack.android.settings - -import androidx.compose.foundation.Image -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.material.Switch -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.symbol.SymbolSelectorViewModel -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.ack.structures.Symbol -import com.inkapplications.ack.structures.symbolOf - -@Composable -fun IntStateRow( - state: SettingState.IntState, - onClick: () -> Unit -) = Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clickable(onClick = onClick) - .padding(vertical = AckTheme.spacing.clickSafety, horizontal = AckTheme.spacing.gutter) -) { - Column { - WarningLabel(state.setting) - Text(state.setting.name, fontWeight = FontWeight.Bold) - } - Spacer(Modifier.weight(1f)) - Text(state.value.toString(), style = AckTheme.typography.caption) -} - -@Composable -fun StringStateRow( - state: SettingState.StringState, - onClick: () -> Unit -) = Column( - modifier = Modifier - .clickable(onClick = onClick) - .fillMaxWidth() - .padding(vertical = AckTheme.spacing.clickSafety, horizontal = AckTheme.spacing.gutter) -) { - WarningLabel(state.setting) - Text(state.setting.name, fontWeight = FontWeight.Bold) - Text(state.value, style = AckTheme.typography.caption) -} - -@Composable -fun BooleanStateRow( - state: SettingState.BooleanState, - onChange: (Boolean) -> Unit, -) = Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clickable { onChange(!state.value) } - .padding(vertical = AckTheme.spacing.clickSafety, horizontal = AckTheme.spacing.gutter) -) { - Column { - WarningLabel(state.setting) - Text(state.setting.name, fontWeight = FontWeight.Bold) - } - Spacer(Modifier.weight(1f)) - Switch( - checked = state.value, - onCheckedChange = { checked -> - onChange(checked) - } - ) -} - -/** - * APRS Symbol selection setting state. - */ -@Composable -fun SymbolStateRow( - state: SettingState.StringState, - setting: StringBackedSetting, - symbolViewModel: SymbolSelectorViewModel = hiltViewModel(), - onClick: () -> Unit, -) = Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clickable(onClick = onClick) - .padding(vertical = AckTheme.spacing.clickSafety, horizontal = AckTheme.spacing.gutter) -) { - Column { - WarningLabel(setting) - Text(setting.name, fontWeight = FontWeight.Bold) - } - Spacer(Modifier.weight(1f)) - - val bitmap = symbolViewModel.createBitmap(symbolOf(state.value)) - if (bitmap != null) { - Image( - bitmap = bitmap.asImageBitmap(), - contentDescription = null, - modifier = Modifier - .width(24.dp) - .height(24.dp), - ) - } -} - -/** - * Warning label for advanced or dev settings. - */ -@Composable -private fun WarningLabel(setting: Setting) { - when (setting.visibility) { - SettingVisibility.Advanced -> Text( - text = stringResource(R.string.settings_advanced_label), - color = AckTheme.colors.warnForeground, - style = AckTheme.typography.caption, - ) - SettingVisibility.Dev -> Text( - text = stringResource(R.string.settings_dev_label), - color = AckTheme.colors.dangerForeground, - style = AckTheme.typography.caption, - ) - else -> {} - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingState.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingState.kt deleted file mode 100644 index adad311a..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingState.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.inkapplications.ack.android.settings - -sealed interface SettingState { - val setting: Setting - - data class IntState( - override val setting: IntSetting, - val value: Int, - ): SettingState - - data class StringState( - override val setting: StringSetting, - val value: String, - ): SettingState - - data class BooleanState( - override val setting: BooleanSetting, - val value: Boolean, - ): SettingState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingVisibility.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingVisibility.kt deleted file mode 100644 index 400eed85..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingVisibility.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.inkapplications.ack.android.settings - -/** - * How/when to display a setting. - */ -enum class SettingVisibility { - /** - * Displayed to the user normally in the UI. - */ - Visible, - - /** - * Displayed only if the user chooses to display advanced settings. - */ - Advanced, - - /** - * Displayed only as a partially hidden developer setting. - */ - Dev, -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsAccess.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsAccess.kt deleted file mode 100644 index c50d496d..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsAccess.kt +++ /dev/null @@ -1,90 +0,0 @@ -package com.inkapplications.ack.android.settings - -import com.inkapplications.ack.android.connection.ConnectionSettings -import com.inkapplications.ack.android.settings.license.LicensePromptFieldValues -import com.inkapplications.ack.structures.station.toStationAddress -import com.inkapplications.coroutines.mapItems -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map -import javax.inject.Inject - -/** - * Provide the settings screen with application-wide settings info. - */ -class SettingsAccess @Inject constructor( - private val settingsProvider: SettingsProvider, - private val settingValues: SettingsReadAccess, - private val settingsStorage: SettingsWriteAccess, - private val connectionSettings: ConnectionSettings, -) { - fun settingsGroups(visibility: SettingVisibility): Flow { - return settingsProvider.settings - .filter { it.visibility <= visibility } - .groupBy { it.categoryName } - .map { (key, settings) -> - settings.map { setting -> - when (setting) { - is StringSetting -> settingValues.observeString(setting) - .map { SettingState.StringState(setting, it) } - is IntSetting -> settingValues.observeInt(setting) - .map { SettingState.IntState(setting, it) } - is BooleanSetting -> settingValues.observeBoolean(setting) - .map { SettingState.BooleanState(setting, it) } - } - }.let { - combine(*it.toTypedArray()) { it.toList() } - } .map { - SettingsGroup(key, it) - } - } - .let { - combine(*it.toTypedArray()) { it.toList() } - } - .mapItems { - it.copy(settings = it.settings.sortedBy { it.setting.name }) - } - .map { - it.sortedBy { it.name } - } - .map { - SettingsListData().apply { - this.settings = it - this.visibility = visibility - } - } - } - - val licenseData = settingValues.observeData(connectionSettings.address) - .combine(settingValues.observeData(connectionSettings.passcode)) { callsign, passcode -> - LicenseData(callsign, passcode) - } - - val licensePromptFieldValues: Flow = settingValues.observeData(connectionSettings.address) - .combine(settingValues.observeData(connectionSettings.passcode)) { callsign, passcode -> - LicensePromptFieldValues(callsign?.toString().orEmpty(), passcode?.value?.toString().orEmpty()) - } - - fun setLicense(values: LicensePromptFieldValues) { - settingsStorage.setData(connectionSettings.address, values.callsign.trim().takeIf { it.isNotEmpty() }?.toStationAddress()) - settingsStorage.setData(connectionSettings.passcode, Passcode(values.passcode.trim().toIntOrNull() ?: -1)) - } - - fun updateInt(key: String, value: Int) { - val setting = settingsProvider.settings.find { it.key == key } as? IntSetting - ?: throw IllegalArgumentException("Unknown Int Setting: <$key>") - settingsStorage.setInt(setting, value) - } - - fun updateString(key: String, value: String) { - val setting = settingsProvider.settings.find { it.key == key } as? StringSetting - ?: throw IllegalArgumentException("Unknown String Setting: <$key>") - settingsStorage.setString(setting, value) - } - - fun updateBoolean(key: String, value: Boolean) { - val setting = settingsProvider.settings.find { it.key == key } as? BooleanSetting - ?: throw IllegalArgumentException("Unknown Boolean Setting: <$key>") - settingsStorage.setBoolean(setting, value) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsActivity.kt deleted file mode 100644 index 198d18b5..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsActivity.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.inkapplications.ack.android.settings - -import androidx.activity.compose.setContent -import androidx.activity.viewModels -import com.google.android.gms.oss.licenses.OssLicensesMenuActivity -import com.inkapplications.ack.android.settings.agreement.UserAgreementActivity -import com.inkapplications.ack.android.settings.license.LicenseEditActivity -import com.inkapplications.android.extensions.ExtendedActivity -import com.inkapplications.android.startActivity -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi -import kimchi.analytics.intProperty -import kimchi.analytics.stringProperty -import javax.inject.Inject - -@AndroidEntryPoint -class SettingsActivity: ExtendedActivity(), SettingsController { - @Inject - lateinit var settingsAccess: SettingsAccess - - private val viewModel: SettingsViewModel by viewModels() - - override fun onCreate() { - super.onCreate() - Kimchi.trackScreen("settings") - - setContent { - SettingsScreen( - viewModel = viewModel, - controller = this, - ) - } - } - - override fun onVersionLongPress() { - Kimchi.trackEvent("settings_show_advanced") - viewModel.showDev() - } - - override fun onCallsignEditClick() { - Kimchi.trackEvent("settings_license_edit") - startActivity(LicenseEditActivity::class) - } - - override fun onIntSettingChanged(state: SettingState.IntState, newValue: Int) { - Kimchi.trackEvent("settings_change", listOf( - stringProperty("setting", state.setting.key), - intProperty("value", newValue) - )) - settingsAccess.updateInt(state.setting.key, newValue) - } - - override fun onStringSettingChanged(state: SettingState.StringState, newValue: String) { - Kimchi.trackEvent("settings_change", listOf( - stringProperty("setting", state.setting.key), - stringProperty("value", newValue) - )) - settingsAccess.updateString(state.setting.key, newValue) - } - - override fun onSwitchSettingChanged(state: SettingState.BooleanState, newState: Boolean) { - Kimchi.trackEvent("settings_change", listOf( - stringProperty("setting", state.setting.key), - stringProperty("value", newState.toString()) - )) - settingsAccess.updateBoolean(state.setting.key, newState) - } - - override fun onAckLicenseClick() { - Kimchi.trackEvent("settings_self_license") - startActivity(UserAgreementActivity::class) - } - - override fun onLicensesClick() { - Kimchi.trackEvent("settings_show_licenses") - startActivity(OssLicensesMenuActivity::class) - } - - override fun onAdvancedChanged(checked: Boolean) { - Kimchi.trackEvent("settings_advanced", listOf( - intProperty("enabled", if (checked) 1 else 0) - )) - viewModel.showAdvanced(checked) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsController.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsController.kt deleted file mode 100644 index 353c1f78..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsController.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.inkapplications.ack.android.settings - -interface SettingsController { - fun onIntSettingChanged(state: SettingState.IntState, newValue: Int) - fun onStringSettingChanged(state: SettingState.StringState, newValue: String) - fun onSwitchSettingChanged(state: SettingState.BooleanState, newState: Boolean) - fun onVersionLongPress() - fun onBackPressed() - fun onCallsignEditClick() - fun onAckLicenseClick() - fun onLicensesClick() - fun onAdvancedChanged(checked: Boolean) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsGroup.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsGroup.kt deleted file mode 100644 index ef933cf1..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsGroup.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.inkapplications.ack.android.settings - -data class SettingsGroup(val name: String, val settings: List) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsListData.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsListData.kt deleted file mode 100644 index 15cac1a9..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsListData.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.inkapplications.ack.android.settings - -/** - * Data required to display the list of settings on the settings screen. - */ -class SettingsListData { - lateinit var settings: List - lateinit var visibility: SettingVisibility -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsListViewState.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsListViewState.kt deleted file mode 100644 index c6efff89..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsListViewState.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.inkapplications.ack.android.settings - -/** - * Models the state of the list of settings within the settings screen. - */ -sealed interface SettingsListViewState { - /** - * The initial state of the settings screen before data is loaded. - */ - object Initial: SettingsListViewState - - /** - * The state of the settings screen after data is loaded. - */ - data class Loaded( - val settingsList: List, - val advancedVisible: Boolean, - ): SettingsListViewState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsModule.kt deleted file mode 100644 index 1a0c56a7..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsModule.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.inkapplications.ack.android.settings - -import com.inkapplications.ack.android.BuildConfig -import com.inkapplications.ack.android.firebase.FirebaseSettings -import dagger.Binds -import dagger.Module -import dagger.Provides -import dagger.Reusable -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.Multibinds - -@Module(includes = [StaticSettingsModule::class]) -@InstallIn(SingletonComponent::class) -class SettingsModule { - @Provides - @Reusable - fun settingsProvider( - sharedPreferences: SharedPreferenceSettings, - firebaseSettings: FirebaseSettings - ): SettingsReadAccess { - val readProviders = if (BuildConfig.USE_GOOGLE_SERVICES) { - arrayOf(sharedPreferences, firebaseSettings) - } else { - arrayOf(sharedPreferences) - } - - return PrioritySettingValues(*readProviders) - } -} - -@Module -abstract class StaticSettingsModule { - @Binds - @Reusable - abstract fun settingsStorage(preferences: SharedPreferenceSettings): SettingsWriteAccess - - @Multibinds - abstract fun settingsProviders(): @JvmSuppressWildcards Set - - @Binds - @Reusable - abstract fun settingsProvider(provider: CompositeSettingsProvider): SettingsProvider -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsProvider.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsProvider.kt deleted file mode 100644 index 5daeb577..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsProvider.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.inkapplications.ack.android.settings - -/** - * Contributor to the list of application-wide available settings. - */ -interface SettingsProvider { - val settings: List -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsReadAccess.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsReadAccess.kt deleted file mode 100644 index 67e9b7a4..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsReadAccess.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.inkapplications.ack.android.settings - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map - -/** - * Provides access to key/value primitive preferences for the application. - */ -interface SettingsReadAccess { - fun observeStringState(setting: StringSetting): Flow - fun observeIntState(setting: IntSetting): Flow - fun observeBooleanState(setting: BooleanSetting): Flow -} - -fun SettingsReadAccess.observeString(setting: StringSetting): Flow { - return observeStringState(setting).map { it ?: setting.defaultValue } -} - -fun SettingsReadAccess.observeInt(setting: IntSetting): Flow { - return observeIntState(setting).map { it ?: setting.defaultValue } -} - -fun SettingsReadAccess.observeBoolean(setting: BooleanSetting): Flow { - return observeBooleanState(setting).map { it ?: setting.defaultValue } -} - -/** - * Observes the value of a setting after being transformed into its data type. - */ -fun SettingsReadAccess.observeData(setting: TransformableSetting): Flow { - return when (setting) { - is IntBackedSetting -> observeInt(setting).map(setting.storageTransformer::toData) - is StringBackedSetting -> observeString(setting).map(setting.storageTransformer::toData) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsScreen.kt deleted file mode 100644 index 4e3bcf7c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsScreen.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.inkapplications.ack.android.settings - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.input.IntPrompt -import com.inkapplications.ack.android.input.StringPrompt -import com.inkapplications.ack.android.settings.buildinfo.BuildInfo -import com.inkapplications.ack.android.symbol.SymbolPrompt -import com.inkapplications.ack.android.ui.CallsignChip -import com.inkapplications.ack.android.ui.NavigationRow -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.ack.structures.Symbol -import com.inkapplications.ack.structures.code - -@Composable -fun SettingsScreen( - viewModel: SettingsViewModel, - controller: SettingsController, -) = AckScreen { - Column( - modifier = Modifier - .fillMaxSize() - .padding( - top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), - bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() - ) - .verticalScroll(rememberScrollState()), - ) { - NavigationRow( - title = stringResource(R.string.settings_title), - onBackPressed = controller::onBackPressed, - ) - LicenseRow(viewModel.licenseState.collectAsState(), controller) - val promptSetting = remember { mutableStateOf(null) } - val settingState = promptSetting.value - when { - settingState is SettingState.StringState && settingState.setting is StringBackedSetting<*> && settingState.setting.defaultData is Symbol -> { - val symbolSetting = settingState.setting as StringBackedSetting - SymbolPrompt( - title = symbolSetting.name, - value = symbolSetting.storageTransformer.toData(settingState.value), - onDismiss = { promptSetting.value = null }, - onSubmit = { - if (it != null) { - controller.onStringSettingChanged(settingState, it.code) - } - promptSetting.value = null - } - ) - } - settingState is SettingState.IntState -> IntPrompt( - title = settingState.setting.name, - value = settingState.value, - validator = settingState.setting.validator, - onDismiss = { promptSetting.value = null }, - onSubmit = { - controller.onIntSettingChanged(settingState, it) - promptSetting.value = null - } - ) - settingState is SettingState.StringState -> StringPrompt( - title = settingState.setting.name, - value = settingState.value, - validator = settingState.setting.validator, - onDismiss = { promptSetting.value = null }, - onSubmit = { - controller.onStringSettingChanged(settingState, it) - promptSetting.value = null - } - ) - else -> {} - } - - when (val listState = viewModel.settingsList.collectAsState().value) { - SettingsListViewState.Initial -> {} - is SettingsListViewState.Loaded -> { - listState.settingsList.forEach { - SettingsCard(group = it, controller = controller, promptSetting = promptSetting) - } - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - modifier = Modifier.fillMaxWidth(), - ) { - Text( - text = stringResource(R.string.settings_advanced_toggle_label), - style = AckTheme.typography.caption, - modifier = Modifier.padding(end = AckTheme.spacing.item) - ) - Switch( - checked = listState.advancedVisible, - onCheckedChange = controller::onAdvancedChanged, - ) - } - } - } - - Spacer(Modifier - .weight(1f) - .defaultMinSize(minHeight = AckTheme.spacing.content)) - - BuildInfo( - buildInfo = viewModel.buildInfoState.collectAsState().value, - onVersionLongPress = controller::onVersionLongPress, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - - Text( - text = stringResource(R.string.settings_author_line), - style = AckTheme.typography.caption, - textAlign = TextAlign.Center, - modifier = Modifier.fillMaxWidth() - ) - Spacer(Modifier.height(AckTheme.spacing.content)) - TextButton(controller::onAckLicenseClick, modifier = Modifier.align(Alignment.CenterHorizontally)) { - Text(stringResource(R.string.settings_ack_license)) - } - TextButton(controller::onLicensesClick, modifier = Modifier.align(Alignment.CenterHorizontally)) { - Text(stringResource(R.string.settings_licenses)) - } - } -} - -@Composable -private fun LicenseRow( - state: State, - controller: SettingsController, -) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = AckTheme.spacing.gutter, vertical = AckTheme.spacing.content), - ) { - when (val licenseState = state.value) { - LicenseViewState.Initial -> {} - LicenseViewState.Unconfigured -> Button(onClick = controller::onCallsignEditClick) { - Text("Add Callsign") - } - is LicenseViewState.CallsignConfigured -> CallsignChip( - licenseState.callsign, - licenseState is LicenseViewState.Verified, - controller::onCallsignEditClick - ) - } - } -} - -@Composable -private fun SettingsCard( - group: SettingsGroup, - controller: SettingsController, - promptSetting: MutableState, -) { - Card(modifier = Modifier.padding(vertical = AckTheme.spacing.item)) { - Column { - SettingsCategoryRow(group.name) - group.settings.forEach { item -> - val setting = item.setting - when { - item is SettingState.StringState && setting is StringBackedSetting<*> && setting.defaultData is Symbol -> { - val symbolSetting = setting as StringBackedSetting - SymbolStateRow(item, symbolSetting) { - promptSetting.value = item - } - } - item is SettingState.BooleanState -> BooleanStateRow(item) { - controller.onSwitchSettingChanged(item, it) - } - item is SettingState.IntState -> IntStateRow(item) { - promptSetting.value = item - } - item is SettingState.StringState -> StringStateRow(item) { - promptSetting.value = item - } - } - } - } - } -} - -@Composable -fun SettingsCategoryRow(name: String) = Row( - Modifier.padding(horizontal = AckTheme.spacing.gutter, vertical = AckTheme.spacing.item) -) { - Text(name, style = AckTheme.typography.h2, modifier = Modifier.padding(vertical = AckTheme.spacing.item)) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsViewModel.kt deleted file mode 100644 index 32398e5f..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsViewModel.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.inkapplications.ack.android.settings - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.settings.buildinfo.BuildDataAccess -import com.inkapplications.ack.android.settings.buildinfo.BuildInfoFactory -import com.inkapplications.ack.android.settings.buildinfo.BuildInfoState -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* -import javax.inject.Inject - -/** - * Android Viewmodel for storing the state of the settings screen. - */ -@OptIn(ExperimentalCoroutinesApi::class) -@HiltViewModel -class SettingsViewModel @Inject constructor( - settingsAccess: SettingsAccess, - settingsViewStateFactory: SettingsViewStateFactory, - buildDataAccess: BuildDataAccess, - buildInfoFactory: BuildInfoFactory, -): ViewModel() { - private val visibility = MutableStateFlow(SettingVisibility.Visible) - - val settingsList = visibility.flatMapLatest { visibility -> - settingsAccess.settingsGroups(visibility) - }.map { - settingsViewStateFactory.viewState(it) - }.stateIn(viewModelScope, SharingStarted.Eagerly, SettingsListViewState.Initial) - - val licenseState = settingsAccess.licenseData - .map { settingsViewStateFactory.licenseState(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, LicenseViewState.Initial) - - val buildInfoState: StateFlow = buildDataAccess.buildData - .map { buildInfoFactory.buildInfo(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, BuildInfoState.Initial) - - fun showAdvanced(value: Boolean) { - visibility.value = if (value) { - SettingVisibility.Advanced - } else { - SettingVisibility.Visible - } - } - - fun showDev() { - visibility.getAndUpdate { - if (it == SettingVisibility.Advanced) SettingVisibility.Dev else it - } - } -} - diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsViewStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsViewStateFactory.kt deleted file mode 100644 index 56f166a1..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsViewStateFactory.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.inkapplications.ack.android.settings - -import dagger.Reusable -import javax.inject.Inject - -/** - * Creates view state objects based on settings data. - */ -@Reusable -class SettingsViewStateFactory @Inject constructor() { - /** - * Create a view state object based on the user's current license data. - */ - fun licenseState(data: LicenseData): LicenseViewState { - return when { - data.address == null -> LicenseViewState.Unconfigured - data.passcode == null -> LicenseViewState.Registered(data.address.toString()) - else -> LicenseViewState.Verified(data.address.toString()) - } - } - - /** - * Create a list state from the current settings data. - */ - fun viewState(data: SettingsListData): SettingsListViewState { - return SettingsListViewState.Loaded( - settingsList = data.settings, - advancedVisible = data.visibility >= SettingVisibility.Advanced, - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsWriteAccess.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsWriteAccess.kt deleted file mode 100644 index bec02968..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsWriteAccess.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.inkapplications.ack.android.settings - -/** - * Provides access to storing key/value preferences for the application. - */ -interface SettingsWriteAccess { - fun setString(setting: StringSetting, value: String) - fun setInt(setting: IntSetting, value: Int) - fun setBoolean(setting: BooleanSetting, value: Boolean) -} - -fun SettingsWriteAccess.setData(setting: TransformableSetting, value: DATA) { - return when (setting) { - is IntBackedSetting -> setInt(setting, setting.storageTransformer.toStorage(value)) - is StringBackedSetting -> setString(setting, setting.storageTransformer.toStorage(value)) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SharedPreferenceSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SharedPreferenceSettings.kt deleted file mode 100644 index d00e473a..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SharedPreferenceSettings.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.inkapplications.ack.android.settings - -import android.content.SharedPreferences -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.channels.trySendBlocking -import kotlinx.coroutines.flow.* -import javax.inject.Inject - -/** - * Provides read + write access to settings via Android's SharedPreferences. - */ -class SharedPreferenceSettings @Inject constructor( - private val preferences: SharedPreferences -): SettingsReadAccess, SettingsWriteAccess { - private val updates = callbackFlow { - val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> - trySendBlocking(key) - } - - preferences.registerOnSharedPreferenceChangeListener(listener) - - awaitClose { - preferences.unregisterOnSharedPreferenceChangeListener(listener) - } - } - - override fun observeStringState(setting: StringSetting): Flow { - return updates - .filter { it == setting.key || it == null } - .onStart { emit(setting.key) } - .map { preferences.getString(setting.key, null) } - } - - override fun setString(setting: StringSetting, value: String) = preferences.apply { putString(setting.key, value) } - - override fun observeIntState(setting: IntSetting): Flow { - return updates - .filter { it == setting.key || it == null } - .onStart { emit(setting.key) } - .map { preferences.getOptionalInt(setting.key) } - } - - override fun observeBooleanState(setting: BooleanSetting): Flow { - return updates - .filter { it == setting.key || it == null } - .onStart { emit(setting.key) } - .map { preferences.getOptionalBoolean(setting.key) } - } - - private fun SharedPreferences.getOptionalInt(key: String): Int? { - return ifContains(key) { getInt(key, -1) } - } - - private fun SharedPreferences.getOptionalBoolean(key: String): Boolean? { - return ifContains(key) { getBoolean(key, false) } - } - - private fun SharedPreferences.ifContains(key: String, action: () -> T): T? { - return if (contains(key)) action() else null - } - - override fun setInt(setting: IntSetting, value: Int) = preferences.apply { putInt(setting.key, value) } - - override fun setBoolean(setting: BooleanSetting, value: Boolean) = preferences.apply { putBoolean(setting.key, value) } - - private fun Flow.requireKey(): Flow> = map { key -> - if (preferences.contains(key)) Result.success(key) - else Result.failure(IllegalArgumentException("No preference contained for: $key")) - } - - private inline fun SharedPreferences.apply(modifications: SharedPreferences.Editor.() -> Unit) { - edit().apply { modifications() }.apply() - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/TransformableSetting.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/TransformableSetting.kt deleted file mode 100644 index 2cd4d6fb..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/TransformableSetting.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.settings - -import com.inkapplications.ack.android.settings.transformer.Transformer - -/** - * A setting with a transformer to use for going between primitives and complex types. - */ -sealed interface TransformableSetting { - /** - * Transformer used to store the typed data structure into settings. - */ - val storageTransformer: Transformer - - /** - * A default value for the setting, in its data format. - */ - val defaultData: DATA -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UsageAgreement.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UsageAgreement.kt deleted file mode 100644 index d4648e7f..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UsageAgreement.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.inkapplications.ack.android.settings.agreement - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun UsageAgreement() { - Column { - Text( - text = stringResource(R.string.usage_legal_services_title), - style = AckTheme.typography.h2, - ) - Spacer(Modifier.height(AckTheme.spacing.item)) - Text( - text = stringResource(R.string.usage_legal_services_section1), - ) - Text( - text = stringResource(R.string.usage_legal_services_section2), - ) - - Spacer(Modifier.height(AckTheme.spacing.content)) - - Text( - text = stringResource(R.string.usage_data_privacy_title), - style = AckTheme.typography.h2, - ) - Spacer(Modifier.height(AckTheme.spacing.item)) - Text( - text = stringResource(R.string.usage_data_privacy_section1), - ) - Spacer(Modifier.height(AckTheme.spacing.item)) - Text( - text = stringResource(R.string.usage_data_privacy_section2), - ) - - Spacer(Modifier.height(AckTheme.spacing.content)) - - Text( - text = stringResource(R.string.usage_warranty_title), - style = AckTheme.typography.h2, - ) - Spacer(Modifier.height(AckTheme.spacing.item)) - Text( - text = stringResource(R.string.usage_warranty_section1), - ) - - Spacer(Modifier.height(AckTheme.spacing.content)) - - Text( - text = stringResource(R.string.usage_rights_title), - style = AckTheme.typography.h2, - ) - Spacer(Modifier.height(AckTheme.spacing.item)) - Text( - text = stringResource(R.string.usage_rights_section1), - ) - Text( - text = stringResource(R.string.usage_rights_section2), - ) - Text( - text = stringResource(R.string.usage_rights_section3), - ) - Text( - text = stringResource(R.string.usage_rights_section4), - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UsageAgreementReviewScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UsageAgreementReviewScreen.kt deleted file mode 100644 index 22507578..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UsageAgreementReviewScreen.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.inkapplications.ack.android.settings.agreement - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.NavigationRow -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun UsageAgreementReviewScreen( - onBackPressed: () -> Unit, -) = AckScreen { - Column { - NavigationRow( - title = stringResource(R.string.usage_title), - onBackPressed = onBackPressed, - ) - Column(Modifier.verticalScroll(rememberScrollState()).fillMaxHeight().padding(AckTheme.spacing.gutter)) { - UsageAgreement() - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UserAgreementActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UserAgreementActivity.kt deleted file mode 100644 index eec5dd2a..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/agreement/UserAgreementActivity.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.inkapplications.ack.android.settings.agreement - -import androidx.activity.compose.setContent -import com.inkapplications.android.extensions.ExtendedActivity -import kimchi.Kimchi - -/** - * Displays the user-agreement for the application. - * - * Note that this does not have a prompt to agree/disagree like seen in - * the onboarding screens. It is simply for informational purposes. - */ -class UserAgreementActivity: ExtendedActivity() { - override fun onCreate() { - super.onCreate() - Kimchi.trackScreen("user_agreement") - - setContent { - UsageAgreementReviewScreen(onBackPressedDispatcher::onBackPressed) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildData.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildData.kt deleted file mode 100644 index c22ad40c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildData.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.inkapplications.ack.android.settings.buildinfo - -/** - * Raw data about the current app build and its environment. - */ -data class BuildData( - /** - * Android build type, ie. debug/release. - */ - val buildType: String, - - /** - * Readable version name. - */ - val versionName: String, - - /** - * Canonical version code. - */ - val versionCode: Int, - - /** - * Git commit hash, if specified. - */ - val commit: String?, - - /** - * Whether or not the build was configured to use play services. - */ - val usePlayServices: Boolean, - - /** - * Whether or not play services is available on the device. - */ - val playServicesAvailable: Boolean, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildDataAccess.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildDataAccess.kt deleted file mode 100644 index 66418657..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildDataAccess.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.inkapplications.ack.android.settings.buildinfo - -import android.content.Context -import com.google.android.gms.common.ConnectionResult -import com.google.android.gms.common.GoogleApiAvailability -import com.inkapplications.ack.android.BuildConfig -import dagger.Reusable -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf -import javax.inject.Inject - -/** - * Provides access to build and application runtime information. - */ -@Reusable -class BuildDataAccess @Inject constructor( - googleApiAvailability: GoogleApiAvailability, - context: Context, -) { - val buildData: Flow = flowOf(BuildData( - buildType = BuildConfig.BUILD_TYPE, - versionName = BuildConfig.VERSION_NAME, - versionCode = BuildConfig.VERSION_CODE, - commit = BuildConfig.COMMIT, - usePlayServices = BuildConfig.USE_GOOGLE_SERVICES, - playServicesAvailable = googleApiAvailability.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS, - )) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfo.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfo.kt deleted file mode 100644 index 73aecb40..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfo.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.inkapplications.ack.android.settings.buildinfo - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.android.extensions.compose.longClickable - -/** - * A column of information text about the build. - */ -@Composable -fun BuildInfo( - buildInfo: BuildInfoState, - modifier: Modifier = Modifier, - onVersionLongPress: () -> Unit = {}, -) = Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier) { - when (buildInfo) { - BuildInfoState.Initial -> BuildString( - text = stringResource(R.string.app_name_short), - onLongPress = onVersionLongPress, - ) - is BuildInfoState.Debug -> { - BuildString(stringResource(R.string.application_version_debug), onVersionLongPress) - } - is BuildInfoState.Release -> { - BuildString( - text = buildInfo.versionStatment, - onLongPress = onVersionLongPress, - ) - } - } - if (buildInfo is BuildInfoState.ServiceAvailabilityInfo) { - when (buildInfo.playServices) { - BuildInfoState.ServiceState.Unavailable -> Text(stringResource(R.string.application_version_qualifier_play_unavailable)) - BuildInfoState.ServiceState.Unconfigured -> Text(stringResource(R.string.application_version_qualifier_play_unconfigured)) - BuildInfoState.ServiceState.Available -> {} - } - } -} - -@Composable -private fun BuildString( - text: String, - onLongPress: (() -> Unit)? = null, -) { - Text( - text = text, - style = AckTheme.typography.caption, - modifier = Modifier - .let { if (onLongPress != null) it.longClickable(onLongPress) else it } - .padding(AckTheme.spacing.clickSafety) - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoFactory.kt deleted file mode 100644 index 40620f97..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoFactory.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.inkapplications.ack.android.settings.buildinfo - -import com.inkapplications.ack.android.R -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import kimchi.logger.KimchiLogger -import javax.inject.Inject - -/** - * Create a view state based on current build data. - */ -@Reusable -class BuildInfoFactory @Inject constructor( - private val stringResources: StringResources, - private val logger: KimchiLogger, -) { - fun buildInfo(data: BuildData): BuildInfoState { - val playServices = when { - !data.usePlayServices -> BuildInfoState.ServiceState.Unconfigured - !data.playServicesAvailable -> BuildInfoState.ServiceState.Unavailable - else -> BuildInfoState.ServiceState.Available - } - if (data.buildType == "debug") { - return BuildInfoState.Debug(playServices) - } - - return BuildInfoState.Release( - versionStatment = stringResources.getString( - key = R.string.application_version_full, - arguments = arrayOf( - data.versionName, - data.versionCode.toString(), - data.commit?.take(7) ?: stringResources.getString(R.string.application_version_commit_missing).also { - logger.error("Release Commit without Commit Hash") - }, - ) - ), - playServices = playServices - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoState.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoState.kt deleted file mode 100644 index 787fb110..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoState.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.inkapplications.ack.android.settings.buildinfo - -/** - * View state for the build info composable - */ -sealed interface BuildInfoState { - /** - * Initial state before data has been loaded. - */ - object Initial: BuildInfoState - - /** - * Debug build info, limited useful information. - */ - data class Debug( - override val playServices: ServiceState, - ): BuildInfoState, ServiceAvailabilityInfo - - /** - * Release build info with full details. - */ - data class Release( - val versionStatment: String, - override val playServices: ServiceState - ): BuildInfoState, ServiceAvailabilityInfo - - /** - * Availability descriptor for services on the device. - */ - sealed interface ServiceAvailabilityInfo { - /** - * Availability of Google Play Services - */ - val playServices: ServiceState - } - - /** - * Availability states for a service on the device. - */ - enum class ServiceState { - /** - * Indicates that the service is available and usable. - */ - Available, - - /** - * Indicates that the device does not support this feature. - */ - Unavailable, - - /** - * Indicates that the feature was not configured or disabled at build time. - */ - Unconfigured, - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditActivity.kt deleted file mode 100644 index 7c768454..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditActivity.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.inkapplications.ack.android.settings.license - -import androidx.activity.compose.setContent -import androidx.compose.runtime.collectAsState -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.settings.SettingsAccess -import com.inkapplications.android.extensions.ExtendedActivity -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi -import kimchi.analytics.Property -import javax.inject.Inject - -/** - * Displays an edit-form for editing the user's licens after onboarding. - */ -@AndroidEntryPoint -class LicenseEditActivity: ExtendedActivity() { - @Inject - lateinit var settingsAccess: SettingsAccess - - @Inject - lateinit var validator: LicensePromptValidator - - override fun onCreate() { - super.onCreate() - Kimchi.trackScreen("license_edit") - - setContent { - val viewModel: LicenseEditViewModel = hiltViewModel() - val state = viewModel.state.collectAsState().value - - when (state) { - LicenseEditState.Initial -> {} - is LicenseEditState.Editable -> LicensePromptScreen( - initialValues = state.initialValues, - validator = validator, - onContinue = ::onContinue - ) - } - - } - } - - private fun onContinue(values: LicensePromptFieldValues) { - Kimchi.trackEvent("license_update", listOf( - Property.IntProperty("license_callsign_provided", if (values.callsign.isBlank()) 0 else 1), - Property.IntProperty("license_passcode_provided", if (values.passcode.isBlank()) 0 else 1), - )) - settingsAccess.setLicense(values) - finish() - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditState.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditState.kt deleted file mode 100644 index 6f6e0dda..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditState.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.settings.license - -/** - * State of the license edit screen. - */ -sealed interface LicenseEditState { - /** - * Initial state of the screen before data has been loaded. - */ - object Initial: LicenseEditState - - /** - * State of the screen when the user's existing license is loaded. - */ - data class Editable( - val initialValues: LicensePromptFieldValues, - ): LicenseEditState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditViewModel.kt deleted file mode 100644 index 3d2f5528..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicenseEditViewModel.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.inkapplications.ack.android.settings.license - -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.settings.SettingsAccess -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android viewmodel containing the current state of the license edit screen. - */ -@HiltViewModel -class LicenseEditViewModel @Inject constructor( - settingsAccess: SettingsAccess, -): androidx.lifecycle.ViewModel() { - val state = settingsAccess.licensePromptFieldValues - .map { LicenseEditState.Editable(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, LicenseEditState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePrompt.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePrompt.kt deleted file mode 100644 index cb1c3b8a..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePrompt.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.inkapplications.ack.android.settings.license - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.Button -import androidx.compose.material.Text -import androidx.compose.material.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.input.KeyboardType -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun LicensePromptScreen( - initialValues: LicensePromptFieldValues, - validator: LicensePromptValidator, - onContinue: (LicensePromptFieldValues) -> Unit, -) = AckScreen { - Column ( - modifier = Modifier - .padding( - top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), - bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() - ) - .padding(AckTheme.spacing.gutter), - ) { - Text( - "License Info", - style = AckTheme.typography.h1, - ) - Spacer(Modifier.height(AckTheme.spacing.item)) - Text("If you have a radio license, enter the information below to enable transmit and internet services.") - Spacer(Modifier.height(AckTheme.spacing.content)) - - val callsign = rememberSaveable { mutableStateOf(initialValues.callsign) } - val passcode = rememberSaveable { mutableStateOf(initialValues.passcode) } - val callsignError = rememberSaveable { mutableStateOf(null) } - val passcodeError = rememberSaveable { mutableStateOf(null) } - - TextField( - value = callsign.value, - label = { Text("Callsign") }, - onValueChange = { callsign.value = it; passcode.value = "" }, - isError = callsignError.value != null, - modifier = Modifier.fillMaxWidth(), - ) - if (callsignError.value != null) Text(callsignError.value.orEmpty(), style = AckTheme.typography.errorCaption) - Spacer(Modifier.height(AckTheme.spacing.item)) - TextField( - value = passcode.value, - label = { Text("APRS-IS Passcode") }, - onValueChange = { passcode.value = it }, - enabled = callsign.value.isNotBlank(), - isError = passcodeError.value != null, - singleLine = true, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - modifier = Modifier.fillMaxWidth(), - ) - if (passcodeError.value != null) Text(passcodeError.value.orEmpty(), style = AckTheme.typography.errorCaption) - Spacer(Modifier.weight(1f)) - Button( - onClick = { - callsignError.value = validator.getLicenseError(callsign.value) - passcodeError.value = validator.getPasscodeError(callsign.value, passcode.value) - if (validator.isValid(callsign.value, passcode.value)) { - onContinue(LicensePromptFieldValues(callsign.value, passcode.value)) - } - }, - modifier = Modifier.fillMaxWidth().padding(top = AckTheme.spacing.item), - ) { - if (callsign.value.isBlank() && passcode.value.isBlank()) { - Text("Skip") - } else { - Text("Continue") - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePromptFieldValues.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePromptFieldValues.kt deleted file mode 100644 index 27b94d54..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePromptFieldValues.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.inkapplications.ack.android.settings.license - -/** - * Form data for the license prompt fields. - */ -data class LicensePromptFieldValues( - val callsign: String, - val passcode: String, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePromptValidator.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePromptValidator.kt deleted file mode 100644 index 7a7b5f77..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePromptValidator.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.inkapplications.ack.android.settings.license - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.connection.ConnectionSettings -import com.inkapplications.ack.android.input.ConvertibleOptionalIntValidator -import com.inkapplications.ack.android.input.ValidationResult -import com.inkapplications.ack.client.generatePasscode -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import kimchi.logger.KimchiLogger -import javax.inject.Inject - -@Reusable -class LicensePromptValidator @Inject constructor( - private val connectionSettings: ConnectionSettings, - private val intValidator: ConvertibleOptionalIntValidator, - private val stringResources: StringResources, - private val logger: KimchiLogger, -) { - fun getLicenseError(license: String): String? { - return connectionSettings.address.validator - .validate(license) - .let { (it as? ValidationResult.Error)?.message } - } - - fun getPasscodeError(license: String, passcode: String): String? { - val fieldValidation = intValidator.validate(passcode) - if (fieldValidation is ValidationResult.Error) return fieldValidation.message - - val converted = connectionSettings.passcode.fieldTransformer.toStorage(passcode) - val inputValidation = connectionSettings.passcode.inputValidator.validate(converted) - val data = connectionSettings.passcode.storageTransformer.toData(converted) - val actual = generatePasscode(license) - - return when { - inputValidation is ValidationResult.Error -> inputValidation.message.also { - logger.debug("Passcode input validation failed") - } - data == null -> null - converted != actual -> stringResources.getString(R.string.connection_setting_passcode_incorrect) - else -> null - } - } - - fun isValid(license: String, passcode: String): Boolean { - return getLicenseError(license) == null && getPasscodeError(license, passcode) == null - } -} - diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/EnumTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/EnumTransformer.kt deleted file mode 100644 index 3907e03c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/EnumTransformer.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -/** - * Creates a transformer for an enum type, stored by enm name. - */ -inline fun > enumTransformer(): Transformer { - return object: Transformer { - override fun toStorage(data: T): String = data.name - override fun toData(storage: String): T = enumValueOf(storage) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/IntFieldTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/IntFieldTransformer.kt deleted file mode 100644 index a1aef5bc..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/IntFieldTransformer.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -/** - * Transform a string to an integer. - */ -object IntFieldTransformer: Transformer { - override fun toStorage(data: String): Int = data.toInt() - override fun toData(storage: Int): String = storage.toString() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MileTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MileTransformer.kt deleted file mode 100644 index 0550dbe6..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MileTransformer.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import inkapplications.spondee.measure.Length -import inkapplications.spondee.measure.us.miles -import inkapplications.spondee.measure.us.toMiles -import inkapplications.spondee.structure.roundToInt - -/** - * Transform a length to a primitive of Miles. - */ -object MileTransformer: Transformer { - override fun toStorage(data: Length): Int = data.toMiles().roundToInt() - override fun toData(storage: Int): Length = storage.miles -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MillisecondTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MillisecondTransformer.kt deleted file mode 100644 index 4b439749..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MillisecondTransformer.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import kotlin.time.Duration -import kotlin.time.Duration.Companion.milliseconds - -/** - * Transform a duration to a primitive stored in milliseconds. - * - * Note: This is stored as an Int, so this should not be used for large - * duration values. - */ -object MillisecondTransformer: Transformer { - override fun toStorage(data: Duration): Int = data.inWholeMilliseconds.toInt() - override fun toData(storage: Int): Duration = storage.milliseconds -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MinuteTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MinuteTransformer.kt deleted file mode 100644 index 2f7536cb..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/MinuteTransformer.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import kotlin.time.Duration -import kotlin.time.Duration.Companion.minutes - -/** - * Transform a duration to a primitive stored in minutes. - */ -object MinuteTransformer: Transformer { - override fun toStorage(data: Duration): Int = data.inWholeMinutes.toInt() - override fun toData(storage: Int): Duration = storage.minutes -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/OptionalIntTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/OptionalIntTransformer.kt deleted file mode 100644 index b6a24efd..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/OptionalIntTransformer.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -/** - * Convert a string to an integer, using a default value if the string is blank. - * - * @param nullValue The value to use if the string is blank. - */ -class OptionalIntTransformer(val nullValue: Int = -1): Transformer { - override fun toStorage(data: String): Int = data.takeIf { it.isNotBlank() }?.toInt() ?: nullValue - override fun toData(storage: Int): String = storage.takeIf { it != nullValue }?.toString().orEmpty() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/PercentageTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/PercentageTransformer.kt deleted file mode 100644 index 4eaa07bd..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/PercentageTransformer.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import inkapplications.spondee.scalar.Percentage -import inkapplications.spondee.scalar.percent -import inkapplications.spondee.scalar.toWholePercentage -import inkapplications.spondee.structure.roundToInt - -/** - * Transform a percentage object to a whole integer value. - */ -object PercentageTransformer: Transformer { - override fun toStorage(data: Percentage): Int = data.toWholePercentage().roundToInt() - override fun toData(storage: Int): Percentage = storage.percent -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/SentinelOptionalTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/SentinelOptionalTransformer.kt deleted file mode 100644 index 704c5247..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/SentinelOptionalTransformer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -/** - * Wrap a transformer, making it optional if the stored value matches a key. - */ -class SentinelOptionalTransformer( - private val sentinelValue: STORAGE, - private val delegate: Transformer, -): Transformer { - override fun toStorage(data: DATA?): STORAGE { - return data?.let(delegate::toStorage) ?: sentinelValue - } - - override fun toData(storage: STORAGE): DATA? { - return storage?.takeIf { it != sentinelValue }?.let(delegate::toData) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/StationAddressTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/StationAddressTransformer.kt deleted file mode 100644 index 78764ea3..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/StationAddressTransformer.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import com.inkapplications.ack.structures.station.StationAddress -import com.inkapplications.ack.structures.station.toStationAddress - -/** - * Transform a station callsign and ssid to a string primitive. - */ -object StationAddressTransformer: Transformer { - override fun toStorage(data: StationAddress): String = data.toString() - override fun toData(storage: String): StationAddress = storage.toStationAddress() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/Transformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/Transformer.kt deleted file mode 100644 index fcc18d73..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/Transformer.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -/** - * Transformer to change settings to/from their storage type. - * - * Note: Data is expected to be validated before being passed to the - * transformer. - */ -interface Transformer { - /** - * Change a data structure into a type appropriate for storing. - */ - fun toStorage(data: DATA): STORAGE - - /** - * Change a data structure into a type appropriate for application use. - */ - fun toData(storage: STORAGE): DATA -} - -/** - * Combines two transformers, allowing chaining. - */ -private class CompositeTransformer( - val first: Transformer, - val second: Transformer -): Transformer { - override fun toStorage(data: ORIGIN): END { - return second.toStorage(first.toStorage(data)) - } - - override fun toData(storage: END): ORIGIN { - return first.toData(second.toData(storage)) - } -} - -/** - * Chain two transformers together. - */ -fun Transformer.then(second: Transformer): Transformer { - return CompositeTransformer(this, second) -} - -/** - * Chain two transformers together. - */ -operator fun Transformer.plus(second: Transformer): Transformer { - return this.then(second) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/TrimmingTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/TrimmingTransformer.kt deleted file mode 100644 index b86cd32c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/transformer/TrimmingTransformer.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -/** - * Trim whitespace from a string in both transformation directions. - */ -object TrimmingTransformer: Transformer { - override fun toStorage(data: String): String { - return data.trim() - } - - override fun toData(storage: String): String { - return storage.trim() - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/ApplicationInitializer.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/ApplicationInitializer.kt deleted file mode 100644 index c99d1d6b..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/ApplicationInitializer.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.inkapplications.ack.android.startup - -import android.app.Application - -interface ApplicationInitializer { - val priority: Priority get() = Priority.NORMAL - - suspend fun initialize(application: Application) - - enum class Priority { - HIGH, - NORMAL, - LOW, - } -} - -/** - * Create a static initializer from a lambda. - */ -fun ApplicationInitializer( - priority: ApplicationInitializer.Priority = ApplicationInitializer.Priority.NORMAL, - init: Application.() -> Unit -): ApplicationInitializer { - return object: ApplicationInitializer { - override suspend fun initialize(application: Application) { - application.init() - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/CompositeApplicationInitializer.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/CompositeApplicationInitializer.kt deleted file mode 100644 index 62388d6c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/CompositeApplicationInitializer.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.inkapplications.ack.android.startup - -import android.app.Application -import dagger.Reusable -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.coroutineScope -import javax.inject.Inject - -@Reusable -class CompositeApplicationInitializer @Inject constructor( - private val initializers: @JvmSuppressWildcards Set, - private val logger: KimchiLogger -): ApplicationInitializer { - override suspend fun initialize(application: Application) { - logger.trace("Initializing Application with ${initializers.size} initializers.") - coroutineScope { - val jobs = initializers - .sortedBy { it.priority } - .mapIndexed { index, initializer -> - async { - initializer.initialize(application) - logger.trace("#$index: <${initializer.javaClass.simpleName}> complete.") - } - } - jobs.awaitAll() - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/InitJob.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/InitJob.kt deleted file mode 100644 index 01500312..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/InitJob.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.inkapplications.ack.android.startup - -import android.app.Application -import kotlinx.coroutines.* - -/** - * Contains and executes the Initialization Job for the application. - */ -class InitJob private constructor( - private val initializer: ApplicationInitializer, - private val job: CompletableJob, -): Job by job { - constructor(initializer: ApplicationInitializer): this(initializer, Job()) - - private val scope = CoroutineScope(this + Dispatchers.Main) - - fun init(application: Application) { - if (job.isCompleted) return - scope.launch { - initializer.initialize(application) - job.complete() - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/KimchiInitializer.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/KimchiInitializer.kt deleted file mode 100644 index 7cdc6b46..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/KimchiInitializer.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.inkapplications.ack.android.startup - -import com.inkapplications.ack.android.BuildConfig -import com.inkapplications.android.extensions.LifecycleLogger -import kimchi.Kimchi -import kimchi.KimchiLoggerAnalytics -import kimchi.bridge.firebase.analytics.FirebaseAnalyticsAdapter -import kimchi.bridge.firebase.crashlytics.FirebaseCrashlyticsExceptionAdapter -import kimchi.bridge.firebase.crashlytics.FirebaseCrashlyticsLogMessageAdapter -import kimchi.logger.LogLevel -import kimchi.logger.defaultWriter -import kimchi.logger.withThreshold - -/** - * Initializes the Kimchi Logging Framework. - */ -val KimchiInitializer = ApplicationInitializer(ApplicationInitializer.Priority.HIGH) { - Kimchi.addLog(defaultWriter) - if (BuildConfig.USE_GOOGLE_SERVICES) { - Kimchi.addLog(FirebaseCrashlyticsLogMessageAdapter().withThreshold(LogLevel.INFO)) - Kimchi.addLog(FirebaseCrashlyticsExceptionAdapter()) - Kimchi.addAnalytics(FirebaseAnalyticsAdapter()) - } - Kimchi.addAnalytics(KimchiLoggerAnalytics) - - registerActivityLifecycleCallbacks(LifecycleLogger { - Kimchi.trace(it) - }) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/NoOpInitializer.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/NoOpInitializer.kt deleted file mode 100644 index 1952a00e..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/NoOpInitializer.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.inkapplications.ack.android.startup - -/** - * An Initializer implementation that does nothing. - * - * This can be used for testing or as a stand in for disabled services. - */ -val NoOpInitializer = ApplicationInitializer(ApplicationInitializer.Priority.LOW) {} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupActivity.kt deleted file mode 100644 index d1609931..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupActivity.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.inkapplications.ack.android.startup - -import android.os.Bundle -import androidx.activity.compose.setContent -import com.inkapplications.ack.android.capture.CaptureActivity -import com.inkapplications.ack.android.onboard.OnboardActivity -import com.inkapplications.ack.android.onboard.OnboardingStateAccess -import com.inkapplications.android.extensions.ExtendedActivity -import com.inkapplications.android.startActivity -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.launch -import javax.inject.Inject -import kotlin.time.Duration.Companion.seconds - -/** - * A screen for initializing application settings. - */ -@AndroidEntryPoint -class StartupActivity: ExtendedActivity() { - /** - * Delay time for the splash screen. - * - * This is so the splash screen doesn't flash for too short of a time and - * appear as jank. Since the initializers are run asynchronously, this will - * not increase the load time, but set a minimum load time. - */ - private val delayTime = .5.seconds - - @Inject - lateinit var initJob: InitJob - - @Inject - lateinit var onboardingStateAccess: OnboardingStateAccess - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setContent { - StartupScreen() - } - } - - override fun onStart() { - super.onStart() - foregroundScope.launch { - delay(delayTime) - initJob.join() - - if (onboardingStateAccess.finished.first()) { - startActivity(CaptureActivity::class) - } else { - startActivity(OnboardActivity::class) - } - finish() - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupModule.kt deleted file mode 100644 index 1cb92e51..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupModule.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.inkapplications.ack.android.startup - -import android.app.Application -import com.inkapplications.ack.android.capture.service.CaptureServiceNotifications -import com.inkapplications.ack.android.maps.MapsImplementation -import dagger.Binds -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.ElementsIntoSet -import dagger.multibindings.Multibinds -import javax.inject.Singleton - -@Module(includes = [StartupModuleBindings::class]) -@InstallIn(SingletonComponent::class) -class StartupModule { - @Singleton - @Provides - fun initJob(initializer: ApplicationInitializer) = InitJob(initializer) - - @Provides - @ElementsIntoSet - fun initializers( - captureService: CaptureServiceNotifications - ): Set = setOf( - object: ApplicationInitializer { - override suspend fun initialize(application: Application) { - MapsImplementation.initialize(application) - } - }, - KimchiInitializer, - captureService, - ) -} - -@Module -private abstract class StartupModuleBindings { - @Multibinds - abstract fun initializerBinding(): @JvmSuppressWildcards Set - - @Binds - abstract fun initializer(composite: CompositeApplicationInitializer): ApplicationInitializer -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupScreen.kt deleted file mode 100644 index 988f3164..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupScreen.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.inkapplications.ack.android.startup - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.MutableTransitionState -import androidx.compose.animation.fadeIn -import androidx.compose.foundation.layout.* -import androidx.compose.material.Icon -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.settings.buildinfo.BuildInfo -import com.inkapplications.ack.android.settings.buildinfo.BuildInfoState -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun StartupScreen( - viewModel: StartupViewModel = hiltViewModel() -) = AckScreen { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .padding(AckTheme.spacing.gutter) - .fillMaxHeight() - .fillMaxWidth() - ) { - val buildInfoState = viewModel.buildInfoState.collectAsState() - val visible = remember { MutableTransitionState(false) } - - if (buildInfoState.value !is BuildInfoState.Initial) { - visible.targetState = true - } - - AnimatedVisibility( - visibleState = visible, - enter = fadeIn(), - ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Icon( - painterResource(R.drawable.wave), - contentDescription = null, - tint = AckTheme.colors.accent, - modifier = Modifier.padding(bottom = AckTheme.spacing.content) - ) - BuildInfo(buildInfoState.value) - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupViewModel.kt deleted file mode 100644 index e46abcbb..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/startup/StartupViewModel.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.inkapplications.ack.android.startup - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.settings.buildinfo.BuildDataAccess -import com.inkapplications.ack.android.settings.buildinfo.BuildInfoFactory -import com.inkapplications.ack.android.settings.buildinfo.BuildInfoState -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android viewmodel for storing the state loaded on the startup screen. - */ -@HiltViewModel -class StartupViewModel @Inject constructor( - buildDataAccess: BuildDataAccess, - buildInfoFactory: BuildInfoFactory, -): ViewModel() { - val buildInfoState: StateFlow = buildDataAccess.buildData - .map { buildInfoFactory.buildInfo(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, BuildInfoState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/InsightViewState.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/InsightViewState.kt deleted file mode 100644 index 2c717b88..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/InsightViewState.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.structures.TelemetryValues - -/** - * Summary data for a particular station to display to the user - */ -data class InsightViewState( - val name: String = "", - val comment: String? = null, - val temperature: String? = null, - val wind: String? = null, - val altitude: String? = null, - val telemetryValues: TelemetryValues? = null, - val telemetrySequence: String? = null, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationActivity.kt deleted file mode 100644 index af967d04..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationActivity.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.inkapplications.ack.android.station - -import android.app.Activity -import android.os.Bundle -import androidx.activity.compose.setContent -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.android.log.details.startLogInspectActivity -import com.inkapplications.ack.android.trackNavigation -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.android.extensions.ExtendedActivity -import com.inkapplications.android.startActivity -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi - -const val EXTRA_CALLSIGN = "aprs.station.extra.callsign" - -/** - * Displays information and recent packets for a particular station. - */ -@AndroidEntryPoint -class StationActivity: ExtendedActivity(), StationScreenController { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - Kimchi.trackScreen("station") - - setContent { - AckScreen { - StationScreen( - controller = this, - ) - } - } - } - - override fun onMapItemClicked(id: CaptureId?) { - Kimchi.trackEvent("station_map_item_click") - Kimchi.debug("Map Item Clicked: No-Op") - } - - override fun onLogItemClicked(item: LogItemViewState) { - Kimchi.trackEvent("station_log_item_click") - startLogInspectActivity(item.id) - } -} - -/** - * Start the station activity for the station with the given callsign. - * - * @param callsign The callsign of the station to display. - */ -fun Activity.startStationActivity(callsign: Callsign) { - Kimchi.trackNavigation("station") - startActivity(StationActivity::class) { - putExtra(EXTRA_CALLSIGN, callsign.canonical) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationData.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationData.kt deleted file mode 100644 index dd5f0441..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationData.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.data.CapturedPacket - -/** - * Data required to render the station screen. - */ -data class StationData( - val packets: List = emptyList(), - val metric: Boolean = false, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationEvents.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationEvents.kt deleted file mode 100644 index 4d5349a2..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationEvents.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.android.locale.LocaleSettings -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.observeBoolean -import com.inkapplications.ack.android.settings.observeInt -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.data.PacketStorage -import com.inkapplications.ack.structures.station.Callsign -import dagger.Reusable -import kimchi.logger.EmptyLogger -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flatMapLatest -import javax.inject.Inject - -@Reusable -class StationEvents @Inject constructor( - private val aprs: PacketStorage, - private val settings: SettingsReadAccess, - private val localeSettings: LocaleSettings, - private val stationSettings: StationSettings, - private val logger: KimchiLogger = EmptyLogger, -) { - suspend fun packet(id: CaptureId) = aprs.findById(id).first() - - fun stationData(callsign: Callsign): Flow { - logger.trace("Observing Station Data for: $callsign") - return settings.observeInt(stationSettings.recentStationEvents) - .flatMapLatest { aprs.findBySource(callsign, it.toLong()) } - .combine(settings.observeBoolean(localeSettings.preferMetric)) { packets, metric -> - StationData( - packets = packets, - metric = metric, - ) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationInsightViewStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationInsightViewStateFactory.kt deleted file mode 100644 index ca25391c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationInsightViewStateFactory.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.android.locale.format -import com.inkapplications.ack.android.log.SummaryFactory -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.capabilities.Commented -import com.inkapplications.ack.structures.capabilities.Report -import com.inkapplications.android.extensions.ViewStateFactory -import dagger.Reusable -import javax.inject.Inject - -/** - * Convert raw station data into data needed to render the insight view for a station. - */ -@Reusable -class StationInsightViewStateFactory @Inject constructor( - private val summaryFactory: SummaryFactory, -): ViewStateFactory { - override fun create(data: StationData): InsightViewState { - val firstWeatherData = data.packets.firstNotNullOfOrNull { it.parsed.data as? PacketData.Weather } - - return InsightViewState( - name = data.packets.first().parsed.route.source.callsign.canonical, - comment = data.packets.firstNotNullOfOrNull { (it.parsed.data as? Commented)?.comment }, - temperature = firstWeatherData?.temperature - ?.format(data.metric), - wind = firstWeatherData?.let { summaryFactory.createWindSummary(it.windData, data.metric) }, - altitude = data.packets.firstNotNullOfOrNull { it.parsed.data as? Report } - ?.altitude - ?.format(data.metric), - telemetryValues = data.packets.firstNotNullOfOrNull { it.parsed.data as? PacketData.TelemetryReport } - ?.data, - telemetrySequence = data.packets.firstNotNullOfOrNull { it.parsed.data as? PacketData.TelemetryReport } - ?.sequenceId, - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationModule.kt deleted file mode 100644 index 0d429eb0..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationModule.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.android.settings.SettingsProvider -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.IntoSet - -@Module -@InstallIn(SingletonComponent::class) -abstract class StationModule { - @Binds - @IntoSet - abstract fun settings(settings: StationSettings): SettingsProvider -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreen.kt deleted file mode 100644 index 69fac28b..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreen.kt +++ /dev/null @@ -1,142 +0,0 @@ -package com.inkapplications.ack.android.station - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.log.AprsLogItem -import com.inkapplications.ack.android.map.MarkerMap -import com.inkapplications.ack.android.ui.IconRow -import com.inkapplications.ack.android.ui.NavigationRow -import com.inkapplications.ack.android.ui.TelemetryTable -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun StationScreen( - viewModel: StationViewModel = hiltViewModel(), - controller: StationScreenController, -) { - val stationState = viewModel.stationState.collectAsState().value - if (stationState is StationViewState.Loaded) { - StationDetails(stationState, controller) - } -} - -@Composable -private fun StationDetails( - viewState: StationViewState.Loaded, - controller: StationScreenController, -) { - Column( - modifier = Modifier.verticalScroll(rememberScrollState()), - ) { - if (viewState.mapState.markers.isNotEmpty()) { - Column { - Box { - MarkerMap( - viewModel = viewState.mapState, - onMapItemClicked = controller::onMapItemClicked, - interactive = false, - modifier = Modifier.aspectRatio(16f / 9f), - ) - Box( - modifier = Modifier - .padding(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()) - ) { - IconButton( - onClick = controller::onBackPressed - ) { - Icon(Icons.Default.ArrowBack, stringResource(R.string.navigate_up)) - } - } - } - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(top = AckTheme.spacing.gutter) - ) { - Text( - viewState.insight.name, - style = AckTheme.typography.h1, - modifier = Modifier.padding( - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - ), - ) - } - } - } else { - Box( - Modifier - .padding( - top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), - ) - .padding( - start = AckTheme.spacing.gutter, - top = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - ) - ) { - NavigationRow( - title = { - Text( - viewState.insight.name, - style = AckTheme.typography.h1, - modifier = Modifier.padding( - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - ), - ) - }, - onBackPressed = controller::onBackPressed - ) - } - } - Column( - modifier = Modifier - .padding( - bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() - ) - .padding( - top = AckTheme.spacing.content, - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - bottom = AckTheme.spacing.gutter, - ), - ) { - if (viewState.insight.temperature != null) { - IconRow(Icons.Default.WbSunny, viewState.insight.temperature) - } - if (viewState.insight.wind != null) { - IconRow(Icons.Default.Air, viewState.insight.wind) - } - if (viewState.insight.altitude != null) { - IconRow(Icons.Default.Terrain, viewState.insight.altitude) - } - if (viewState.insight.comment != null) { - IconRow(Icons.Default.Comment, viewState.insight.comment) - } - if (viewState.insight.telemetryValues != null) { - TelemetryTable(viewState.insight.telemetryValues, viewState.insight.telemetrySequence) - } - Text( - text = stringResource(R.string.station_packet_list_title), - style = AckTheme.typography.h2, - modifier = Modifier.padding(vertical = AckTheme.spacing.content), - ) - viewState.packets.forEach { log -> - AprsLogItem(log, controller::onLogItemClicked) - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreenController.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreenController.kt deleted file mode 100644 index 77482763..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreenController.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.data.CaptureId - -/** - * Actions invoked on the station screen - */ -interface StationScreenController { - /** - * Invoked when the user presses the back button at the top of the page. - */ - fun onBackPressed() - - /** - * Invoked when the user clicks on a log item in the list of packets - * received for this station. - */ - fun onLogItemClicked(item: LogItemViewState) - - /** - * Invoked when the user clicks on a map marker. - * - * @param id The id of the map marker that was clicked. - */ - fun onMapItemClicked(id: CaptureId?) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationSettings.kt deleted file mode 100644 index bc2ed994..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationSettings.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.input.IntegerValidator -import com.inkapplications.ack.android.settings.* -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import javax.inject.Inject - -@Reusable -class StationSettings @Inject constructor( - stringResources: StringResources, -): SettingsProvider { - private val categoryName = stringResources.getString(R.string.station_settings_category) - - val showDebugData = BooleanSetting( - key = "station.data.debug", - name = stringResources.getString(R.string.station_settings_debug), - categoryName = categoryName, - defaultValue = false, - visibility = SettingVisibility.Dev, - ) - - val recentStationEvents = IntSetting( - key = "station.data.recent.limit", - name = stringResources.getString(R.string.station_settings_recent_limit), - categoryName = categoryName, - defaultValue = 10, - visibility = SettingVisibility.Advanced, - validator = IntegerValidator( - error = stringResources.getString(R.string.input_validator_positive_integer_error), - zeroInclusive = false, - ), - ) - - override val settings: List = listOf( - showDebugData, recentStationEvents - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationViewModel.kt deleted file mode 100644 index 149fcd05..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationViewModel.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.inkapplications.ack.android.station - -import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.android.log.LogItemViewStateFactory -import com.inkapplications.ack.android.maps.* -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.structures.capabilities.Mapable -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.android.extensions.ViewStateFactory -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android viewmodel to load state for the station screen. - */ -@HiltViewModel -class StationViewModel @Inject constructor( - savedState: SavedStateHandle, - stationEvents: StationEvents, - stationInsightViewStateFactory: StationInsightViewStateFactory, - logItemViewStateFactory: LogItemViewStateFactory, - markerViewStateFactory: ViewStateFactory, -): androidx.lifecycle.ViewModel() { - private val stationCallsign = savedState.get(EXTRA_CALLSIGN)!!.let(::Callsign) - val stationState = stationEvents.stationData(stationCallsign) - .map { data -> - StationViewState.Loaded( - insight = stationInsightViewStateFactory.create(data), - packets = data.packets.map { packet -> - logItemViewStateFactory.create(packet.id, packet.parsed, data.metric) - }, - mapState = data.packets.firstOrNull { it.parsed.data is Mapable } - .let { firstMapable -> - MapViewModel( - markers = firstMapable?.let { markerViewStateFactory.create(it) } - ?.let { listOf(it) } - .orEmpty(), - cameraPosition = (firstMapable?.parsed?.data as? Mapable)?.coordinates - ?.let { MapCameraPosition(it, ZoomLevels.ROADS) } - ?: CameraPositionDefaults.unknownLocation, - ) - } - ) - } - .stateIn(viewModelScope, SharingStarted.Eagerly, StationViewState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationViewState.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationViewState.kt deleted file mode 100644 index 7b821662..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationViewState.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.android.log.LogItemViewState -import com.inkapplications.ack.android.maps.MapViewModel - -sealed interface StationViewState { - object Initial: StationViewState - data class Loaded( - val insight: InsightViewState, - val packets: List, - val mapState: MapViewModel, - ): StationViewState -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/symbol/AndroidSymbolFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/symbol/AndroidSymbolFactory.kt deleted file mode 100644 index 76a5a0eb..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/symbol/AndroidSymbolFactory.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.graphics.Canvas -import android.graphics.Matrix -import com.inkapplications.ack.structures.Symbol -import com.inkapplications.ack.structures.symbolOf -import dagger.Reusable -import javax.inject.Inject - -/** - * Create a bitmap icon for an APRS symbol character. - */ -@Reusable -class AndroidSymbolFactory @Inject constructor( - private val context: Context, - private val locator: SymbolResourceLocator -): SymbolFactory { - private val resources = context.resources - - override val defaultSymbol by lazy { - createSymbol(symbolOf('"', '/')) - } - - override fun createSymbol(symbol: Symbol): Bitmap? { - val base = locator.getBaseResourceName(symbol).let(::findBitmap) - val overlay = locator.getOverlayResourceName(symbol)?.let(::findBitmap) - - return if (overlay == null) base else base?.withOverlay(overlay) - } - - private fun findBitmap(name: String): Bitmap? { - return resources.getIdentifier(name, "drawable", context.packageName) - .let { BitmapFactory.decodeResource(resources, it) } - } - - private fun Bitmap.withOverlay(other: Bitmap): Bitmap { - val bmOverlay = Bitmap.createBitmap(width, height, config ?: Bitmap.Config.ARGB_8888) - val canvas = Canvas(bmOverlay) - canvas.drawBitmap(this, Matrix(), null) - canvas.drawBitmap(other, 0f, 0f, null) - return bmOverlay - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolFactory.kt deleted file mode 100644 index 9022b2b7..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolFactory.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import android.graphics.Bitmap -import com.inkapplications.ack.structures.Symbol - -/** - * Create bitmaps for APRS Symbols. - */ -interface SymbolFactory { - val defaultSymbol: Bitmap? - fun createSymbol(symbol: Symbol): Bitmap? -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolModule.kt deleted file mode 100644 index 7f118242..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolModule.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -abstract class SymbolModule { - @Binds - abstract fun symbolFactory(symbolFactory: AndroidSymbolFactory): SymbolFactory -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolPrompt.kt b/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolPrompt.kt deleted file mode 100644 index bd8fe6e6..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolPrompt.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import androidx.compose.foundation.layout.* -import androidx.compose.material.ButtonDefaults -import androidx.compose.material.Surface -import androidx.compose.material.Text -import androidx.compose.material.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.ack.structures.Symbol - -/** - * Input prompt allowing the user to select a symbol. - */ -@Composable -fun SymbolPrompt( - title: String, - value: Symbol?, - onDismiss: () -> Unit, - onSubmit: (Symbol?) -> Unit, -) { - val currentSymbol = remember { mutableStateOf(value) } - - Dialog( - onDismissRequest = onDismiss, - ) { - Surface( - shape = AckTheme.shapes.corners, - ) { - Column( - modifier = Modifier.padding(AckTheme.spacing.gutter), - ) { - Text(title, style = AckTheme.typography.h2) - SymbolSelector( - onChange = { - currentSymbol.value = it - }, - default = currentSymbol.value, - modifier = Modifier.padding(vertical = AckTheme.spacing.item) - .align(Alignment.CenterHorizontally) - .sizeIn(maxWidth = 400.dp, maxHeight = 200.dp) - ) - - Row( - horizontalArrangement = Arrangement.End, - modifier = Modifier.fillMaxWidth().padding(top = AckTheme.spacing.item), - ) { - TextButton( - onClick = onDismiss, - colors = ButtonDefaults.textButtonColors( - contentColor = AckTheme.colors.foreground, - ), - modifier = Modifier.padding(end = AckTheme.spacing.item), - ) { - Text(stringResource(R.string.prompt_cancel)) - } - TextButton( - onClick = { - onSubmit(currentSymbol.value) - }, - ) { - Text(stringResource(R.string.prompt_save)) - } - } - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolResourceLocator.kt b/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolResourceLocator.kt deleted file mode 100644 index 10aa72e3..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolResourceLocator.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import com.inkapplications.ack.structures.Symbol -import dagger.Reusable -import kimchi.logger.KimchiLogger -import javax.inject.Inject - -private const val ALT_START = 96 -private const val OVERLAY_START = 207 -private const val PREFIX = "symbol_" -private const val CHAR_RANGE_START = '!' -private const val CHAR_RANGE_END = '~' -private const val ASC_0 = '0' -private const val ASC_9 = '9' -private const val ASC_A = 'A' -private const val ASC_Z = 'Z' -private const val FAULT_SYMBOL = 127.toChar() - -/** - * Translate a pair of APRS Symbol Chars to symbol resource names. - * - * The resource names are arbitrary and sequential as produced by an image - * slicer. They start at 0 and go up, with some empty symbols having been - * removed. - * The three tables (primary, offset and alphanumeric overlays) are offset - * by [ALT_START] and [OVERLAY_START]. i.e. the alternate symbols should start - * at the image number corresponding to [ALT_START] and so on. - * - * APRS Symbol format is defined here: http://www.aprs.org/symbols.html - * - * TL;DR – the first char is typically '/' or '\' designating the primary or - * secondary set of symbols, and the symbol is looked up by the second - * character's ASCII table position. If the first character is something other - * than '/' or '\' then it is indicating an overlay. - * - * This supports alphanumeric overlays, and will fall-back to just the alternate - * symbol if an unknown overlay is used. - */ -@Reusable -class SymbolResourceLocator @Inject constructor( - private val logger: KimchiLogger -) { - fun getBaseResourceName(symbol: Symbol): String { - if (symbol.id !in CHAR_RANGE_START..CHAR_RANGE_END) { - logger.warn("Out-of-bounds symbol requested: ${symbol.id}") - return format(FAULT_SYMBOL - CHAR_RANGE_START) - } - return when(symbol) { - is Symbol.Primary -> format(symbol.id - CHAR_RANGE_START) - is Symbol.Alternate -> format(symbol.id - CHAR_RANGE_START + ALT_START) - } - } - - fun getOverlayResourceName(symbol: Symbol): String? { - if (symbol !is Symbol.Alternate) return null - val overlay = symbol.overlay ?: return null - if (!symbol.alphaNumeric) return null - return when(overlay) { - in ASC_0..ASC_9, in ASC_A..ASC_Z -> format(overlay - ASC_0 + OVERLAY_START) - else -> null.also { - logger.warn("Out-of-bounds overlay requested: ${overlay.toInt()}") - } - } - } - - private fun format(number: Int): String = PREFIX + number.toString() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolSelector.kt b/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolSelector.kt deleted file mode 100644 index 93e53474..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolSelector.kt +++ /dev/null @@ -1,91 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.grid.GridCells -import androidx.compose.foundation.lazy.grid.LazyVerticalGrid -import androidx.compose.foundation.lazy.grid.items -import androidx.compose.material.IconButton -import androidx.compose.material.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.ack.structures.Symbol -import com.inkapplications.ack.structures.code -import com.inkapplications.ack.structures.symbolOf - -/** - * Selection UI showing a list of APRS symbols to select. - * - * This invokes the [onChange] callback any time a symbol is clicked on - * or a valid symbol is typed into the text field. - */ -@Composable -fun SymbolSelector( - onChange: (Symbol?) -> Unit, - modifier: Modifier = Modifier, - default: Symbol? = null, - viewModel: SymbolSelectorViewModel = hiltViewModel(), -) { - val current = remember { mutableStateOf(default?.code) } - - Column(modifier = modifier) { - TextField( - value = current.value.orEmpty(), - leadingIcon = { - val icon = current.value - .takeIf { it?.length == 2 } - ?.let { - try { symbolOf(it[0], it[1]) } - catch (e: IllegalArgumentException) { null } - } - ?.let { viewModel.createBitmap(it) } - ?: return@TextField - Image( - bitmap = icon.asImageBitmap(), - contentDescription = null, - modifier = Modifier - .width(24.dp + AckTheme.spacing.icon) - .height(24.dp + AckTheme.spacing.icon) - .padding(AckTheme.spacing.icon), - ) - }, - onValueChange = { new -> - if (new.length > 2) return@TextField - current.value = new - runCatching { symbolOf(new) }.getOrNull()?.run(onChange) - }, - shape = RectangleShape, - modifier = Modifier.fillMaxWidth() - ) - LazyVerticalGrid( - columns = GridCells.Adaptive(minSize = 32.dp), - ) { - items(viewModel.symbols) { symbol -> - val bitmap = viewModel.createBitmap(symbol) - IconButton(onClick = { - current.value = symbol.code - onChange(symbol) - }) { - if (bitmap == null) { - return@IconButton - } - Image( - bitmap = bitmap.asImageBitmap(), - contentDescription = null, - modifier = Modifier - .width(24.dp + AckTheme.spacing.icon) - .height(24.dp + AckTheme.spacing.icon) - .padding(AckTheme.spacing.icon), - ) - } - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolSelectorViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolSelectorViewModel.kt deleted file mode 100644 index f94744de..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/symbol/SymbolSelectorViewModel.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import android.graphics.Bitmap -import androidx.lifecycle.ViewModel -import com.inkapplications.ack.structures.Symbol -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -/** - * Viewmodel used to in UIs that require symbol rendering. - * - * This provides access to the symbol factory to create bitmaps in Compose - * as well as data access to the available list of symbols in APRS. - */ -@HiltViewModel -class SymbolSelectorViewModel @Inject constructor( - private val symbolFactory: SymbolFactory, -): ViewModel() { - val symbols = Symbol.Primary.ALL + Symbol.Alternate.BASE - fun createBitmap(symbol: Symbol): Bitmap? { - return symbolFactory.createSymbol(symbol) ?: symbolFactory.defaultSymbol - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncActivity.kt deleted file mode 100644 index ce755510..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncActivity.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.inkapplications.ack.android.tnc - -import android.annotation.SuppressLint -import android.app.Activity -import android.content.Intent -import androidx.activity.compose.setContent -import androidx.lifecycle.lifecycleScope -import com.inkapplications.ack.android.trackNavigation -import com.inkapplications.ack.data.drivers.DriverConnectionState -import com.inkapplications.ack.data.drivers.PacketDrivers -import com.inkapplications.android.extensions.ExtendedActivity -import com.inkapplications.android.startActivity -import dagger.hilt.android.AndroidEntryPoint -import kimchi.Kimchi -import kimchi.analytics.stringProperty -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.launch -import javax.inject.Inject - -private const val ARG_BACKGROUND_INTENT = "background_intent" - -/** - * Activity that displays bluetooth TNC devices and manages connections. - */ -@AndroidEntryPoint -class ConnectTncActivity: ExtendedActivity(), DeviceListController { - @Inject - lateinit var drivers: PacketDrivers - - private lateinit var backgroundService: Intent - - override fun onCreate() { - super.onCreate() - - Kimchi.trackScreen("connect_tnc") - - backgroundService = intent.getParcelableExtra(ARG_BACKGROUND_INTENT)!! - - setContent { - ConnectTncScreen(this) - } - } - - @SuppressLint("MissingPermission") - override fun onDeviceConnectClick(device: DeviceItem) { - Kimchi.trackEvent("connect_tnc_connect", listOf( - stringProperty("device_name", device.name) - )) - lifecycleScope.launch { - drivers.tncDriver.selectDevice(device.data) - startService(backgroundService) - drivers.tncDriver.connectionState.filter { it == DriverConnectionState.Connected }.first() - finish() - } - } - - override fun onCloseClick() { - Kimchi.trackEvent("connect_tnc_close") - finish() - } -} - -fun Activity.startConnectTncActivity( - backgroundService: Intent, -) { - Kimchi.trackNavigation("connect_tnc") - startActivity(ConnectTncActivity::class) { - putExtra(ARG_BACKGROUND_INTENT, backgroundService) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncScreen.kt deleted file mode 100644 index cbd5acc7..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncScreen.kt +++ /dev/null @@ -1,155 +0,0 @@ -package com.inkapplications.ack.android.tnc - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.material.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.BluetoothSearching -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.hilt.navigation.compose.hiltViewModel -import com.inkapplications.ack.android.ui.NavigationRow -import com.inkapplications.ack.android.ui.theme.AckScreen -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun ConnectTncScreen( - controller: DeviceListController, -) = AckScreen { - DeviceList(controller = controller) -} - -@Composable -fun DeviceList( - viewModel: ConnectTncViewModel = hiltViewModel(), - controller: DeviceListController, -) { - val state = viewModel.state.collectAsState() - when (val stateValue = state.value) { - ConnectTncState.Initial, - is ConnectTncState.Discovering.Empty -> { - Box( - modifier = Modifier.fillMaxSize() - .padding( - top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), - bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() - ), - ) { - DeviceHeader(controller::onCloseClick) - Column( - modifier = Modifier.fillMaxSize().padding( - horizontal = AckTheme.spacing.gutter, - ), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Icon( - imageVector = Icons.Default.BluetoothSearching, - contentDescription = null, - tint = AckTheme.colors.foregroundInactive, - modifier = Modifier.size(AckTheme.sizing.dispayIcon), - ) - Text("Searching for devices...") - LinearProgressIndicator( - modifier = Modifier.padding(vertical = AckTheme.spacing.item), - ) - } - } - } - is ConnectTncState.Discovering.DeviceList -> { - LazyColumn( - contentPadding = PaddingValues( - bottom = AckTheme.spacing.gutter, - ), - ) { - val rows = listOf(RowType.Header) + stateValue.devices.map { RowType.Device(it) } - items(rows) { row -> - when (row) { - RowType.Header -> DeviceHeader(controller::onCloseClick) - is RowType.Device -> Device( - device = row.device, - onConnectClick = { controller.onDeviceConnectClick(row.device) }, - ) - } - } - } - } - } -} - -@Composable -private fun DeviceHeader( - onBackPress: () -> Unit, -) { - NavigationRow( - title = "Devices", - onBackPressed = onBackPress, - ) -} - -private sealed interface RowType { - object Header: RowType - data class Device(val device: DeviceItem): RowType -} - -@Composable -@OptIn(ExperimentalMaterialApi::class) -private fun Device( - device: DeviceItem, - onConnectClick: () -> Unit, -) { - Card( - onClick = onConnectClick, - modifier = Modifier - .fillMaxWidth() - .padding( - horizontal = AckTheme.spacing.gutter, - vertical = AckTheme.spacing.singleItem, - ), - ) { - Box( - modifier = Modifier.padding(AckTheme.spacing.item), - ) { - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth(), - ) { - Column { - Text( - text = device.name, - style = AckTheme.typography.h3, - ) - } - DeviceConnectionOptions( - device = device, - ) - } - } - } -} - -@Composable -private fun DeviceConnectionOptions( - device: DeviceItem, -) = Row( - verticalAlignment = Alignment.CenterVertically, -) { - when (device) { - is DeviceItem.Connecting -> { - Box(Modifier.padding(AckTheme.spacing.clickSafety)) { - CircularProgressIndicator( - modifier = Modifier.size(AckTheme.sizing.iconButton), - ) - } - } - else -> { - Box(Modifier.padding(AckTheme.spacing.clickSafety)) { - Spacer(modifier = Modifier.size(AckTheme.sizing.iconButton)) - } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncState.kt b/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncState.kt deleted file mode 100644 index b27a71ab..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncState.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.inkapplications.ack.android.tnc - -/** - * View data for the TNC connection screen. - */ -sealed interface ConnectTncState { - /** - * Initial state of the screen, before any data is loaded. - */ - object Initial: ConnectTncState - - /** - * State indicating that bluetooth discovery is running. - */ - sealed interface Discovering: ConnectTncState { - /** - * Bluetooth discovery is running, but no compatible devices have been found. - */ - object Empty: Discovering - - /** - * A list of compatible TNC devices and their states. - */ - data class DeviceList(val devices: List): Discovering - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncStateFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncStateFactory.kt deleted file mode 100644 index 1d9bc804..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncStateFactory.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.inkapplications.ack.android.tnc - -import android.bluetooth.BluetoothDevice -import com.inkapplications.ack.data.drivers.ConnectTncData -import dagger.Reusable -import javax.inject.Inject - -/** - * Create view model data from the current connection state. - */ -@Reusable -class ConnectTncStateFactory @Inject constructor() { - fun create(data: ConnectTncData): ConnectTncState { - val connectedDevice = data.connectedDevice - val connectingDevice = data.connectingDevice - - val devices = data.discoveredDevices.map { - when { - it == connectedDevice -> DeviceItem.Connected( - name = it.name, - data = it, - reconnect = false, - ) - it == connectingDevice -> DeviceItem.Connecting( - name = it.name, - data = it, - ) - it.bondState == BluetoothDevice.BOND_BONDED -> DeviceItem.NotConnected( - name = it.name, - data = it, - reconnect = false, - ) - else -> DeviceItem.Unpaired( - name = it.name, - data = it, - ) - } - } - - return when { - data.discoveredDevices.isEmpty() -> ConnectTncState.Discovering.Empty - else -> ConnectTncState.Discovering.DeviceList(devices) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncViewModel.kt b/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncViewModel.kt deleted file mode 100644 index 48706f76..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncViewModel.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.inkapplications.ack.android.tnc - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.inkapplications.ack.data.drivers.PacketDrivers -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import javax.inject.Inject - -/** - * Android view model for holding data in the TNC connection screen. - */ -@HiltViewModel -class ConnectTncViewModel @Inject constructor( - drivers: PacketDrivers, - stateFactory: ConnectTncStateFactory, -): ViewModel() { - val state: StateFlow = drivers.tncDriver.deviceData - .map { stateFactory.create(it) } - .stateIn(viewModelScope, SharingStarted.Eagerly, ConnectTncState.Initial) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/tnc/DeviceItem.kt b/android-application/src/main/java/com/inkapplications/ack/android/tnc/DeviceItem.kt deleted file mode 100644 index b3e29ebb..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/tnc/DeviceItem.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.inkapplications.ack.android.tnc - -import com.inkapplications.android.extensions.bluetooth.BluetoothDeviceData - -/** - * Represents a bluetooth device and its connection state. - */ -sealed interface DeviceItem { - /** - * Technical data about the bluetooth device. - */ - val data: BluetoothDeviceData - - /** - * User-friendly name for the device. - */ - val name: String - - /** - * An unpaired bluetooth device. - */ - data class Unpaired( - override val name: String, - override val data: BluetoothDeviceData, - ): DeviceItem - - /** - * A device that is paired, but not connected. - */ - data class NotConnected( - override val name: String, - override val data: BluetoothDeviceData, - /** - * Whether automatic reconnection is enabled for this device. - */ - val reconnect: Boolean, - ): DeviceItem - - /** - * A device that is currently being connected to. - */ - data class Connecting( - override val name: String, - override val data: BluetoothDeviceData, - ): DeviceItem - - /** - * A connected bluetooth device. - */ - data class Connected( - override val name: String, - override val data: BluetoothDeviceData, - /** - * Whether automatic reconnection is enabled for this device. - */ - val reconnect: Boolean, - ): DeviceItem -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/tnc/DeviceListController.kt b/android-application/src/main/java/com/inkapplications/ack/android/tnc/DeviceListController.kt deleted file mode 100644 index d35e3f12..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/tnc/DeviceListController.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.android.tnc - -/** - * Actions that can be taken from the bluetooth device list. - */ -interface DeviceListController { - /** - * Invoked when the user clicks the connect icon for a device. - */ - fun onDeviceConnectClick(device: DeviceItem) - - /** - * Invoked when the user clicks on the close icon for the screen. - */ - fun onCloseClick() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/transmit/PathTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/transmit/PathTransformer.kt deleted file mode 100644 index 560d3d32..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/transmit/PathTransformer.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.inkapplications.ack.android.transmit - -import com.inkapplications.ack.android.settings.transformer.Transformer -import com.inkapplications.ack.structures.Digipeater -import com.inkapplications.ack.structures.station.toStationAddress - -/** - * Transforms a path of digipeaters into a comma-separated string. - */ -object PathTransformer: Transformer, String> { - override fun toStorage(data: List): String { - return data.map { it.address.toString() }.joinToString(",") - } - - override fun toData(storage: String): List { - return storage.split(',') - .map { it.trim() } - .map { it.toStationAddress() } - .map(::Digipeater) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/transmit/PreferenceDriverSettingsProvider.kt b/android-application/src/main/java/com/inkapplications/ack/android/transmit/PreferenceDriverSettingsProvider.kt deleted file mode 100644 index 4b46dac5..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/transmit/PreferenceDriverSettingsProvider.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.inkapplications.ack.android.transmit - -import com.inkapplications.ack.android.connection.ConnectionSettings -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.observeData -import com.inkapplications.ack.android.settings.observeInt -import com.inkapplications.ack.android.settings.observeString -import com.inkapplications.ack.data.AfskModulationConfiguration -import com.inkapplications.ack.data.ConnectionConfiguration -import com.inkapplications.ack.data.drivers.DriverSettingsProvider -import dagger.Reusable -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.flow.* -import javax.inject.Inject - -@Reusable -class PreferenceDriversSettingsProvider @Inject constructor( - settings: SettingsReadAccess, - connectionSettings: ConnectionSettings, - transmitSettings: TransmitSettings, - logger: KimchiLogger, -): DriverSettingsProvider { - override val internetServiceConfiguration: Flow = settings.observeData(connectionSettings.address) - .filterNotNull() - .map { ConnectionConfiguration(it) } - .combine(settings.observeData(connectionSettings.passcode)) { settings, passcode -> - settings.copy(passcode = passcode?.value ?: -1) - } - .combine(settings.observeString(connectionSettings.server)) { settings, server -> - settings.copy(host = server) - } - .combine(settings.observeInt(connectionSettings.port)) { settings, port -> - settings.copy(port = port) - } - .combine(settings.observeData(connectionSettings.radius)) { settings, radius -> - settings.copy(searchRadius = radius) - } - .onEach { logger.debug("New Internet Service Configuration Received: $it") } - - override val afskConfiguration: Flow = settings.observeData(transmitSettings.preamble) - .combine(settings.observeData(transmitSettings.volume)) { preamble, volume -> - AfskModulationConfiguration( - preamble = preamble, - volume = volume, - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/transmit/SymbolTransformer.kt b/android-application/src/main/java/com/inkapplications/ack/android/transmit/SymbolTransformer.kt deleted file mode 100644 index c4caa58c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/transmit/SymbolTransformer.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.inkapplications.ack.android.transmit - -import com.inkapplications.ack.android.settings.transformer.Transformer -import com.inkapplications.ack.structures.Symbol -import com.inkapplications.ack.structures.code -import com.inkapplications.ack.structures.symbolOf - -/** - * Transform an APRS symbol into its 2-char ASCII code. - */ -object SymbolTransformer: Transformer { - override fun toStorage(data: Symbol): String = data.code - - override fun toData(storage: String): Symbol = symbolOf(storage) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/transmit/TransmitModule.kt b/android-application/src/main/java/com/inkapplications/ack/android/transmit/TransmitModule.kt deleted file mode 100644 index c9941c16..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/transmit/TransmitModule.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.inkapplications.ack.android.transmit - -import com.inkapplications.ack.android.settings.SettingsProvider -import com.inkapplications.ack.data.drivers.DriverSettingsProvider -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import dagger.multibindings.IntoSet - -@Module -@InstallIn(SingletonComponent::class) -abstract class TransmitModule { - @Binds - @IntoSet - abstract fun settings(settings: TransmitSettings): SettingsProvider - - @Binds - abstract fun driverSettings(settings: PreferenceDriversSettingsProvider): DriverSettingsProvider -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/transmit/TransmitSettings.kt b/android-application/src/main/java/com/inkapplications/ack/android/transmit/TransmitSettings.kt deleted file mode 100644 index 6c33d912..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/transmit/TransmitSettings.kt +++ /dev/null @@ -1,146 +0,0 @@ -package com.inkapplications.ack.android.transmit - -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.input.* -import com.inkapplications.ack.android.settings.* -import com.inkapplications.ack.android.settings.transformer.* -import com.inkapplications.ack.structures.Digipeater -import com.inkapplications.ack.structures.Symbol -import com.inkapplications.ack.structures.station.StationAddress -import com.inkapplications.android.extensions.StringResources -import inkapplications.spondee.measure.us.miles -import inkapplications.spondee.scalar.Percentage -import inkapplications.spondee.scalar.percent -import inkapplications.spondee.scalar.toWholePercentage -import inkapplications.spondee.structure.roundToInt -import javax.inject.Inject -import kotlin.time.Duration.Companion.minutes -import kotlin.time.Duration.Companion.seconds - -class TransmitSettings @Inject constructor( - resources: StringResources, -): SettingsProvider { - val minRate = IntBackedSetting( - key = "transmit.rate.min", - name = resources.getString(R.string.transmit_settings_rate_min), - defaultData = 10.minutes, - categoryName = resources.getString(R.string.transmit_settings_category), - storageTransformer = MinuteTransformer, - inputValidator = IntegerValidator( - error = resources.getString(R.string.input_validator_positive_integer_error), - zeroInclusive = false, - ), - ) - - val maxRate = IntBackedSetting( - key = "transmit.rate.max", - name = resources.getString(R.string.transmit_settings_rate_max), - defaultData = 5.minutes, - categoryName = resources.getString(R.string.transmit_settings_category), - storageTransformer = MinuteTransformer, - inputValidator = IntegerValidator( - error = resources.getString(R.string.input_validator_positive_integer_error), - zeroInclusive = false, - ), - ) - - val distance = IntBackedSetting( - key = "transmit.distance", - name = resources.getString(R.string.transmit_settings_distance), - defaultData = 5.miles, - categoryName = resources.getString(R.string.transmit_settings_category), - storageTransformer = MileTransformer, - inputValidator = IntegerValidator( - error = resources.getString(R.string.input_validator_positive_integer_error), - zeroInclusive = false, - ), - ) - - val preamble = IntBackedSetting( - key = "transmit.preamble", - name = resources.getString(R.string.transmit_settings_preamble), - defaultData = 1.seconds, - categoryName = resources.getString(R.string.transmit_settings_category), - visibility = SettingVisibility.Advanced, - storageTransformer = MillisecondTransformer, - inputValidator = IntegerValidator( - error = resources.getString(R.string.input_validator_positive_integer_error), - zeroInclusive = false, - ), - ) - - val digipath = StringBackedSetting( - key = "transmit.digipath", - name = resources.getString(R.string.transmit_settings_digipath), - defaultData = StationAddress("WIDE1", "1").let(::Digipeater).let(::listOf), - visibility = SettingVisibility.Advanced, - categoryName = resources.getString(R.string.transmit_settings_category), - storageTransformer = PathTransformer, - ) - - val symbol = StringBackedSetting( - key = "transmit.symbol.normalized", - name = resources.getString(R.string.transmit_settings_symbol), - defaultData = Symbol.Primary('$'), - categoryName = resources.getString(R.string.transmit_settings_category), - storageTransformer = SymbolTransformer, - inputValidator = MinLengthValidator( - minLength = 2, - error = resources.getString(R.string.transmit_settings_symbol_length), - ) + MaxLengthValidator( - maxLength = 2, - error = resources.getString(R.string.transmit_settings_symbol_length), - ), - ) - - val destination = StringBackedSetting( - key = "transmit.destination", - name = resources.getString(R.string.transmit_settings_destination), - defaultData = StationAddress("APZ022"), - categoryName = resources.getString(R.string.transmit_settings_category), - visibility = SettingVisibility.Advanced, - storageTransformer = StationAddressTransformer, - ) - - val comment = StringSetting( - key = "transmit.comment", - name = resources.getString(R.string.transmit_settings_comment), - defaultValue = "Hello!", - categoryName = resources.getString(R.string.transmit_settings_category), - validator = MaxLengthValidator( - maxLength = 43, - error = resources.getString(R.string.transmit_settings_comment_length), - ), - ) - - val volume = IntBackedSetting( - key = "transmit.volume", - name = resources.getString(R.string.transmit_settings_volume), - defaultData = 50.percent, - categoryName = resources.getString(R.string.transmit_settings_category), - storageTransformer = PercentageTransformer, - dataValidator = object: Validator { - override fun validate(input: Percentage): ValidationResult { - return if (input.toWholePercentage().roundToInt() in (0..100)) { - ValidationResult.Valid - } else { - ValidationResult.Error( - message = resources.getString(R.string.transmit_settings_volume_range_error), - ) - } - } - } - ) - - override val settings: List = listOf( - minRate, - maxRate, - distance, - preamble, - digipath, - symbol, - destination, - comment, - volume, - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/AckChip.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/AckChip.kt deleted file mode 100644 index 47493441..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/AckChip.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.Surface -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import com.inkapplications.ack.android.ui.theme.AckTheme - -/** - * Rounded UI element, similar to a button, but intended to also display state. - */ -@Composable -@OptIn(ExperimentalMaterialApi::class) -fun AckChip( - modifier: Modifier = Modifier, - onClick: (() -> Unit)? = null, - border: BorderStroke? = BorderStroke(1.dp, AckTheme.colors.foregroundInactive), - content: @Composable () -> Unit, -) { - if (onClick != null) { - Surface( - shape = RoundedCornerShape(24.dp), - elevation = 1.dp, - border = border, - onClick = onClick, - modifier = modifier, - ) { - Row( - verticalAlignment = androidx.compose.ui.Alignment.CenterVertically, - modifier = Modifier.padding(AckTheme.spacing.content), - ) { content() } - } - } else { - Surface( - shape = RoundedCornerShape(24.dp), - elevation = 1.dp, - border = border, - modifier = modifier, - ) { - Row( - verticalAlignment = androidx.compose.ui.Alignment.CenterVertically, - modifier = Modifier.padding(AckTheme.spacing.content), - ) { content() } - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/AprsSymbol.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/AprsSymbol.kt deleted file mode 100644 index fb25022e..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/AprsSymbol.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.inkapplications.ack.android.capture.log - -import android.graphics.Bitmap -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.unit.dp -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun AprsSymbol(symbol: Bitmap?) { - if (symbol != null) { - Image( - bitmap = symbol.asImageBitmap(), - contentDescription = null, - modifier = Modifier - .width(24.dp + AckTheme.spacing.icon) - .height(24.dp + AckTheme.spacing.icon) - .padding(AckTheme.spacing.icon) - ) - } else { - Box( - modifier = Modifier.width(24.dp).height(24.dp).padding(AckTheme.spacing.icon) - ) {} - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/CallsignChip.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/CallsignChip.kt deleted file mode 100644 index b81b8dad..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/CallsignChip.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Verified -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun CallsignChip( - callsign: String, - verified: Boolean, - onClick: (() -> Unit)? = null, - border: BorderStroke? = null, -) { - if (onClick != null) { - AckChip( - border = border, - onClick = onClick, - ) { - CallsignChipContent(callsign, verified) - } - } else { - AckChip( - border = border, - ) { - CallsignChipContent(callsign, verified) - } - } -} - -@Composable -private fun CallsignChipContent( - callsign: String, - verified: Boolean, -) { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - if (verified) Icon( - Icons.Default.Verified, - stringResource(R.string.settings_callsign_verified_description), - modifier = Modifier.padding(end = AckTheme.spacing.icon) - ) - Text(callsign, style = AckTheme.typography.h2) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/EmptyBox.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/EmptyBox.kt deleted file mode 100644 index 62c67ab6..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/EmptyBox.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.size -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.ImageVector -import com.inkapplications.ack.android.ui.theme.AckTheme - -/** - * Placeholder with an icon and caption to explain that there is no data loaded - * for this section of the app yet. - * - * @param icon A large icon to place in the middle of the screen - * @param caption A snippet of text to explain what data is missing. - */ -@Composable -fun EmptyBox( - icon: ImageVector, - caption: String, - modifier: Modifier = Modifier, -) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = Modifier - .fillMaxSize() - .then(modifier) - ) { - Icon( - imageVector = icon, - contentDescription = null, - tint = AckTheme.colors.foregroundInactive, - modifier = Modifier.size(AckTheme.sizing.dispayIcon), - ) - Text(caption) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/IconRow.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/IconRow.kt deleted file mode 100644 index fc2b6be8..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/IconRow.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.graphics.vector.ImageVector -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun IconRow( - icon: ImageVector, - text: String, - modifier: Modifier = Modifier, -) = Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) { - Icon(icon, null, tint = AckTheme.colors.accent, modifier = Modifier.padding(AckTheme.spacing.icon)) - Text(text) -} - -@Composable -fun IconRow( - icon: Painter, - text: String, - modifier: Modifier = Modifier, -) = Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) { - Icon(icon, null, tint = AckTheme.colors.accent, modifier = Modifier.padding(AckTheme.spacing.icon)) - Text(text) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/KeyValueRow.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/KeyValueRow.kt deleted file mode 100644 index 1a8026a4..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/KeyValueRow.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun KeyValueRow( - label: String, - value: String, - modifier: Modifier = Modifier, -) = Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier) { - Text(label, style = AckTheme.typography.caption, color = AckTheme.colors.accent, modifier = Modifier.padding(end = AckTheme.spacing.icon)) - Text(value, style = AckTheme.typography.body) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/LabelledIconButton.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/LabelledIconButton.kt deleted file mode 100644 index 3f15cc12..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/LabelledIconButton.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.Button -import androidx.compose.material.ButtonDefaults -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun LabelledIconButton( - icon: ImageVector, - title: String, - onClick: (() -> Unit) = {}, - backgroundColor: Color = AckTheme.colors.accent, - iconColor: Color = AckTheme.colors.onAccent, - border: BorderStroke? = null, - enabled: Boolean = true, - modifier: Modifier = Modifier, -) = Box(modifier) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .padding(vertical = AckTheme.spacing.clickSafety, horizontal = AckTheme.spacing.gutter) - ) { - Button( - onClick = onClick, - shape = CircleShape, - colors = ButtonDefaults.buttonColors( - backgroundColor = backgroundColor, - contentColor = iconColor, - ), - border = border, - enabled = enabled, - contentPadding = PaddingValues(8.dp), - modifier = Modifier.size(60.dp), - ) { - Icon( - imageVector = icon, - contentDescription = null, - tint = iconColor, - modifier = Modifier.padding(AckTheme.spacing.icon), - ) - } - Text( - text = title, - style = AckTheme.typography.caption, - textAlign = TextAlign.Center, - modifier = Modifier.padding(top = AckTheme.spacing.item).width(70.dp) - ) - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/NavigationRow.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/NavigationRow.kt deleted file mode 100644 index e698c9c3..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/NavigationRow.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import com.inkapplications.ack.android.ui.theme.AckTheme - -@Composable -fun NavigationRow( - title: String, - onBackPressed: (() -> Unit)? = null, -) = NavigationRow( - title = { - Text( - text = title, - style = AckTheme.typography.h1, - modifier = Modifier.padding( - start = AckTheme.spacing.item, - ) - ) - }, - onBackPressed = onBackPressed, -) - -@Composable -fun NavigationRow( - title: @Composable () -> Unit, - onBackPressed: (() -> Unit)? = null, -) = Row ( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding( - start = 0.dp, - top = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - bottom = AckTheme.spacing.content, - ) -) { - if (onBackPressed != null) { - IconButton( - onClick = { onBackPressed() }, - Modifier.padding(start = 0.dp) - ) { - Icon(Icons.Default.ArrowBack, "") - } - } else { - Spacer(Modifier.width(AckTheme.spacing.item)) - } - title() -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/SelectionRow.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/SelectionRow.kt deleted file mode 100644 index ca114391..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/SelectionRow.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Check -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.inkapplications.ack.android.R -import com.inkapplications.ack.android.ui.theme.AckTheme - -/** - * Clickable row with a selection state. - * - * This is designed to be used in a selection screen or pop up, to indicate - * a list of options with one or more items in a "selected" state. - * - * @param name User-readable string displayed in this row. - * @param selected Whether to indicate the row as currently selected/enabled. - * @param onClick Invoked when the user clicks the row. - */ -@Composable -fun SelectionRow( - name: String, - selected: Boolean, - onClick: () -> Unit, -) { - Row( - horizontalArrangement = Arrangement.SpaceBetween, - modifier = Modifier - .clickable { onClick() } - .fillMaxWidth() - .padding(vertical = AckTheme.spacing.clickSafety, horizontal = AckTheme.spacing.gutter), - ) { - Text(name, style = AckTheme.typography.h2) - - if (selected) { - Icon( - Icons.Default.Check, - contentDescription = stringResource(id = R.string.state_selected_description), - ) - } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/StateLabelledIconButton.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/StateLabelledIconButton.kt deleted file mode 100644 index 16d3311c..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/StateLabelledIconButton.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.BorderStroke -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.unit.dp -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.android.extensions.control.ControlState - -@Composable -fun StateLabelledIconButton( - icon: ImageVector, - title: String, - onClick: ((ControlState) -> Unit) = {}, - state: ControlState, - modifier: Modifier = Modifier, -) = when (state) { - ControlState.On -> LabelledIconButton( - title = title, - icon = icon, - backgroundColor = AckTheme.colors.accent, - iconColor = AckTheme.colors.onAccent, - onClick = { onClick(state) }, - modifier = modifier, - ) - ControlState.Off -> LabelledIconButton( - title = title, - icon = icon, - onClick = { onClick(state) }, - modifier = modifier, - backgroundColor = AckTheme.colors.surface, - border = BorderStroke(1.dp, AckTheme.colors.accent), - iconColor = AckTheme.colors.foregroundInactive, - ) - ControlState.Disabled -> LabelledIconButton( - title = title, - icon = icon, - onClick = { onClick(state) }, - modifier = modifier.alpha(.6f), - enabled = false, - backgroundColor = AckTheme.colors.surface, - border = BorderStroke(1.dp, AckTheme.colors.foregroundInactive), - iconColor = AckTheme.colors.foregroundInactive, - ) - ControlState.Hidden -> {} -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/TelemetryTable.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/TelemetryTable.kt deleted file mode 100644 index 1fd596ef..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/TelemetryTable.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.inkapplications.ack.android.ui - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Card -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.inkapplications.ack.android.ui.theme.AckTheme -import com.inkapplications.ack.structures.TelemetryValues - -@Composable -fun TelemetryTable(values: TelemetryValues, sequence: String?) { - Card(modifier = Modifier.fillMaxWidth().padding(vertical = AckTheme.spacing.content)) { - Column(modifier = Modifier.padding(AckTheme.spacing.content)) { - Text("Telemetry Data", style = AckTheme.typography.h2) - TelemetryValueRow("a1", values.analog1.toString()) - TelemetryValueRow("a2", values.analog2.toString()) - TelemetryValueRow("a3", values.analog3.toString()) - TelemetryValueRow("a4", values.analog4.toString()) - TelemetryValueRow("a5", values.analog5.toString()) - TelemetryValueRow("d1", values.digital.toString()) - TelemetryValueRow("sq", sequence.orEmpty()) - } - } -} - -@Composable -private fun TelemetryValueRow( - label: String, - value: String, -) = KeyValueRow(label, value, Modifier.padding(vertical = AckTheme.spacing.singleItem)) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AckScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AckScreen.kt deleted file mode 100644 index 7d5c0892..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AckScreen.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import androidx.compose.material.LocalContentColor -import androidx.compose.material.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider - -@Composable -fun AckScreen(content: @Composable () -> Unit) { - MaterialTheme( - colors = AckTheme.colors.materialColors, - typography = AckTheme.typography.material, - ) { - CompositionLocalProvider( - LocalContentColor provides AckTheme.colors.foreground, - ) { content() } - } -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AckTheme.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AckTheme.kt deleted file mode 100644 index 65057055..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AckTheme.kt +++ /dev/null @@ -1,131 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import android.os.Build -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.runtime.Composable -import androidx.compose.runtime.ReadOnlyComposable -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp - -object AckTheme { - private val primaryColor - @Composable - @ReadOnlyComposable - get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - colorResource(android.R.color.system_accent1_400) - } else { - ColorPalette.brand - } - - val darkColors - @Composable - @ReadOnlyComposable - get() = ColorVariant( - accent = primaryColor, - onAccent = ColorPalette.darkStroke, - foreground = ColorPalette.lightStroke, - background = ColorPalette.darkStroke, - surface = ColorPalette.darkStrokeSoftened, - error = ColorPalette.red, - onError = ColorPalette.lightStroke, - light = false, - warnForeground = ColorPalette.lightWarning, - dangerForeground = ColorPalette.red, - ) - - val lightColors - @Composable - @ReadOnlyComposable - get() = darkColors.copy( - foreground = ColorPalette.darkStroke, - background = ColorPalette.lightStroke, - surface = ColorPalette.lightStrokeSoftened, - warnForeground = ColorPalette.darkWarning, - dangerForeground = ColorPalette.red, - ) - - val colors - @Composable - @ReadOnlyComposable - get() = if (isSystemInDarkTheme() || Build.VERSION.SDK_INT < Build.VERSION_CODES.N) darkColors else lightColors - - val spacing - @Composable - @ReadOnlyComposable - get() = SpacingVariant( - gutter = 16.dp, - content = 8.dp, - item = 8.dp, - icon = 8.dp, - clickSafety = 16.dp, - ) - - val sizing - @Composable - @ReadOnlyComposable - get() = SizingVariant( - dispayIcon = 120.dp, - displayDecorationIcon = 80.dp, - iconButton = 16.dp, - ) - - val shapes - @Composable - @ReadOnlyComposable - get() = ShapeVariant( - corners = RoundedCornerShape(8.dp), - ) - - val typography - @Composable - @ReadOnlyComposable - get() = TypographyVariant( - display = TextStyle( - fontFamily = AprsFonts.titleFont, - fontWeight = FontWeight.Normal, - fontSize = 48.sp, - letterSpacing = 0.25.sp - ), - h1 = TextStyle( - fontFamily = AprsFonts.titleFont, - fontWeight = FontWeight.Normal, - fontSize = 34.sp, - letterSpacing = 0.25.sp - ), - h2 = TextStyle( - fontFamily = AprsFonts.titleFont, - fontWeight = FontWeight.Normal, - fontSize = 24.sp, - letterSpacing = 0.sp - ), - h3 = TextStyle( - fontFamily = AprsFonts.titleFont, - fontWeight = FontWeight.Medium, - fontSize = 20.sp, - letterSpacing = 0.15.sp - ), - body = TextStyle( - fontFamily = AprsFonts.contentFont, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - letterSpacing = 0.5.sp - ), - caption = TextStyle( - fontFamily = AprsFonts.contentFont, - fontWeight = FontWeight.Normal, - fontSize = 12.sp, - letterSpacing = 0.4.sp - ), - errorCaption = TextStyle( - fontFamily = AprsFonts.contentFont, - fontWeight = FontWeight.Normal, - fontSize = 12.sp, - letterSpacing = 0.4.sp, - color = colors.error - ) - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AprsFonts.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AprsFonts.kt deleted file mode 100644 index 19c812de..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/AprsFonts.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import androidx.compose.ui.text.font.Font -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import com.inkapplications.ack.android.R - -object AprsFonts { - val titleFont = FontFamily( - Font(R.font.anonymous_pro, FontWeight.Normal), - Font(R.font.anonymous_pro_bold, FontWeight.Bold), - ) - val contentFont = FontFamily( - Font(R.font.lato_regular, FontWeight.Normal), - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ColorPalette.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ColorPalette.kt deleted file mode 100644 index f4cf30bb..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ColorPalette.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import androidx.compose.ui.graphics.Color - -object ColorPalette { - val brand = Color(0xFFFFa72B) - val brandLight = Color(0xFFFCB652) - val brandDark = Color(0xFFB16D0D) - - val darkStroke = Color(0xFF212121) - val darkStroke70 = Color(0x70212121) - val darkStrokeSoftened = Color(0xFF292929) - - val lightStroke = Color(0xFFFFFFFF) - val lightStroke70 = Color(0x70FFFFFF) - val lightStrokeSoftened = Color(0xFFF2F2F2) - - val darkWarning = Color(0xFFB16D0D) - val lightWarning = Color(0xFFFCB652) - - val red = Color(0xFFFF432B) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ColorVariant.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ColorVariant.kt deleted file mode 100644 index d4cb2657..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ColorVariant.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import androidx.compose.material.Colors -import androidx.compose.ui.graphics.Color - -data class ColorVariant( - val accent: Color, - val onAccent: Color, - val foreground: Color, - val background: Color, - val surface: Color, - val error: Color, - val onError: Color, - val light: Boolean, - val warnForeground: Color, - val dangerForeground: Color, -) { - val foregroundInactive = foreground.copy(alpha = .5f) - val surfaceInactive = surface.copy(alpha = .5f) - - val materialColors = Colors( - primary = accent, - primaryVariant = accent, - secondary = accent, - secondaryVariant = accent, - background = background, - surface = background, - error = error, - onPrimary = onAccent, - onSecondary = onAccent, - onBackground = foreground, - onSurface = foreground, - onError = onError, - isLight = light, - ) -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ShapeVariant.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ShapeVariant.kt deleted file mode 100644 index 4fe4304e..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/ShapeVariant.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import androidx.compose.ui.graphics.Shape - -/** - * Defines the shapes used in the application. - * - * @param corners Corner radii used for dialogs and other surfaces. - */ -data class ShapeVariant( - val corners: Shape, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/SizingVariant.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/SizingVariant.kt deleted file mode 100644 index 3bca0555..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/SizingVariant.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import androidx.compose.ui.unit.Dp - -data class SizingVariant( - val dispayIcon: Dp, - val displayDecorationIcon: Dp, - val iconButton: Dp, -) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/SpacingVariant.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/SpacingVariant.kt deleted file mode 100644 index 5947a58a..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/SpacingVariant.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp - -data class SpacingVariant( - val gutter: Dp, - val content: Dp, - val item: Dp, - val icon: Dp, - val clickSafety: Dp, - val bottomBarHeight: Dp = 60.dp, - val fabSize: Dp = 40.dp, -) { - val navigationProtection = bottomBarHeight + (fabSize / 2) + content - val singleItem: Dp = item / 2 -} diff --git a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/TypographyVariant.kt b/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/TypographyVariant.kt deleted file mode 100644 index af654ab2..00000000 --- a/android-application/src/main/java/com/inkapplications/ack/android/ui/theme/TypographyVariant.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.inkapplications.ack.android.ui.theme - -import androidx.compose.material.Typography -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight - -data class TypographyVariant( - val display: TextStyle, - val h1: TextStyle, - val h2: TextStyle, - val h3: TextStyle, - val body: TextStyle, - val caption: TextStyle, - val errorCaption: TextStyle, -) { - val material = Typography( - defaultFontFamily = AprsFonts.contentFont, - h1 = h1, - h2 = h2, - h3 = h3, - h4 = h1, - h5 = h2, - h6 = h3, - subtitle1 = caption, - subtitle2 = caption, - body1 = body, - body2 = body.copy(fontWeight = FontWeight.Bold), - button = body, - caption = caption, - overline = body, - ) -} diff --git a/android-application/src/main/res/drawable-nodpi/symbol_0.png b/android-application/src/main/res/drawable-nodpi/symbol_0.png deleted file mode 100644 index 210ea853d78b8c8b891756862799a12c86950ee2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 902 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DhBC&U#kVv{(SF(g2MCX)z+`K7ZBL<|NsAA zADg6r_6U>&`2{lwobPW?c)x#rfW!TS`340q_`fUz$}uK+ySpeJ$>9|Pa@b2eeO=j~ zurrH^s(k8c5!Wk@R8k*gd0q5GM`|0ut#~`!6kF}G|~=Cl#y?~&?+InRA_?G z+C5D|XHN-*O!42od`w<+F!jUhZwbiS@=0j)tE-G5yifKc$M=6PRDU z{BFtfm*>Uv({nz2id=Do$03(V>L17F`2qPSnEXFHYY^L4vi#Dm<|yU{7M9=2#k&%i zn(nSOVCZKvaX7x-=cI^K$i`bo>dqcv4Jdr{=eYff6xUV0EW!u$`ybi_?R>*hviJ_u z2YxNnE;9z}skLq?@eGfxBhF^K@BCi7m1$Mni+fp5-)y=h<(jzj6yx>K?W{8&%zAb0 zl(ANwaX823vsv9UrsU;~A}K0lU`T**feN<4*g(PcU@h+%7y=j=_5-bEV7L!`sf6Lw}XQI$`fv1frocRgJkLn02popw>ENkPC>Q`A&w?G_J{Ex-QfpK;TUnYE>~ zYK6u6)3)ypoa<|e(3ziZCVr^!W2Jx0!i;A9D48`1FIY-eIYcyy0@0gd&F(!%xDK`E zShhUg_k5$=X^(py5-q>o?8F#U?+%k%5(|v9^JMm4U%|o7Sl)8glbfGSez? zYuJ})s|nN~39=zLKdq!Zu_%?nF(p4KRlzeiF+DXXH8G{K@MJ0|#V~lf`njxgN@xNA DtjE;a diff --git a/android-application/src/main/res/drawable-nodpi/symbol_10.png b/android-application/src/main/res/drawable-nodpi/symbol_10.png deleted file mode 100644 index 62be5e34c5f43b377c8dc1f213f09bc1fc0ccec1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5ln@Q@32_C||Jm43(EtBV z`&ZfmC0I*>{DK)A8WQ%mWj1UB3NR*lySuO@rtPQ&a@b2eeO=j~urrH^s(k8cwc%mI-DtUL}}AUO_QmvAUQh^kMk%5tcu7SC(fpLhDk(H5wm8r3| zfq|8Q!Fik3sVEw9^HVa@DsgMrmuRaA)F276Aviy+q&%@GmBBG3KPgqgGdD3kH7GSP VrLyp3DkyLmJYD@<);T3K0RX9tYwiF5 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_100.png b/android-application/src/main/res/drawable-nodpi/symbol_100.png deleted file mode 100644 index a1b79390e74ac1e7771dd43d7a3cdfb86997bf0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 686 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*EhC&U#<;|HP)4FAC> z0j#bMrurQN!)=(kxX1RpPX(Pj*b#FMGDy$aVSM-fBcrY=#Mx%j6fQR*fvBUueHVIyX z(;7=F8QGpG?oN~68=7}~-5l24>OC>0o!8#$cg{Jyk@ZGr#>Hb!S+2*dG)oXTwz471k=1;ufzR)-ZG~77>YE@GjcXn5ACWJJR;o^;60% z$*b)%Z^$j-eWS5FdgDRaHS^`yZCbQtRsBypg9b)7wg&qj8ySQ&6yACA-#X7~*TVdN z|3~$m43{Kb_rE`~J`3n+)e_f;l9a@fRIB8oR3OD*WME{VYhbQxU>ss(WMyPvWooQ# zU|?lnaNeeMDvE~O{FKbJO57UuCE98NHAsSN2+mI{DNig)WpGT%PfAtr%uP&B4N6T+ UsVqF13Q9x_p00i_>zopr0D_Lu`v3p{ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_101.png b/android-application/src/main/res/drawable-nodpi/symbol_101.png deleted file mode 100644 index fdaffe388e4880ebca3e956eda37ad90d0a0035f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 619 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjfzi*?#W5t~-rJi8We++C9DUf%7Sy&_XvzZSmprmB95_oB zu*$AsW>=habEdgI`?a$N|9jU>dXv}i|Hs#j3V)7qc{6O! zxhyAhef64WOI!Z!>G@!*ugLTKGUwx;Ax*mT-8MWA<|wVST4?95`s0&HlfA#_4Gg1 zaXQ+f(i~u^nk+0cIY{lGrEa<)6Spv%;trE;A&&0L9F1FSz6*6oi^wrmb}ySYVS{I= zv&XGvn}vkTwRBsati5H}l(2c%Tr+zYfqfe?mY@AD_$0q)SIcB`du~Cq8;ckV4#d@d z`R^!Qt{=oUHQ$ww4;a|0C9V-ADTyViR>?)FK#IZ0z{o(?z+BhBIK;@v%E-XV)L7fV zz{-L1;Fyx1l&avFo0y&&l$w}Q US$HxPlmZw$UHx3vIVCg!00E!gx&QzG diff --git a/android-application/src/main/res/drawable-nodpi/symbol_102.png b/android-application/src/main/res/drawable-nodpi/symbol_102.png deleted file mode 100644 index 96dafa84f351c0e3e22b960998c9d59e16d031af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3851 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 GCF;K&gE-9q diff --git a/android-application/src/main/res/drawable-nodpi/symbol_103.png b/android-application/src/main/res/drawable-nodpi/symbol_103.png deleted file mode 100644 index 8f97077bfb17df1141eb44eb9762edc9aa236e1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2378 zcmZ`*XH=8f7X1=h=r~A85a9t*hamwA282Wjf=UgM5-9-^1W}}mw9uuGqEZz{(Zo=s zNr@sjAc&BJs9@+)3@x-lMEZ;G-+ODld)D21opaW{_s>~p?R0zFvyx&kF#rH0t*tB^ z`HcE?A;Ns5`3H~jNze~%g9d<_T=5-(5Ih>o=d+Uds7 zVv&2`!7p-M@ru8JJPc$-0~6(zVN{74g$61aB2#QtHZ4>lLJ7Ft7AxkUj-ugGM3V6@ zaVn35HK-k#&t)D9VhYqyG|@nrqhN{A&+lSVZh%CqH#zRhLyEV!-w7n%;9%jXYaZP* zw5;5<)I?=thqeDObg4zy&UCdy_J3io)wfqWmSP(OyhKSfReGv#t;gFYqV!}$H0-vO z`hG4ePPb-&7;W-(YBCUe2M06;L-sX9tKI&}8>}0cdE92VzCca%s?V1bVibdKJ=U&` zS|c^b?b0PAB&?952G5<&-HDC8W2G_Oo!7)0ZnTp(@CYQGDRCgRM+%`*SM{8$?v9Ol zKo1?dn~*^HI6lr-xNTkNG>_YHIcyfA(bCfLkskTt=WbpvssK$r>(lSw@^W_fL;P<* zW#`w%tHYYCQuBO2*2C^k6uYOb@u-jfqd$EeCs&(H<8~|#pSsC^LHZloE_bALAH^&+ zH|X#0Cus%>(z}(-i#&yIAsCwN#V-|dEav-6+qc#i2I=8?YKb&4HQF3)XjTx1ON$$C z4o#EOi?j0d^z0NNu^uvZHrEa$T=`NJvO0+gjXdZgtYIlYhQp4`6#eN;UKwc)otvHQ zlaNC@Wv;p+(Q`sl5 zyuR*y^i(!N`oo8xUAx=O&l15UKpZ7HM&6Ak4#t8a7Kbo6oSa%B^|3pH;Xnzs2Q`ue(H5_)pg__mcG#^G{MkU`&CGe>o+t{vGgNd8grBYNE~t~Xoh z1TaM25C?gc^lZCHPT}3$I8DJ*_GwYo-agb8CR}&;MiP`pJ?Z+SXs@cW@)!V-M+$Y? z(4!k6U;7mdvZw*~EFXaC8yY@xIL4m|$^`++RO)f$l-aRiI3oI{V)F0HN<4P>JF`-R z##1jK!{asJ#cLc#j$*}Sq|!oRrE~gu6H(p?yRl0x25KXpUrVdIU=KDoX+i8gJxhr( z+)FS2icMu&gljFo`bad3p8I$tN7;lVv1s)c=%CnXnZ+X0QEhV%6;XKn@cF25TAlb! zZ_%4j6it|1NbkuvDDI-)2U8N1gf)Q2Y;E@C&m?BXDb)s>aGp~71|~T*RoaCf_8c() zZy%&dDWGdEpEhMC-zZt_E_07pcRP8`_>iUy#P@7$ciumi@MWA*#L2mg%*@U8ptv5b z(m=x`nJ)>m1Mw$J5I(%Wzj)}uP8dT31Y-I>`7puguW-28A*s;$&pMhmMR&)yX$+JN zZp>b+H)DnS*-v(TtvX;U3wrn7z2K#hljYe{;m0cgDR2^(c`3Y29_4T_r9DmBPtntb z9@^LZqOXmwQTsb{%)8q#zwoN@jmX-%Bb8~WIH3rlD@gZNrF zZot}!gO(Vx17jW_{06Gr7iu{*=OZVrwh6iTbMECc?j4CSpQ^77nmAp&2y3YP07=|@ z?5irH{WD1@%3P1cp}d+9>#NU^S#wf+GxRQ7NL(JKNfc}kEfIcD|-&S*tgk#<iunXSC4SFiEnPxoXV9E*z+Os6M3Ne*7b?M zh1$!KWdU!Hs&IAajO`bdo|)K%=zsJ>YW+*0>o_CD0B$2r_Ka<*8RqwaQ`1-@p!o+# ziGBYqf2F1Mmpd!em*)jtEfpdYulZ3-`q6$uAx$r4(9$B(d+Aow^#rWodDx+10kXE6 zZpqE>vktntx{#F94Vfi`Amf83>JK)A-sJ`^$A4$1jl7O(4`fBVi2W7g`Zd;vS%GiN z;VcdxXJ7hf!Ls^&&3gTUD)pro{Bpy$d`@5yS3vcdIfUHWQCg=OtS}+I{^qS(T3G%8 zC!?t@R&m_hyE@pci5Im-eT)EmkV~zvXk2`H`$!}ysoZeGL_5MsX*5|>_Qv+2TYC=u zHuz6qmdDe$ZN=4&C;?xp!sI0VVMoWhBhFsQ(~?H08ao0*z@2UlmG~W_JKYw{dQN}; zyU|yXo_}vk%`smG2Y{S$bqPlg1#^29Qk4&wOpWlwy2y)dol{-8p9Tl5u~=D2NlEBf zQ^+^5VSK}a{~?+qoPh; z8K@u()Yr!Or9Q7bCS zCX!ST`yy*;rYZ|d+&Y#No6RP?))kA{CxU>=KRAhRY?j*YLymV1<8Zh#N1dh7SAL7< z9uZ+eu_8qivRc4>gZO-V?T(H~Z{+@-oR;0gvewq|#eyeUDtgz_@-Sd97yhr#ymtwqe0`X=wkR zqgv=-_Evj8KV9qLjmiH&cl?7LS(46$XsR?|&G!*U!Z0pjzJxF$(kFz-C%_PH2-k<7 z(1#m285$xD;mBh~dT=-r4riIB-1{%V)gWJgQq=z!ydj*@;R~R@e!vEi!XgPFL;&p@ gTIuZ%KQNi8BUj_%T#@Jd^o%TxnHx6lGM*si- diff --git a/android-application/src/main/res/drawable-nodpi/symbol_104.png b/android-application/src/main/res/drawable-nodpi/symbol_104.png deleted file mode 100644 index 8b4473d861b4caa22a9c338e3dc7798402f416fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 849 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$E3QC&U#<|HpwE7#IW? z7z!8|<^vTmFq~&#NMK;t&%hACz;K^|;XMNb(9nbghK2@)|Nj~K8yNOCF!VDptOuI* z|9^nA+&Q2gj*=k1U_dkocH}>X6l-*pXb!Ym5zMZ#g zA5Y$R{!>!ulbiES*~?sgWg+)yzx`VO`eU5)SthUV)s$qMYhN1@YQJdF@dG;F&iwf* zeBq2$%j6SRUN@X#QmAJ?!Mvbgzgg;SPKQ!G{nO8znDp4zNU_~I9)8)o;p_({rYHj~ zhIbMiTS}!i1b<*>OgJ}v`2s10mIIUScXW5OFm!yfWZ;nN_#CMqBIEGnvx9;T!&H5S zxEYK_@l10JA{x$#GpgTkv5IF~W8hcZ6H>=i!ST4id*TUy##KA35|lnEFSw+U$5`N& z9Lh7rv`>>^k)tf*Gt&b#au?P!rdA2^GPFHWdX#ZdGUVjxj?dWz%7RTCH=d{Oo0@-J z@Y*ZU1E2oPeXH7DTEzQc-u<0&7nt~eJg;BrvE%@gRdP`(kYX@0Ff!0JFxNFO4ly#aGBU6- zHP$vTure?>Z__#zMMG|WN@iLmZVmeqZ8d=!BtbR==ckpFCl;kLIHu$$r7C#lCZ?wb Xr6#6S7M@H6rE>;PS3j3^P6;E zK@n7nf{-XuKoKJatQIs%t&NI2WW!4#JQf;+^=>$)fA+`joSC`je)oRg+%t2|+&l)I zwr16)RS2Oq9`3F_YU{kbbUst>WlfnM)MiBl#fyT_ErIS5OH=LRL*0G65K1veh@Xwn zM>WJBMd&C2p>ZZc`pGO{ZccE&)o5UkjcR0^&dND8f*u`4W`L0nd=dOA2T3cG-vnni zNaesx1DPBMejx3F_C63?h2Q&t5eIr?=vRPp2JkeHbiwToXn79tdC=7d?a$#)1q@Aq zpmw=_nMJ@;^-X@w^P&5qegQ+NCuNr7Wl}zYFO~JjD`oM{5+z@v?3c)7N?E_GU&>dO zOUnDDGJ%w-R0{YB65<}U0EYby&6PxGZl5mmYXH^=TJMVwTZ3Q?Iv7sRe z&zRb~czJQLdfl;0Wy!-OC58AU>8IKEc~w!DY4Y5*L#f-uSUn1|xx0sdz%)BjIEP_x z9$07Wt~2%c<9yal44OV#C|p`omdHQ4Ug#j~T*gp%_ zYEV4;<#^$X-zaIT!W*IxKh(Fye<8+_bL)FQ1$LXYgE#$iub?K&rJ52Cm1mYrf5>QB z6%*}Z@tUyvdVyXJqsRV-cFSg=D1oNsb2k&atJ%M-zIedyz|v;AD6pmbVaSb^@FMcL zTGIkdua-u3NI-t6y^XE2qe(}KmZ*Ey9IYJG?as2Gqw8XwUk;qso1NR2NBx;(-s~=K z?n zmp(lj`{~wz17nA@iaZvNCP#}t7Ati zV#|%XXDMl8U*!$oXU_%8opiSEbS8~vZgG^B+Fw!|M z%7FX%?6*&d3rOuGCBihLikKd~9bGh7-?bjz;Et+bsTNIs9wbbE??$uor zs6+)Au2GN(yI5nFMA~Tm>?Nz>xI>_y5W6AjV&gP(onk%eUMpHrVE=vt?SiT;j9mZv zMe~pmMirSVV>URJ4C8b3^{elEDQ0K3rRDf+xl^~}L0Ge!@g{NB#+9854Z?R0)D?pc zw43d|)@FyX^Fxf0jQr={Tbo-S%)M^$2D4U0{h==H+ur(nDNoplk?kBkrbv%TnOJa} zJRefOs+RMc)f?S$?%-r;vBT@&x1WachsQDdUgjukkN;t4UOYkTo!|Or`q6YgO&VVi zk}NvpGa?xc4Y{j2+@JUgTHf2bDb1^Dyb8?JADkJF8psP{@i^qrM2^}ZB7sP-A&_hc zc78-6nMfdiZD&OwkO>6Y?i1(!i@=QwiwaNv--P=tM@u!~^W_tKZsg5$$sg(W9E=BOJXLLOAQtJsB^^&fbZne6}o diff --git a/android-application/src/main/res/drawable-nodpi/symbol_106.png b/android-application/src/main/res/drawable-nodpi/symbol_106.png deleted file mode 100644 index 8b373175c7a320270241d9de6251c73ac03f71a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}l)W;J%8R-pT=A7tHI<}qLT^W!BhmGMF1bJTKwgZ#q4 zu#LIKj}goQ6L}Ku1_w0FI@*Ce)e_f;l9a@fRIB8oR3OD*WME{VYhbQxU>ss(WMyPv zWooQ#U|?lnaNeeMDvE~O{FKbJO57UuCE98NHAsSN2+mI{DNig)WpGT%PfAtr%uP&B Y4N6T+sVqF13JMwqPgg&ebxsLQ0Jr9D=l}o! diff --git a/android-application/src/main/res/drawable-nodpi/symbol_107.png b/android-application/src/main/res/drawable-nodpi/symbol_107.png deleted file mode 100644 index 0427f9e1b12f39ed9c298e102c2c19a0bd41ff5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J(0C&U#H=O z_9yJjVxp?8eYw#A_Z>QbvJFLLtqS(MWUFF~Z^>=fkLq#8)5?*rEE+uZU zWm9Kv&Y88*|Kq-`d^+jo&ja~^E{c6SF3u9De-?N2>`(uuUs5Z17=5A~QXFr2PheT$ z)$rtbuGj+JhgJ!l^G>{1QaJMU&%C9RytH439827_=*$0msRbP+FaD;de_`nVG4s2g z{h9L%SzQD!Of_BDutHbP^L7kNEQc7|2i^=uzHjoIOE2(EZ(zDLlff+ceqRR1(%I|@ z=3j$(tq&Q_$dvrhAD?CGSoL!H^_crhitUTFLhqSQI$IjQ#9?*e&Zx7(x*|u{ZK%s$ z%ar43vad02@gk1N*;1R9^cK1NeJfe8-|+YGVtKtE=MUBV=jMOS8c~vxSdwa$T$Bo=7>o>z40H|5bq$O|jEt;|46ICz zwG9lc3=GcOv`$6Qkei>9nO2Eg!@fjYO`rxzkPX54X(i=}MX3yqDfvmM3ZA)%>8U}f Wi7AzZCsRQwhQZU-&t;ucLK6T6kNmv= diff --git a/android-application/src/main/res/drawable-nodpi/symbol_108.png b/android-application/src/main/res/drawable-nodpi/symbol_108.png deleted file mode 100644 index f6cd514907c0186f311591a89f026f9283c72603..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1415 zcmZ`(3rtgI6#i?a_y|cSb2?Gi4yiPb?2d@>RTCU7`iq|m?$=H^`oq3p{P zy?xcXaA!lXZMtpF(f$U}RC# zJznF*RM%*lD~WPEXbuh+hxU(=7sq1v$B;9ExHxrn3?8JQ@H1m*ChPFmpAABc$*Yhl z5i3fDqs%B7kCWjDD;bGkNdm(?R4jqVahwXr5=jgvs7NfCj72Gu2vgBmjKHyYEKK1E z4=c`$;t3K^CY21waX^U#5oLL>SR|%TWM{xZG>b$i*x8wI&Hy9TD=sfhy_ZUVZDv-> z)>;EXlje#Ae3h=(O3qFR(lT3~cUiioa?NIYZ|30qS%ds@)XipDG3UtIzAPr@FWRO^ zZ@zQaHzIm6lAh0JEz>Z=C)z#6z?4&**3BV_sI2c|U)kM4K4;lS8ESz>R>hZdxl6MO za!NAu*fM=el-AmAQL2?Ut_)o&lMToQ2l}_fuU-G)$7_YmtqU(qemB$F@gneWC~)G! zCwI1AJvLOY%xgH*Q<}m~r_A#VohrTBq+I2;A9hx06IX7!HnjiN&9((7))Bblodye z@Mv?ztMr~8Q9f9^5~iQTx_Ih(#Z#*Y0{oP7ca)O!)miK;ajn^D XSJ=%q-`W8?{2dVzm&yd)E6BhgkE z_4M@2oH?_hp~1ny;mnyc`}gnn_4VDndGoSm%hc4=q@<*Zi;H=Ad5X&z$WETdy!m77rXwHfB&z~7Dnf56uP68+iY?Ij!Uh zU%&s4pc~I4-Kz%2e{Qb&9V^s%<$w_)q7{k>0q z7_WKY^j|ah-^-elo8B1j|MzyywMua0;`1*tCD;|H8d-FXGQ{Di!u}2!6YP_m1YvVNJaAYi0 zFIZ<8|Hl5g-sB%52bx|zRam<_<@Cwj{EAnq>RS{}yEH5oX<}$Oc+keiXreYp)aRE1 za_c<~r|q4*wpjMVjt$J2RU2Fwo$ENx?dfe`kYt*%!|`RR-VP29LFI+IQ|ha~{Z#Q@ z#l-tR(xs_kv06Y-T^!fz54om|*7FaFO>m9&eQ-)WBZJLM{D@fpy+2Fz9QY3HbI47+ z7=5g0!Q$;7dsTM5(LLNaPigs2ft5HwTmuBTZRcJutv;a&|DZK@IjUJO0dA;DZ(|y-i>e48>J>b@@GEh zbf!s-``d~`cCvqJ=T|FpDSmj{sn+f);-oqM&o=%~E1SZPYS?}}{__HB<wFiyj_0J@PU6=kl?QEQq@l{+FVHgq{y-IgxwmxF9-L8Eo6?FT%Q?yW7(x|y+=wk zFN9CC+C8&%t3ih1wuS5O-}qyH#D3n3wOsFAukHn=J=GG|h?11Vl2ohYqEsNoU}Ruq zple{RYhWB=WMpMzU}b8oZD3$!U~t~1bt;O6-29Zxv`X9>_9fbC0yRj2YzWRzD=AMb lN@Z|N$xljE@XSq2PYp^tu;Ty# diff --git a/android-application/src/main/res/drawable-nodpi/symbol_11.png b/android-application/src/main/res/drawable-nodpi/symbol_11.png deleted file mode 100644 index bce59d80314e02d72a9d28d717f093fbce00dd23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 784 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J(0C&U#=$z$3CVIpE*_Z2wRJOEHhbU)KJ9VzF79b9VRT zFNe1ueCEigckD+HtF20c(*xxi>9`Hdj5}f-E{eKXEKr%azlCGL$E{vWiHe*by8XGG z+NCwzKa?|iiCx?6puizg(=JH!FQV%dSbN;mYSlkAtL><<6ksEHs3pO%c{l@f? z`}Utbfd@;nimq05e1CCo<|m0w&yx?IPS=!us&sXB@ciawffLfz&HbZyM)#a$+nv&= ztsKtqe06D7lKqo!TUyU3mYMa<6_tKr+pCto(>OUUP3Y*P++N@y@KN}v>oPmF z+WdzJl?)r6Gj7=MtzM}A%-I)$ufJt&ELXSOIiF*<-d-WjHgQWHE(Uqez4{8Q&!plN zSxeShFAhIe(PGN0UKo{hRNu;nq2s5Py8T%>p2WB3m|RpCokcw+r!D3>vhCT5KPH-X z_xp`}*0Yx}CVrUjzI$W*Jo$hh%yZt`Ure$8;0}y5)e_f;l9a@fRIB8oR3OD*WME{V zYhbQxU>ss(WMyPvWooQ#U|?lnaNeeMDvE~O{FKbJO57UuCE98NHAsSN2+mI{DNig) kWpGT%PfAtr%uP&B4N6T+sVqF13QDF7p00i_>zopr08`5%2mk;8 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_110.png b/android-application/src/main/res/drawable-nodpi/symbol_110.png deleted file mode 100644 index 02a3c4988f3b3ce3136551d788073c41d0884f66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2328 zcmZ`*dpy$(7ynJeW^Ti3NNz1zWagHU`!%*?s=2hbSgy;ZRTz(LSy2&%5EChhN<=A_ zDe`z+l4}ShTDc|=kxuX^WQni9t39@DHSOI0AyTU96Uv6 z^V=a3qWCa4a!dr^KwG>m06e`8+n|bzY7KuEPdos`?g0Q+A^@z3DAqRsIEMj%X$k<~ zvH@U6MBd9ImZFBlDK}>aK=|A4)R){8F_H{dyrbl#n(NkK zE4fvJ>N8kZ?5HK8m0Sz+GD(N3*(Zr-HgPR>7c=6 zAcEwHmjshg4frBQbLpq|iPs($7B$|3=qx|4f{b^lG=?2bjNjc8g6@E@Jl};+l@m&q zRfd&8cEnyog2h<3?0v{+mlOl#my8dl9b8~2 zDZC7kj_t{h8;wCV)0S62o4MN_Ll1AU7hy{oPUw!f2+5Lg2UXmQ(|ex$Sn~CnhQgtt zaT2B)*Me7`i{;h2(}kKf!cUmn*Ll#(qo{EOiZCD$TrlY1uw2>b(NO5=x-F{Or^i#ZR&N z={G#KPL_@PN=8u-5p&=^rXR08tR8$VD76}CDi-%`q%L0Q_VFm%XF$&TQah-+@*a*- zs-*9TD$M8mX-|E0_uQB;THI`0yFK#H-#X?JdA-=cD(HK8f07tw0U;@=7iDL z`)&qrK9!4jSTbOXH^U6i`zwP6)#M)~K`ogX=flVnS0fMmx>+{9AmPdh zE+0dx?32)|zH#rEEE3HW?03MOC9Y(h*X!7CzH6N}Ge2rERl;g2 zb*t{6R&VLIU${J|2vx}=^Z4?6CpOplz0RbBSv~)IMTLIPGPK;xD>Jn1QCKf6gU!EK z>YIg?X6cKu>=9F^FmGSV(y*A~UGc8Yp~Y^2m$TCxixC#e^W8ioWd%w|WSPr)Mz|MVvw$B|8rrYIB7| zFKba~c&puHV-a?(iBW0~_7phd2zL-LH};!kii~mpitkemu|ks$GyGGzvax;?5IgW# z>jj~Ns7XjXre|z-na(-e4cUZslCsGzIiax%o{|E=-Y+|v39zg!{Y%G_038l7Sx2{7 z_Zjg>GK^cZbmY#(^I9a>#2q-y=&EkjRb3d~dEfbuICQU&%W7~fS^$@;2CS$PgIZBD z(fhWm(4B*t7`Or{ZcP(VdeLdb@YQ5C**%9|toJN&WPsK_iD>GF|KRO%ll^zI;5gAnrb$ZYWGPXaq&&^aYv&SGGOVQQiFM(fvr!Aig|B1?lNSm z*~(UScXHTPvRv@;)U64}YMZ&ktv!^^+=J^3aRP0Z-2 zbiv2D6kx6{{E4EbYkcu>NIlc|E%VX=u2Z|=NQApVG~(lhS37ygw(}{+z{ed~-}T~w z7*2*t{-feb5L<>WdBKsW0<1i%{Wmn8j>%YS{FU*9v(Oc^jFrJ4D z;)U9lj~%;uPbhb#qjjxk7bORkmCLhLH(E-5E!LmRlsinQJ!JY**VsfsdK(4_UYPfZ zyv0hde8u>2*0Rcz?z;>0h^IfjcVysy#j{Zo|!*v%}gr@Ll&h(*tYvMS3+3bMa$~93(H>YkRisD92jf0HN>u$E0~D*|^&uGU?>h@6YQLFYW%iw4n$ z-I-!*k$yGk+eLD76V3LovJXb(PFFe8zO)6Gf(|%G&FqD(Hgbt0XS|2bC0IkhRa!mL zIUt_sfdF&^7TIQS`y}eOROkzTG1$u%{h>(GwYI$Bafe7Wh`s_8!;!=YpfYGU z|0tRW04xTJ(Z`tSV~o78SR59EGcnqS!Qe2Mcb44D{}Ir`1A+0yT;T*an23qG`C&sev?48Z{s$vW@opT>)Gj2@a3#D4c%*VDJmz diff --git a/android-application/src/main/res/drawable-nodpi/symbol_111.png b/android-application/src/main/res/drawable-nodpi/symbol_111.png deleted file mode 100644 index 7e8b547333dce8a16ffbb9f9c23f5637a0eecc88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1117 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjf!V>+#W5t~-rJe>KEi=A$L$|5cu)3@SrQyOORvRPr|)=1 z(3B&bF@3D17Z>qaG0tY@I^sF~5L4o!Ww9lhGiT^cJF+r3as_vhr}!n;_T!7+d%gFs zUVr3BUH%UH_vP=u@4R3A{@vdD2LqgWO|Sf4H_`6BvBAa}hXU4JwOr_wdf^0{S?WKQ z9QGS>2EASrpW9s6dFNbYFPq?APM)GQTl^>cOjcVfVPR5WksDudGbvQO;UuHxORLj5 z!gg(@T~jhnUDoOjdCdIe#)NazPq^(^c!Ztv;ifa&_CH}?<{xYGvzKn zQa@l(-1DQq_XEe1jYl`Tm)@IpSX#0@SL}E90k-o;gr9nTdm%T;=2?d^!{o{DY85S* z%qk!LGwz&sm)o?`%U9-HNp^<7$jcBtdwqGi1) zJ!kZP>P6P$Hwuouzp?qSxKSVf4^df$R}y#HrFtVcvWx!cSF~!h_k8HTQWuZ`2$}b*qz<`}U)B#Rh>_c3zWSHPyaLaOxH^ zRZ~8CFtJxQ>QTz%=l`Y!er~Z0dy;ccN&1Gem&omnMUii=eXU{_$h@V!pHt`3lBrjN zCrg>i$b9`8o3PVZQP4lkV^-ANQ_K-DaZW9&YtElsojpI{>+k&s4kdL>IUYFG>bOW# z@nL7)ujgOtC)+UgI6k{m2FzZnC9V-ADTyViR>?)FK#IZ0z{o(?z+BhBIK;@v%E-XV z)L7fVz{-L1;Fyx1l&avFo0y&& Yl$w}QS$HxPl;;^dUHx3vIVCg!098iL1^@s6 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_112.png b/android-application/src/main/res/drawable-nodpi/symbol_112.png deleted file mode 100644 index 3783dae0051243b2fba4833f9e92293c65b5a97f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 670 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*WnC&U#_1s0E_J4Xv zGe?QrhM3G>ch~(F-!w6=RHjYR#e>z0YnQ`8X4iAO10Dyle$xD~jH^a$Lj$YMjn~Z= zkI&KKNL!X>x9;B5TCs(h5nera)moWa%ycc|SXyWAJtDf?@1Dps1{EQf9Sh!Yo!h41 z#PmbMU>n1}Urpvs6&d`i^5SkY)!dF)KB1iT>IY2=CC|TdtIg!s{r0Y#)w5&M=Cj)J z7wVqoL_gQJj{3K6V`b=zProkz1zP??pYi9~JA1APuUaru{DpA)hop|ZoWk73ZPKY- z_J*^I*PjM@R<*=6q9i4;B-JXpC>2OC7#SED=o*;o8W@Kd8Ce+_SeY7Y8yHv_7@W6h zor08-nxGO3D+9QW+dm@{>{(JaZG%Q-e|yQz{Ejrh*a; NgQu&X%Q~loCIH)k+l2rC diff --git a/android-application/src/main/res/drawable-nodpi/symbol_113.png b/android-application/src/main/res/drawable-nodpi/symbol_113.png deleted file mode 100644 index e64f65c7e9058b81553d75009567d1d02cd67521..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 665 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DP5C&U#}Ozj4;E|yx`2VvlILtumI7l40S2ZkZ#c< zoqH}X`TWY*NKOBVgIA7`z;)pp3#y-`UcS{`5Hh{&Xq=RW0)u+=P1aK)92yIzF^F&k zD=cjAFD)?meEcQf0ZE_SgLcdX-0HyvZM;7o$Td&sjoAOm(bL^{ORxY8>^ZFrsvON2U>5h6!B-hOvb@EA3uxPs%x6vmp;`M9xbn5P}8J+agF8a zoqt_`LCc_8;u=wsl30>zm0Xkxq!^40j0|)Q%ykWnLyU~9j0~(yjkOI7tPBj!+q6za z(U6;;l9^VCTf@FYTTP$_NstY}`DrEPiAAXljw$&`sS2LCiRr09sfj6-g(p)%>4m}5 L)z4*}Q$iB}_O{mX diff --git a/android-application/src/main/res/drawable-nodpi/symbol_114.png b/android-application/src/main/res/drawable-nodpi/symbol_114.png deleted file mode 100644 index bcc7fbb33ee2259c23e128c33bcb16752423a8fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 664 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*)zC&U#<;{u`#4FAEX z53C{qRo!g{hPN;U4q&MQ28R6%4DZ2$0t^iI85n?C<})z#Gcc?NJ00kV2B7T!|K_p5 zXMkEHN`m}?83g9vKi^Q`uz$b7`~HN6fb|OR@81_V-*8)S-9?}p#w2fd7quvk8C!uI z_7YEDSN13D%wnRdt$n%CK%wiNE{-7)hu>bg$=75c;1C!UeO7M*cl%B4`lpuxP{P$BfdJmx2t z95~p|B`*kKc3hs+wPP>3*}#i?`eB zlkbLv2LJz5*}%ZWQSwoaql8gtzfHZp#-fb|mKWJKsP1BVao^d#X|0Pj(2J@it`Q|E zi6yC4$wjF^iowXh$UxV?T-U%j#K_3X$iT|fSlhtB%D~{fP3u$?4Y~O#nQ4`{HS9~Y z)dXsg1lbUrpH@hTC9q1+ZWN1H*nW_dNrH00YB)28IL%hV={#^BEWdz)lA`q5-Jj|Nnd@ zN1%ZW5+y-?!3+ZP@1IY2-*2$LpkaT&`~H3hh4uIED>PVqdkfUaz?kIi?xGgOF=H!` z!(QU)>&pIwomos&wY4ud8Ypzf)5S3);_%z)@#0PfGHvNfi#aalq;$RiFB&}M@6H7~ zPiCH9d;ho0Jxgf@i8^`iTNTgOoY?(?^NQG;j}6PU9Tp#m*XHOsz|r&IJ!^Z@g-Ie) z*FBK9B%Zn@<4zINMB%>ztVSCr`RC{aO`ZIpOLWRwsguH{PgjIC*TiTr_lO&WPU!j> zA*ryZVFi;)=#Q-mb6+ob$a=PheV#V∨6Cb)pSVl_!3la(;<7ho0r8&mZRU7w-+X zJb#Q$zv}0{8{3lCWN+UiFVQF{agafV^;Z1rlehk}PWbXYA=|zoQQL;$y0puMdADCK z1o~68#5JNMC9x#cD!C{XNHG{07#ZjqnCluChZq@I85vla8fzOESQ!|cw`rYa>QWZRN6Vp?JQWH}u3s0tk(hP&AtDnm{ Hr-UW|BhA=c diff --git a/android-application/src/main/res/drawable-nodpi/symbol_116.png b/android-application/src/main/res/drawable-nodpi/symbol_116.png deleted file mode 100644 index f35baf2e8a5e28e4dab22fcc80ee5e7e41f537c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 682 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@+1(C&U#<;{l=!4FAC> z0j6jbnDLf@;WkVPs6YWG3#1zu81{pu-ZL;1Ffa%(Fx+Qg2w-67XJA;*z>vVe0Cb82 zP{IHIFD&gqK9MR3@(X5An16qN!ux)Q1|ZoWP|$C1|GvR_frfzf`}OL8wlOd!dAqx4 z?A@?+6OhAR;_2(k{)C-bOjNbCFE<(}^w87AF(l&f+v(SZnhXS76uj<3FJ#p~QP(~f)mb6tMj3+MjlxE?pYw_Sx_}v+ji^d109aO$Xy&U;WS2^sL*nTIC4S`-U`= zI}D8M?uT}5-h2({S=AEPh?11Vl2ohYqEsNoU}Ruqple{RYhWB=WMpMzU}b8oZD3$! zU~t~1bt;O6-29Zxv`X9>_9fbC0yRj2YzWRzD=AMbN@Z|N$xljE@XSq2PYp^lk44$rjF6*2UngG^O-2VUo diff --git a/android-application/src/main/res/drawable-nodpi/symbol_117.png b/android-application/src/main/res/drawable-nodpi/symbol_117.png deleted file mode 100644 index 3f2c70d9de214841b99bfed08d519a92ce4d1fec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 690 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*xwC&U#<;|Kp47-oW1 ztYTmQvJ+scMHv|0F)(Zc3j)P~$N?;+z`)SYz_1@I@*b>SfPvvY0|U?n4GawH85rg> zFcdH_oM&JN0IK=_-)YV=kRzl@g8YIR6z0F*A7Ie1UcezCprHSK!~OpK@9!I&7jT%< zHk}iwiZRLC-9;;S-<5el4tt5GuPgf#c4jeA)z-e;XrRzzPZ!6Kh{JEE-Q{aC;BjMB z6BZE+xpJ`0Ug6h2eGRT)H+_Y@28Q2azFTYFy=E{|puQp1y2 z|91J5?r?Bk&n_-6@kCvLbe|7~Ho<<70bHV;01&E6xvN#|1hJ$8@_q`utW)hfEB+UVG` zZ0EbqA`di7-k|# zY-V5pia5YTM1fX*Njp+@M#MAo)nZCfU=T8gZwEx6j`C1x;z|DlY)^21gcpQYUu-x$xisJ;L0 z%ibattC?@Ue)^ifCnU2nb^jiIkhLa9oC+?8R=ofI-n{KsQpeZ#yeTSq*G;`2o_!d5 z4(LJE64!{5l*E!$tK_0oAjM#0U}T_cV6JOm9Aac-Wn^GwYOHNwU}a!%-llabiiX_$ zl+3hB+#2>J+G+wdNP=t#&QB{TPb^Aha7@WhN>%X8O-xS>N=;0uEIgSCN;eFiu6{1- HoD!M<1VPi8 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_119.png b/android-application/src/main/res/drawable-nodpi/symbol_119.png deleted file mode 100644 index bc68adcbbeebda931f43964f91275663b6f6e4a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1100 zcmZ`&4NO~A6h3{grL2U3i4K^?JzZ+tu=81hV1?Pvc5AheM_~>Jj+RoeBbAPoO=iqm z7&y0O%}DA7gOwJ?KdsR5(?Qmn8vGesSLFcgc?Q6| z58y6_%vS+wXn;92fan-NlCkx4UKRlBWky*bLqQ}GF`Lck{Kp~y5p*&a<<#y}iAmP>3W+Hk&P#O7(jE%*>3(jR* zqZST_8HVZX>}+ms?&#>S+wD%L6SEG7V`yl|=ktw>jNm#wJ?(P2P}bMihYqHCdV2c% z`!PEj;q6$H8(+f8EhbfNJ|gX25UYb`hBCWDW+u^S_4yWpYM(fS zYBYkyNTNs(B(cN^l7mJP1dAZqoS4{HZVZPV^_KB?aXcP!wpFRUhOJqpuWypFB81>a zBwUjsN5=h$ORji~-*DJagy}|wR8mkFxPG)UzfSyUBj3%p^~@UhYlZuV4)L0%rVc63 zPBD3l7s8Q9JtcUgQ$2Fy)yc)0;JvBy-v!Q>dfvQG&M)t}YW(!)w=Q$vdE3&JYTOX_ z*^_^ScUbnFGKz)|t{TAo) z>zlJX&K<0=iPv6>Z^^!G;s}P@9Z9#joNkx6?dYXFtnH`B)s|29p3kk~^|5^0v(lJBUd7u1n9KyLhwYOv2JhUSQoSs`Vbv zSlpV>@CL+clc8^nfXd_*+xFhOayKm%9>2M&{_~1s8x!|YFRnf!X!^L@u+`$+C9lp{ z$={z{`;8pHf8#;nyty;w%5QRu=CHmcocY8nN49*BnjH8fGw7MuKfU84<%vJ#C)Zv0 z<*c$%=YDs+>sHJiiFs!$Rb1i8@D{J%`(79G><>u?6HYc!Szmq6u+^D$yTSU@1N-Gk z0e&RDNmgho)0lK3ZM6;ogtU+r&=~?ctw1Og329M!S}IM8XgZkHVEb2rp{h(@Ui<$A yXEfPsupnh=hy1E?({4?*4kTq&r8-Js&{XJDI!#&ajxTliivuWRxl-2#b=_a!eV{l1 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_12.png b/android-application/src/main/res/drawable-nodpi/symbol_12.png deleted file mode 100644 index be5a9a48e952d650c572839931c5069a459399f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 725 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_125.png b/android-application/src/main/res/drawable-nodpi/symbol_125.png deleted file mode 100644 index 9c121d548c326549dadc554e4e9f3d14061f2860..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1186 zcma)6e>B@y6u(2rgbrO3E86(kcI51Pg3zEul1669BBC`NO-OXzm>{M~&r-#@t$uY? zY$98=IJz=3Z4?W|P^+Bk3}X_*(6O#zrCQ6ry3=#EKen@b-g}>W-}~HmKlhLK-sf>y zmgd{d0l<Tps^75ScE}iVq6HH19038K%N7zj&8~4 z0n!kFyFvhJ82~|AaXri*J$T4_MZiSS@IMAh`^#DYlArqjf#U#mf4esR2^B4b+C2az z04hieAOx^N6+UT93ZMqipgjOI05~~0kw_#w9?#`+^YZd)YipaDniL8}W@aXxPRHSJ zQmM2MASx=VxVV@H;Opxvkw}&RQ~(bEZUPJf^Z-l%+yPhs&;xV=i~!7_!VHFjUrkUY z;3DI5!@(*@u5OSbLd`vGA;Ob46b4xd8&F@W)DX35B2TGQx2M@PqWouKLs<;IrI1vF z24*rghiNurW{ltFnp==~2*4C<-Wn1azW=_mfXIeWA@p$IlP6>uGNimx1BpNEZv6U*xv4ub>DAHs;66?!%uR& zmP1>)NO?>yMj5}{w_WVKFG4CfGrBOWxbKy9!|98m!`6g5*q*OOC_~me9eqB|H95b9 zqFSh!?xMEX`l-%os|My%L&Q^~^Eoj$G3I)_V{Xfb@@_iKy-r8P+jNh3(Zs2kXiP)t z>9fjcT`!bnn)g*UdpqOYUMs&_v(k2+FfO%;;ix@&4P`G8RESZa-S-P>5n%!D)mH5$ zx2LA-04rF3)r_a?_Ofp_?pd5857<&2hpSHf&-c+|Z{B59J$7S6tZcSmz z>bRxOqLnJ@>Bny1v*av?H`|i)t}T|4BB%B&Z3(E{>0$AuX;;EWgC)02<2FiyC_|c> z=Bt>VG22v=iRl3CgSW8{T?ndRqZRw?aej8vcy=p4dq$06I-JnrAM5;cuQ!hEnlxOT z=(^BPbr$fqUZwaAKlWyIf#e@5*yK%=8PP*MMD$j`4 z<)6y%t<*2`FYVW?n&>@FMee97{v&VFefj6z{Sm)mudK9QCcX=1x` z-*D>x`g{NPKlvZ9^}oWx{{plB_h0z`{>OhHIRE;8!k+*4Km9K_{NG^3|M}Pdm(;R^ z15M^B3GxeOP?-Pzd_jW2euw_`tq(440*W&xdAqxa)m&U53FNSsc>21sKVfGU6IE^P z%Z&y~+jzP-hD02GJMHeYCIu04H->b(AkODWtC{5)rV5@RXDocYO)`zB^A4f5I+ z`@e{9=9Yat&(39>Wcn?z--vV8fmtonlwSC>N$Ov4_Dhh7y3lr_UonwfP$o z98H2AJlN#<-$8-Z_|1mqW8zJx*Y1p(FTkpm=_g{bal<~w+C3{~c%8{#tu4|LJM%&* z!zX7e<}QVttdNe1Mn2b+DSCo0KK_e3Qm??8Ehp#c;do>J#g9gf@%1Y!XC4TDFy+}q zrit_I;~w}=+86QQ`UG)qm)!w+6^E8{T-ux~T(dyo=b->re}*RJNCv$-rjZQ#r>`hB zbZaHM-%9;HTQ%gY^eB}xB3q5nO+)v9`*g*-55RZCnWN>UO_QmvAUQh^kM zk%5tcu7SC(fpLhDk(H5wm8r3|fq|8Q!Fik3sVEw9^HVa@DsgMrmuRaA)F276Aviy+ pq&%@GmBBG3KPgqgGdD3kH7GSPrLyp3Dk!Bfc)I$ztaD0e0sv)^A`Ack diff --git a/android-application/src/main/res/drawable-nodpi/symbol_127.png b/android-application/src/main/res/drawable-nodpi/symbol_127.png deleted file mode 100644 index 423a8248aa869b58dc700e006034b10aba207f9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2346 zcmZ`*dpOho7k_Va9cqe=zN%4FuAkP|B`s}C!^|zpB}Hp&wC`M|OfE~PR4z$Exg@2n zTp|-!4&$niDS^-mbXL3Ec2|uIT6_8kgBMUDTeIPkpFS zl&0AMtXUFTgURn255;nuGzsw(DzdX;;e$wGidoQW8kx?#wlW}5Y z1MP=6KJV%?eo&dh^>xs0_8SjTx8{)-%k)*Id||FAGQ@Z%IcTQ5rR#WNLtQY^SE
Q@_t8!ACm5k#Un#*zpQgdAWGZ&5^%32F$Y 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_13.png b/android-application/src/main/res/drawable-nodpi/symbol_13.png deleted file mode 100644 index f26b2ed4b3748b08f5ca3ebb221649068d07fb55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 695 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J(0C&U#<|7Qp#4gLSG z^XOA4P^UmikY6xELW6@sfx!9s2JiO=++W}SO=sIWpd4e8x4Vnrqph~PfE@M`PhVH| zC+y5(qAH&{W6uJmZ9QEaLn02popyUtivkZT<4%oNJpcc1&3?NhxKY7!R3Pe`aeTIkNxq92`~%gX%pr%&qP8Pj#+l6=^wBD?2S!-wPH^EwW`{<&ZF zqi5WgKT{c>|7PR8Z~USntz-SaO$*vISN=S_VOm_mzM0=-_oZL>cxS=W=;nFrd4KcH z%kzE1EcLO<`E)k#oa49dbzGOw*ni*Piu>Y{8J~Sx<}bd(ck4sd+=bz54Zmc+T(xJ> zyyH>te?%G{&RBQr+yAu1n;z=EkvXZby?>+QuK(*5W2J2lT-QB*)tT|3w)5xN>5B8D zq#BP`BxNis`1ktRSr1FzKc+1_a{mkM__?OBzPlI9qCJ1XPsVazJ7ZDLLoUFuRV{Ii zC`m~yNwrEYN(E93Mg~R(x(4RD2F4*qMpi}!R;I?<1_o9J2Ip;Br=n=c%}>cptHiBg zU!tuhP=h4MhT#0PlJdl&R0hYC{G?O`&)mfH)S%SFl*+=Bsi4%v;OXk;vd$@?2>>v? B8TkMJ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_130.png b/android-application/src/main/res/drawable-nodpi/symbol_130.png deleted file mode 100644 index c7ae8accd1b219ac41b0c7466f3c40e3bf06d2bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 838 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DP5C&U#KVlGu_eK9*@_#AE@J+7Ht6l5f zoLFQI; z=tkiM6SfJlJE%PsN)!#?QwwEw>SH-_EI@tH&y%OGTwvh~czNDidy+QSgbe!*+oWBZ zJj@rk+y2d)rO05_n6#<3H2H|tgKN2aU;cZ(VCw0Hb@}GmO`8_Br5=c3a^^A>OE_OJ zy*G;WgFAzR8^aX)grzJd2lxz+x82yfaSOu>GrJoePKoA1lQ(<6*fD8wyJv53LczSk z$1w-F70V>kjn8*|{TKB6H3w_L--*{`n>sDUMUON3B$T_w-aP*4bN|=Mrqf3+U9sJJ z%VEim(^LD!7IFz%GTq`nx}@Is$P4*)cDFM(&Tv1j^q;ey+wXpG!+mdY2ETa?n;GZ) z{UhJv<6Lk#lc7TQp+|$6+&>1U6E`<@#aetb=i<{-`tN2x)9e7>8s7b%fzhT~;u=ws zl30>zm0Xkxq!^40j0|)Q%ykWnLyU~9j0~(yjkOI7tPBj!+q6za(U6;;l9^VCTf@FY zTTP$_NstY}`DrEPiAAXljw$&`sS2LCiRr09sfj6-g(p)%iJQUG)z4*}Q$iB}el2Iv diff --git a/android-application/src/main/res/drawable-nodpi/symbol_131.png b/android-application/src/main/res/drawable-nodpi/symbol_131.png deleted file mode 100644 index 2cab788ee6e84ae156c2d43e9bd957f044d1865f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1046 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 B?Na~% diff --git a/android-application/src/main/res/drawable-nodpi/symbol_133.png b/android-application/src/main/res/drawable-nodpi/symbol_133.png deleted file mode 100644 index 621c150c85b900699d1e7c3b8663e467dd3826b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1007 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}f63FuF(l*O+Zl=lw+$p(_rE=MCV5W*`|*P78yY@{tS#r2 z=HS+l(BRPKf6=?eM&Zm(>EMF1wTt=YePC13?n=JtwI}<)AD%^jHZ58HJpR+}|5!ecss3K$f%6}yFZ%IOwr#bm`-4|3c009%zAg3W7qq;+IO4zr zfrjf{c6lXtTUjmzsU#hlH$AB2Xp7{WBca`5EM0nhFJ=dM_)iZ?@O7yvc|I@Z_2nKm zrqichbgWd|z_9JewYihlGx+G7%G=`OWcvPon9C*yCPU-(a#A82J}VSmyKNjhk+JsK zyx4MHZqn6tx%CPD_huh_G*|dphss=n-u=|Row#R3xYeW z81sXF&D>GazG>mMk0H}cm5kozn4urTq>MHyqUSIC)|V+awl_lP7)GNNGQcDt|J! zh1qsP6T<_!1&Mv1JhqFmOySmfwu{Xv=}{DumTc>?XkP!|Ree&%x@mrFJdKJ>ofeUb ztj}tkKP~yX+o3Te-cmq%^U`ze$`_dP=f0hqJnfcl+yaNh9l}K{jb*>RzQ|gKC~++@ zzNp3#B=r3Cu11HAdHFk-g`O?=YGK#cC8cfkoX@XpD$_jAjNdh;|4+mO?3cd5K7F&O zMXL+L!mZ9WN+(Wa^C<_nTsE)LcfMNN=CCNtfid*nwQXhdMdr?bX{564a`69Z50wks zC;3fcWUP&S^|E-9%7$+z7XMpwzU1DrD|_$C^{mW|ti2t7m%oH%o!o>z40H|5bq$O|jEt;|46ICzwG9lc3=GcOv`$6Q zkei>9nO2Eg!@fjYO`rxzkPX54X(i=}MX3yqDfvmM3ZA)%>8U}fi7AzZCsRSWkipZ{ K&t;ucLK6V)CY?S2 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_134.png b/android-application/src/main/res/drawable-nodpi/symbol_134.png deleted file mode 100644 index 57702f92d88bc51703c51e766f2c211918edbc38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1403 zcmV->1%&#EP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 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 Wi7AzZCsRRbpTX1B&t;ucLK6Vy%}xja diff --git a/android-application/src/main/res/drawable-nodpi/symbol_138.png b/android-application/src/main/res/drawable-nodpi/symbol_138.png deleted file mode 100644 index ae3365aed82fce994830ea8ef3b5622d93baea2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1047 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*fqC&U#<|NoB<0Tn>N zf1pYvHjD|@i!23G1fxN^P!P~MhzLvti2MIP=f-+jprP6&L4Lsu3{1?79GrqIBH{)P z3JMPW>-P)1zc0ByA)!EOf5ZLx0q@T@2=oijH()zIeMKP~P#a^Cx4Vn(*;|gbKn{C} zr>`sf6Lw}XQPtMI+-RV2dY&$hArXh)hTJY|G7#{Yx@}uimw>j2%j&%=|NpPmJ*jr{ zuEMd$&HCqrIcJ|t`KENF*Ko(Qgo@~K}TDZqe|GLngL(eVp zCO+6dS(C|j#bVBbZ!RdQvbeWfTF!r(yCH;y`-Zp3!A6gYVis?wfE71_1ozB7>y>-W zA}{Ow`WM_wy3T4ercG5TxTn5AaEil6|E*QC`utaDN(=(RiX zUcKLU|Hv`Z$V^7dDplFnOY;}6`LOB}lZNB7n-M~e8{^js)+%k^Xe#UJ5i33Cz>J#_ z!u|^9UHKbt+zvBky3l*}r_RE}hki4(9Ubm^FL>W#bC9$6`I^N+wI(n81Q@(mJX-eO z=Ee?pPh+7H>5X}B8)jEbRSgg-a+gh8EWAKPgwgVff!V7bugi9qvYUf1q=`Rsdm(>U zt^MZD&lC3SHA&UJ82sYGyX_aN;ufV!70Dgj{8swJ{zFzB44q+~>oaXx793;R&|)+} zL6J!y(Sgr2Nauj3#dWrMz1!X_Tz%{y%PlwaU6T%&6=+1>H*L&Kn7HxgO|KLB7VFpb z+}yRVLm}<3HD?Yp`$;u_(Q9mcHmM(P29_O{z5alo^-hCIzM}ggU}91&ag8WRNi0dV zN-jzTQVd20Mh3bD=DG&PAx1`4Mg~@<#@Yr3Rt5&=ZCa+{)nT>gTe~DWM4fHN26} diff --git a/android-application/src/main/res/drawable-nodpi/symbol_139.png b/android-application/src/main/res/drawable-nodpi/symbol_139.png deleted file mode 100644 index 9b5ddc8e4960500ce1d771acabef7ca8135ff4c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2177 zcmZ{mdpHw(8^?chtc_02c`K>SgRnWIG`0!lu*Dowp*bJt)W|$jQwpUL%P|YJ%2`@$ zQ(6awDezf4@83nQ%lAx*ZAtP_#d4LzF1? zPi~Nt)bh}nL5au&xXqo2!z7eLK*};|LB)b7niqp{H1E!8LWt#hf7_-b1%abTp&AUmeg& zn`0T3xXbHjVo`quC2yqehh$XjSAV_l!gnI@_^?vIE(}TC%|wSU@7Pk$vvX3Y3&5lA zemdB54m*La)gOK49cnOlKAFeHJTc6K8$Y=17X;Z*QkGF)fOn|)UDZa3g#}-Yw|f_^ zra*F<@DA&mMFCFOYI)9d6O80MAdA-SV9FC9=cOWjJr3@L()9Ut>?nsxh@-$qcFJMJ zzbuLLuKrc0xNT%H(yBwqUx_e{X+$Qv&k25){)FV+Ts}htP#ef2IVT8Qgc7y#8y$YT z3te1y_UX%t^u*?(JHqtUvA=2-tuS6Ee9JtCFR|c0Lw55@{JZ?)$!`feytUUG&S3uF|E&Sy2FSac|`~Mm20lyj055@L@RTPnX%M0IZVQ$Z_w$)^d+^^!+Ti!urA4KX<2d4>86V4 zqr-NSAr7GS#i8$687*`pNA9(l8!F8SN|rM+a}7~*cWYnyh^XkMTK-bA?da)q`HnkA zjXk02jFWDO!!yN(P*zg(!fDJ`g+h`4uSZhdw>IuQSq8JzBrT(xi3^+S2yq`lc2 z8wTRN&7;#xR}YBIAPXdGu4!O@LS%FnkMCi+k>=ed&zBM}?4;7<7p+|COtuJ8i|`M) zR^xhN1j5QIJpZmi&-W9XvrV2}Pw#D|x1wB{PD4+Q^hLrr8&@^6BR-`0;fTE5Blrv$ zO;%~MmpPesX);w$*?aS0SV#mM5 z^7J_uJoV%wXMUo>3s^B`DqhZQLnyIvGljE_r^@|ew^f9XZSz*8!04$n-!=0n8cyu> z8|>V4BEAsW6Z!cIe|h=u?4F6gE32N!7kdux9{L7x0&C7Q?9dr+>Tg2?N}nV(a;`m+ ztpb?6Pfn>lykflT?QoA_tJ!#)3iD7RW9j?H{OJ$VeJCd8JQFj|Pdvf*e7!ejCD|wr zB1iHnPDTZW*YD5gO0U8ajtur&Cb>gx^u1au)$>3Qqzy>5H+###X@zH1}>+D(fh!% zaCV}*xQSM)!w2FpGicM$Q_$~x3aP5Lq$)mSmOD~2z4K(vk6x8AE0&_NhPRfwdOG_$>aK{tM`tjL|+Rr`w9K%COrPNU^&7td|;E>1-k33$<+Oi?&Ku;<46>N@m{EDkmS#*d2OZ9qFLfskj=Gu)2Fg2ZA)7V zdM=IjuzJvZ!K1W_o$np=xZV0&PwqnZ@`DdnUFE3}P1s+IN*>wYr8wcUyTyts_*_B= z_>@R2(s^CLA^%*$-MiNk^+oBj=B)Ce=kYh=_MbQJe2Ruw+_?{9xZbV^uM=w7Y%uGK z@T*E?aa1Na6C<(QgyAkPQrmwtf{XD<<9>mCDY}W<{?6-gitub$SQt;(v?f3ztS!0!eI|un;wMXoj+-)ovJL{ln;y8> zIG_aF^llMPLKWe_#KgoBqBTV%?7IG<>sXrcn@C5v;tRnQ$m5MIjQDN9KI90*nGnh> zVfn0KWX|2WObYeH>MGjCYlD#@DJ)TMN*U-SWf)A#faQ{8Y2?H6X{O^p`X8r$8y($t zt*8i}h52PC-9Yc^>XNJ){Qh>?z#JH!TM`t1Qx5~NTrWQ`|D*rRB2&J2*Fp-h3;a&H|rNQ@T+U$QP?M-4R*F&T!Zn`jzy z$GTnD#P)@HdmE+4+~lke?~v&(#udrtgsdlFbf2$K?o4&hcdvs&6_;1ucZZZE-!GhE z>q!alr36~|#|BCS7$c3521s)Qq=}ocv4t_x!puY;iL^i>JJ6SI{f~hh6%ZOk{r`q0 zUrSwyLF3N^*Qg-MS>M<|fD4H73)HeF`vwOR1APOiF>eF^+y%himS9tDO}g+evhDy4 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_14.png b/android-application/src/main/res/drawable-nodpi/symbol_14.png deleted file mode 100644 index fd82b6d923d6fc54503e05ca6e9f7f0a932f964d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1420 zcmZ`(cTkgO82=#bAt-xEzyPx3BMd_XA&>wcvNE6`1`?7$83`+lAg&0~fSzE*s*PwYKM|Jy2}*PVe*&T1mc)FN+MJ^uzY9cfIS~`#$6MJim86&%Ki3!W>s8 zeUz(*c9ZbJK?usIsXg6_5bn>T%~4wk_&oIk~g~0O$?}fP=jNU_qgS zO90Rg0)U(a0L0S(;L|L`xL=$f#*nM1=YqLf#uYZ)rqsKljlrgp>7XN zoe(Q`a)e!+5kkBsd#8?`r)QTM_X^DYBFo3(chbR?(P7Ic{iXvg`YHyJk^paTQALF# z1iX$8>8nZ%jVxnly?L<5azbo5*=ruyYwW1gRZtOPg2Kx~5s2Ohr%nbnS*hBh97Aoz zatqHSZZr3HnLiSl`Z^5_RSM5d3O^rZc&IinQ&*C&XO$T0n9I%F9up@F3>%2ovVtG42h)MOoFmu`2lzLJ5Eh^n|Kg`cI}QNs-nWw@iA&bJd%;3ArUnhDM;FOWoWS6&Q2K|sEUq&U0q<$P0HW^ zg|`R1!BuW!Be%C(TU#4yO}T?MpRbTsNCz@lSFp3Qpjxe-o1Jx^dp);q%{9keqK=?B zR@J+5$WPzAxIBqE_ClzDV!vpQ@%F-LCCp#Y@O_9(VwBzEuzYPtS)ND5R4^0R;y!fc zQ%QLyEpK<;ku#DQWz5&#v}&CO@*WLDU22ROgKOUw)1S{jd-~gxUl+E6i`)q2?9}kp zLz3|`Gkq8PMy|*Ej0@h}xOzQdva?y(+R@V9W}Me8hQzPnZr|S5v$}$@J}l14y!XSF zDL&*336e%1Y=xIjzxdYFJOAU@{NhPQB~7opIPU*tE%z*s_qO-#kw1R#_xAMm(hakK zQL<#ZsIFW@>EM;L7x4MaeOaTik&y$`8_?(sW%~NWozX9@MNi-QYWm6nYl&UHG*R@3 zp{rY9);yLb?Wip@FV5inuvC20{$Yc-Z_qnVmfIm?-fWz?>qK*5LG%(y;)l;FWG`xF z>J9!s^BR;R49JmeCy0F64i6?TWjDQ=YHT~o(Vv=lX@Z{2eUH1v{Hg1H;XCGrTXb4S z-0N%4yMiUc? zFyRDMdJL_XQ}*2kY?vRiooiQ81o!$N#^Esw@y Vb44u=dFU4j01%~+d^wXP{tIgmY)SwC diff --git a/android-application/src/main/res/drawable-nodpi/symbol_140.png b/android-application/src/main/res/drawable-nodpi/symbol_140.png deleted file mode 100644 index 89f5d858eb9c67727d95c0362c7f59cd4b94e2f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 861 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-1U@Plzj!{{J5z0xEz5 zh)M_-nGF=dVhB)>f#C>PwI~C_TLuOdxIqjIePCIjg3SyJp)m0T28R7$@%Ic2>%qP~ z&%n^nz#zcDP{6;T z6-0REzZd5-NZ2pQFD1;)CUE|I|Ni^;3j`ec=O@hHf8N{ruRc&GW0JSKi=Af*!($+a zy~NYkmHi1jvzVxAYhP|OP} zzt`)|jasIXIn6Wef!hCE3;CHk>FLt9}Y)8k@6hOZ6W>g%VoBW)X8qozIW ze`V&yu=n*F26hVv(X;ibg^Rcx+8Ac!-HuP;YWN}hSkGvE`NcE(d!_r&9JuH00SsK# z64!{5l*E!$tK_0oAjM#0U}T_cV6JOm9Aac-Wn^GwYOHNwU}a!%-llabiiX_$l+3hB z+#2>J+G+wdNP=t#&QB{TPb^Aha7@WhN>%X8O-xS>N=;0uEIgSCO7je!u6{1-oD!M< DLbxzJ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_141.png b/android-application/src/main/res/drawable-nodpi/symbol_141.png deleted file mode 100644 index f5eaaf83bfa494d70d72dd7d7740b36e00545729..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 784 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-1d`Plzj!CJ6pBFaS{* zn1rw~Nd|_KKtUi$2r)E(&AHDY2~_!>f!Bax@p=aP{R~C|40{q7>i+-#pRb#p1~f^v zB*-tA;e5eJ4U|^#ba4!cIQ(`>ba9h`KtRc#k|X|yib~C9Zntp&Bjx!`B(71y_9#R z=tIw}kIFXT4dVYew%mWd{lVU8|2|$|YLI;Q$GM1seFxVA-5WXg?0@_VSh&c4oqgDn zhUfo-+}7|+KDJ)zoXo!S3|jBr&tEm|mwU(U2DxGpr|BzrXPC0r=`lR(zQ$3%a@OC} zOK<%Z4+~Am|Lxx5`S$!mV<)x^hor96-3VQ+`P84`65oF=hN74=Te9mJEW#QB-itrA zJM(|*^p64FOga5ON-`L_O=mDaKNRtItC_^a;y+hbz3g7x#I!-mLA5E)CVFKodnrHP z0|veV)rPO{b83~RPA`lyn8Nv9t%NDB>sRzCFPYik2yl%kNl7e8wMs5Z1yT$~21W+D z2Ijg3#vw*VRz?O^rpDR^237_J=WSZ2qG-s?PsvQH#I0dpqOB%SgJcQNhT#0PlJdl& lR0hYC{G?O`&)mfH)S%SFl*+=Bsi0)a;OXk;vd$@?2>_o_5o!Pc diff --git a/android-application/src/main/res/drawable-nodpi/symbol_142.png b/android-application/src/main/res/drawable-nodpi/symbol_142.png deleted file mode 100644 index 2eb77e732e8f34d28f09e3189bc84eb5b8d30214..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2232 zcmZ`*X*?9_7k;`2X<#o%fvQJ)3000z&w#9PM>URnr z;MRsv{2UkfLaa|)1JHV1WY3?U+p7ekv8Mq@&;)>#2EY!NA}s@O2?4+-KLAWi0g$_R zo91f99UKU7w6_KOzoW9dj?85QVlk)f1l|kq%F1Y@=SQC7GB+`{*6#7sYqxwN++N6# zdLCKEaRSk>RuOmWP@2!^>swO}jhB>l+8bQlgz6u>|Bx*((Fa2_y%{(F$I^I0`oH}{9SV6WJJ1|mV z&fNEg$SW(ae>XE|q2@OmdxRfyb+}_mSQ@ID;-RmM*WJhdi*LTNN)~lK0{ns(fN}_7irQ zlW*3l9IR$yvrygsUiks~{IkqITQufBI8^P*bztBl;-aFqVf=LAFttHE?d73M3ejjy z^3c#wfs-a>z}w@j5v>?|7%~_JQ9+B#A3biYUK`pLI4H((RKI#IBH%qn>8{?|!g$T0 z+&abh&G`KE^z<7r-I{!5v-pRPqaY^vZ)Z#FqN5GSInXB&7wj|3x7??n`}*Mr z*WXi09vFU9K*Mt~(!{G~GAA1O!QMl6drwa}Lq}QWEv3*l(Iq+a2=#X;tXh8%;Y4ky z>>X5i9=4&U0%BVgKe@5IZ1om;-1~s4n@Y_+qaZ0A(&o$szm9qlW`|?5c~`2kgw z1QO~UL7ptYG)BG(D^DY+Xph%YsYcNi*KSLgkQ%OA58?xAcFaalx|lc8X#Gvm(>aj^ zZ4A955J72!ntP+j0=PnZ9+lt4Syomye#Zvr}WvDI%yJ-yMn0jzS>Ith_SFbRHc5~U9D*FQ7QcJ->CR!1gk zMRq_HosKh|7{i*WgKnK=ckVC}qbZ=&>!k{_qxamApBEJ28mi3Nx0dXXb#n&cS6)#A zfwW4~Fftetn7>%s(sDE*Az}IR=l(W5Y`t{F$8M=bUdTg_`f6jBfnRl>WUN@(kzpWw zb}i2#Rtciw+HilY&FhiyXu62pz$Y1c9#yoV_LP@ybp0a%K3suBKvM<8N!qn*0pkHL z(EOx8cYib-_Hq$q_&33abc!o2(gTY{pT?~zI=~YW6Dg66>9zy{`!N-`Pz6l#2{({3 z^EQ$;erILbYyC9GrsB>Lfd^s#S{QyJQ{svSNZP^csl zDB}0e3IqZn+;dF3A-F&DRgXVFd*aj^q2BtEbF@o2jh+v98h!IiAO$HBvk1_#ntz67 zW%UkxplKP4k__Bdee?w7zk$jIegaN^y+^n`ZI$Nsdii06L9de4)mE{ZlJFgc=S=2C z+bZLa*!Fk#sq?q6_7(4H(Y7g24*5KH_nZ;L(d{v&Bqnxi-8yr;AGS9O2Fnf(-Z zyx3;oQP=8l)?)YiG3nV@@Pj1jhaB7Oo01nyMY=c;)ygS$T5nR!j)az8BLR^C8 z`4BAHy5KEs;ccx=B^JEWYwoAPSxKHfp)S#+rDy-7IV}0uy zmO`tcS&A2#(RVYVsZL)?wp6-bDyS2zXEZEBv;%f{)fS|Lt}?Dz|1y$at}EjxOnYui zJLXnpQK0cff#>~g^d>!;eAwn&=T49%6RfDpI8Z{K zB5m85>ZPqJm8BFUb4rPJxxwZ*wZUyTzDyF}iG~mt+tGutI<{e_{P22g-@6ZcoIf#@ zln`@z{jC)*$5Bh|!w+_LZNFJBXzc!gjqcvuP~sY5nEF1i=31yion%-5*R?fb?Yv@x z{9|#ZfiXBP03-s5&_|rmM;N*zk)}w5sga>B0%3|kjF_bt|BoOtIw&-l`2Ph@{mtQA vfx_<}+@gbHFZ;*ffOSxG08RxH=^ui_;{1b%_!qd}>jc2qIor0__+9%C3B~(p diff --git a/android-application/src/main/res/drawable-nodpi/symbol_143.png b/android-application/src/main/res/drawable-nodpi/symbol_143.png deleted file mode 100644 index cd50462cd062b7adcf51c2ace89e3654c808ed9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 816 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-0quPlzj!W?-0t4NV3L zGBN_C7#tiN{{R0!Y0{*IhK89lXYSas1IPt}>({S8c<|ur)vHI29Jzh__Wk?!fofK* zS_PB>3f{YS@6x49`}gk$a)Cze-~R;2IDh{2`t|n;3JxnMESx|8`uq1k5)$?p7_7K| z|5HQ5DF=u3{rwjN1ZEeyeFj?3pi~m%7tA1#uzr8Q`}qeB9AE?jCT3=47FJefW+o;k zW>z*f78a(%%UAFMRWl}eySwmy+miSd$YC$>^mS!_!pmS*Y3ftseED~A`ij2#+672Xm zDr^%))HNPVGI3pS^u$RDj87Va=18z< zJThixvR^I0l6uePYGd?F-UAGOoEQB1*Q}MgAU%bl_TrULhM%jt_vI{J|N93!`@fTy zD@r1-z47czEw$P8YUA6T%E!08eYa>g!}UYy*JE|2trk^G*;}Xh!C8<`)MX5lF!N|bK zK-a)r*T6W$$jHjbz{=EE+rYrez~H=1>r@mCx%nxXX_dG&>`S!O1Zt23*$|wcR#Ki= ml*-_klAn~S;F+74o*I;zm{M7IG8L4J89ZJ6T-G@yGywqa8A@IN diff --git a/android-application/src/main/res/drawable-nodpi/symbol_144.png b/android-application/src/main/res/drawable-nodpi/symbol_144.png deleted file mode 100644 index a1544591b9dffd9a69d50daf31094cffcd29df5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1464 zcmZ`(X*d*k9R9nRV;Q#)xoU}-9l05XnUH2&6IzkM3^H;=<2E@KxpEsMO64wchqO(S zSQbg-c*rpeShEHR6C+29C8c-0DxOt;T$+@_HzVzIS4#D zE^v_72TQ;L(3k~1B=d2!qL-Be0f0y~02qk?>~mI(RRF?J0IYccU|0lzR8VQBy)oy& z?P+6)14qeOgU>ihAk>1SnOWkub-(%+vzQ^u8otsHe)%3GIqIZT31xvKH+awkD z$!b%3Q!vg7Vj)Q}v!W{)*Sc?D4sXJ|U)vD4Iz> zwv+N>Xt3K*FUkOuf?N=04l7<=Ezs{0g3`tiNXm6TeOS@R0x2eavi}zwDR40GCF&n7 zkLHxXRMvWtKzakztY&X@0a@-o;+V;LBO%Kcxe2Tm4??#jorHr1GQ(d7;V=yK7fQQg zvpnvZVN{WQ+G+lB)-6al%yHay^>5{Iea!k9hZ}NRq^?8O52Xnsaj4%d7hj8O6*9IW zbjO0_y118aF&AL(Z3K-{Ol&9~!NsY@!H7cqbcYe+ny05}lvbmH0?UGcH)`+?&`oT( zQrl7eC}nd7w!8FIMH#x!6ya{MH?X&qekb0jryc38?xeVWQ5Ur^PvmEKIeBF1WJqkm z0hgOo$m4e%c)_mci#>hFu|-=3{SdPw$6J=a`>fED2pMX#k!MIcCLot$>UWv| zL;UWkJpZ1JJOus`JKDlL*X2HmcOFW#oGPnHFguRJoQ$#bl03hp?f-%1o48~!n(B-PXMbN|q91F^^1|B7-v|(4JIdGMHy&8!-VvA= zp5`9uwUE=NZHuyH%$c1f1(EDOV-XB(@>P>xNY~@aj+LnqDDt#VawddG3?n;*du%c5 zezqP|@%;Nd?HFoHfA?0KC-|%}S^ahqceSZxLbuitN8qNpYRr=i=3xRkI^=2f+NqAE zHunZSvHB*h&7zx4!fNuZ73WP6uS%Xwe*Olz+?w1qacP2BTH%wNJDeEhMhjwMa-kRI zsK&8t_I)cougQW_{c&Wd7n`@K$%3X&qzT1;r zxc;4Q)Pl7Gd^HQ&@>h3zcCfC~tI)VI39YnE8>x=E*@d9krd>f7Wnk=-$`C>zhcedE zKV8}>tCcSkcP9-a>-_bqrXSh^w6Jmtnk$cB z-=Q@bckVS1;b%C_r5cKN3H2t2QVhL9C>#Q46dI+8($hp~lh9~GG|Es%TLXnMM4^U_ zlk)##2nh7{qelF{p@(epE5{)7^Mhj`HIz;cp#ZFRpeIGqI)Lm$aiEaBBZ6O3e%2|l M#uIT3<{t6?0(3KdN&o-= diff --git a/android-application/src/main/res/drawable-nodpi/symbol_145.png b/android-application/src/main/res/drawable-nodpi/symbol_145.png deleted file mode 100644 index 7e946a60d93b4e633cf2444265f20e58b5be6b57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 852 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-1d`Plzj!W?+~?G@8uF z07i_H7#SxrF-`<(-p|1BA7~2$L#!J^XedLTCqsh+Ly-)~SObF<>(}2aC^#%2Fnj*| z>;3%~_V0i4|NsAnhEoX%d(NMK9T2cpL1E$j`=1;f*1v!MWBvNOKxh407jOrtTdpL? zFPK50VgLFBf&TaB9qtk`ciVGe7!J)U0>;wWW|7k{vp(VlsO>4ALKHKmQQ?0=XSe6rJ6%)7z+z%wHT z>uLRce;<`uSI>xGWe_;Js6SXtMZsogo0r1u=YE_^@>44(X7I3lntVm*!3S%H72GVc zAGRM@uGe7CX%O2`?!X?xSi4ffoI#EKz?7~~{m`;KPaHnpPUbze=(J_}yery2-R?h| zJ#qKc=w&S{mK99<8y71tv83%o=#!j3GfqhMNihXC&q>J%`ZXcdY_@IJndil~x6OCS zvA*f)m1(_HxO>H?InPr!Ms)32H)+q_?vAxrj~C6{HrYFqv4+{vvvZRF&qz=bP%Uwd zC`m~yNwrEYN(E93Mg~R(x(4RD2F4*qMpi}!R;I?<1_o9J2Ip;Br=n=c%}>cptHiBg zU!tuhP=h4MhT#0PlJdl&R0hYC{G?O`&)mfH)S%SFl*+=Bsi36J;OXk;vd$@?2>@9o BGqwN# diff --git a/android-application/src/main/res/drawable-nodpi/symbol_146.png b/android-application/src/main/res/drawable-nodpi/symbol_146.png deleted file mode 100644 index 7045951a587e67085c8e0687bfe2c6a15b705640..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1187 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 vu?1p(931?-f}h1 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_148.png b/android-application/src/main/res/drawable-nodpi/symbol_148.png deleted file mode 100644 index 616ad5f90694dba43444448d8b04e4c77b583ee2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3440 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 LZO!V=dQtud&o3gr diff --git a/android-application/src/main/res/drawable-nodpi/symbol_149.png b/android-application/src/main/res/drawable-nodpi/symbol_149.png deleted file mode 100644 index ae22f7a159b29ec9a94932d68c8fedfc1cf7aea7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 862 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DP5C&U#<|Njpp@ByF# z2tre&prG*n{rms_|2H%=tY5$0!NKAF{rdp{0sZ~`0s;c_=g;52f4_l&!TIy&3knJn z5)v}jdtL_`AzTvV7tFwrAP}JNe*b-ghJHpS=J^HZ9hgj#_5r0Clf2zs#A+_CkOXqr zOFVsD*`Kg8i;1eX_T@$crB{2pIEF+VemnK{t|kQmx8qlIF5hjuvS!QW-}{p@WY{FG zy!*B9ZGAekb{Zp>LHarUG{HW;&PNNCqV?LAALsP`bG6{8g!eUO<{-NU*Lzj*X*rKy zD@T3(I(5CAvEVNLeN_{$Fb6QNusakIF8N6!p?Pw%P1>@9D?2$HejTlO63Cd8ePW|V zq1Ng(HqTlP+NmekMarzL%3;iDF3o)UadweA&ABAN@H6&bvO=JHUFN?SFD&&TVg<2S<5Z9yb)MT)xFLTTfl(YVGY^ z3=s-%Ey~?$gE<%$taW*LPW9v2lXvI;TATCs=iGz3KFkNgszWM+*lHWjJ-$5W|AW=H z4u&wi*`=M@B7Ns@3B#M2vzaZ87BjM!{}bEC_{CSk^U!;Sb3!%qOJ*<{KUmIK{4ew# zQ(0#D!i3g(U`(o(xJHzuB$lLFB^RXvDF!10BLiInb6o@D5F;ZiBLgc_V{HQiD`0xD zX`PCqAvZrIGp!Q0hJA^)nm`SbARB`7(@M${i&7aJQ}UBi6+Ckj(^G>|6H_V+Po{zr OJ%gvKpUXO@geCyLyh!N) diff --git a/android-application/src/main/res/drawable-nodpi/symbol_15.png b/android-application/src/main/res/drawable-nodpi/symbol_15.png deleted file mode 100644 index 1151118c59737c5b21e24fde754f850537268a92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 816 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjPAlXY5&^ys)Q>V@Srmw~?z-j66RnHZz^%}S5TSb(h*o( zfAiX3Ca3l+a>L4Xo?^Sf|aH+ii7J(0a-qVMfNz+TR6d zJ}NC~nx&!f!ETv$H;j!DS^_r2FYST3Hi$*teqg4I^t zoh!279ru)dC$={1`jNEMJgloQgSW&BshjjU^z{}! zaWs>&lYX*JnL+6Ach*yUHy?$?B=t>wmKC3vSHaIvQhj*NX9xa`8}Caq#W%AusM_`H z4YkmUS^gklzn*mF^#$keJ-)TgXKD476}PRw{okA4v^zhA#pz&W{(UQv4Nq83-fiF2 z;asnE^bq6UYfD0ERK9=O=Xa#)$fe|`|D@y=9XxqLU`x2&^L|c+w{;c_CnnzduRqh^ zq1q3&4b|5ZvS#i7223%kC9V-ADTyViR>?)FK#IZ0z{o(?z+BhBIK;@v%E-XV)L7fV zz{-L1;Fyx1l&avFo0y&&l$w}Q US$HxPl#CfXUHx3vIVCg!08t!4Gynhq diff --git a/android-application/src/main/res/drawable-nodpi/symbol_150.png b/android-application/src/main/res/drawable-nodpi/symbol_150.png deleted file mode 100644 index 3c1ca5f113ee22e09c5726c0e149bfb512db520d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 899 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 D)J|0K diff --git a/android-application/src/main/res/drawable-nodpi/symbol_152.png b/android-application/src/main/res/drawable-nodpi/symbol_152.png deleted file mode 100644 index 40994599c1420f739b3d455025e8a160bdef75fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 699 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*xwC&U#i7$68D zdjiZAMN;a(z|aR%GZRTXfPrB>So}N#LjePW00YB)28IL%hWS9p0Ug7@@E+`q{R|91 zH~s(r{{;UwbD(yqk|4ie2F8H<3GWpg1lAkO-+%x8{(=U9hJJ_n0S4zc&EF>iRK=L& z?e3x#yzk09Acwug)7O>#2|KfxsA_9pZZuHnji-xaNW|f{({2hiDTp`}9zG?u^{hdR z*V=#o*|SxGckr8BpE*nFoc0{$<}RVrn@(u#lQ(#=LH3x8^!wdwj=Hkj2o`LxOZDHt zc%Q}R0E^E8?j`Q$DyNBi)Ehl*D*ATsYtzm%P31b_r!LrhXnb$fD*WEkxS=W}*g#pD zrGk|^gs&yx(1qtK%Qz=m#d$VLu_>Ju6A4ndzE0uW70$B;1&sT|SC>2L&S9_Pto?Cv zX`;%;xNnWVO9X-zrT^A?GvWNFf45$p<$P&>?^tx)^_Twh+0_!5{tI>-XX{X|`EuWC zqw4{8b`K#LKF6l-yz?LOUH#^B=kvpyFrdFxOI#yLQW8s2t&)pUffR$0fsui(fw``M zafp$Tm63s!sj;?!ft7*5d7IX$C>nC}Q!>*kackI@XsZd-APKS|I6tkVJh3R1!7(L2 gDOJHUH!(dmC^a#qvhZXoC`B=Ny85}Sb4q9e09ZrbdH?_b diff --git a/android-application/src/main/res/drawable-nodpi/symbol_153.png b/android-application/src/main/res/drawable-nodpi/symbol_153.png deleted file mode 100644 index 52e724a5704cc32b7571185c6813c7d06a52f027..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 695 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*xwC&U#i7*;Vb z07(eA&A{-Efk70;h0_jTHGN*-+#ZqKS4pjpy7RgLP5a#n_{nW zfa(~Nyxm>2g7;mS2jsAqc>21sKVfGU6IE^P%Z&yKJ@a&N42d}WcG`2kCIb;SM~xL% z4i<=Whg|!;e}S7rM!t`yZ_LY|w|~zy+pcWNbM|_&AIHX=uQp2MS9txDXRLS@dub7C z)B@J1519u`#O7-*_4Io7_}OQJ^G(}SPER#xu@!%E-9;gJZbMuV(}&g?2Cbx9!48eW zpO{#*Za6p?XB4P5<;+;FDx%Q2;0ephkc6(sJ9Ajqt?8V@kk_o7w^%<+q}itVCx=YS z0T-Fsx%xL08I4VzypjLe{3zAJ%)K$R>*wv_9fbC0yRj2YzWRzD=AMbN@Z|N$xljE d@XSq2PYp^lx44$rjF6*2UngH{l;HUrq diff --git a/android-application/src/main/res/drawable-nodpi/symbol_154.png b/android-application/src/main/res/drawable-nodpi/symbol_154.png deleted file mode 100644 index e9296614c5ad89b956b6da7ee9833970c62bb285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3438 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 I;Qru$02iWiYXATM diff --git a/android-application/src/main/res/drawable-nodpi/symbol_155.png b/android-application/src/main/res/drawable-nodpi/symbol_155.png deleted file mode 100644 index 2c23a0ea505ea9b554366ae80332208089d866ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DzHC&U#<;|Kr2(xMCu zZy6X0!EB(&HY7a>3=HQP7=VKN85jf@7~X?j*}%YXpMe2rs{#YVdZ6t8|Fv^Ms(`vg zOM?7@85-{IcbIR`zh2?JK*Ij}{Q?OE0q0e2zSaXOU`+CMcTtK>jadWau$OrHy0SlE zXBHDxZSBjA1`56Oba4!cIQ(|{YoR6u0k=RC{h7B?MMbyV`>&cE#C73PWcsR1i~5Jw zN}JXRCH*Xw5pSsav4_9h>_*Ln=ZY@R7Ax`_20id(jA#@EqBWu-s>y4#7TnUCHNPb! zdHSY#T}!X1bhuT@m%N(fDHV5^BVUcb$yV^O&5reEK9@9_%A68Px(~=a^I1Au;Kg@` z``kZniTZH7I3qX5^xzN8BWZ_y&PYz3wExWW{J9q{o)mFR>#_9Q_aNn+{7XLMU%#fEFJyIG>YOaw z;-(Muv}%cKL`h0wNvc(HQ7VvPFfuSQ&^0jEH82h_GO{u&pIwomos&wY4ud8YuM4)5S3);_%yPulbq`c-$HpyEMYrH=mmOz23#N zVS^c)k&y7&bN9bldv3qDAhWC9-P|I5S7i2WRkL>*YLyzD4eTBd9<^m@H8e?G z5a78k>=+Q}Xi?0vRUu=Af)K0XI`gK6XD1(jC~&tt`TPsdOWRqyJZzrztA|{E>oNQJ zAF&vf`$czrC&sCMKEHlr-tBEaU)C;Q@%kX&bUUi?KKGLU*M8e(>O{uRZ%bhO9QH)? z{v$@wqi#ystJtD|K2|MpjVMV;EJ?LWE=mPb3`Pb<2D%33x(3D}Mn+af23DrV+6D$z z1_tMCTBo9D$jwj5OsmALVPB%HCQySU$cEtjw370~qErUQl>DSr1<%~X^wgl##FWay Slc}I2#Ng@b=d#Wzp$PzFcH1Wa diff --git a/android-application/src/main/res/drawable-nodpi/symbol_157.png b/android-application/src/main/res/drawable-nodpi/symbol_157.png deleted file mode 100644 index 876867799845e246be317df9bd1884f3667b514c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3278 zcmZ`+XEdB!7k)8}-g_M-N({y*i3u@Um`fze7tuzq5o9t18H~h`kc&hog25$v34$11 zh^s`RN3X#s(I)CAKffQ}I%}V2oqg7`_m8vJKF@x6*VK@OQIHV;02Y*yzWF60{}?^p zC}n#@(gh?GQSM~A<_VVj|70@OBa3(00LkDukd`h$l zbC0@s@NDSdugCGE<1qB#>fZ0LcY~5`g~yiJo>=dc_h-i^78T>=Q5q97u{lh zK0ert{uS1yX|%uFvYuQvCZN90L0b>AQKL!S~hsAO&C z25Uw}M}I9P-Z8&-?^bZIMnOS=9SN7dw>n7ULp#Zb(P7G>QP1di=QijS=^?3S_5%yl z6&`I=FL+~V4a_hu)ll9(5jIF64nX#EJ%IzZqZC~AeJJom6)(4?oyiByUvcB>u?)E5 zajvz9X<)U{=>g9p9@8%`FE>jkqF!`453j9xl5yYZ_m-)M9rKkM!mL7-BaFItO9F(L zqvT|kY34M3hdiK5xo>49v-zVTv9S>m5j-ir!qhtYqXcUM8yRcj$wNUE6$b>~sf8gT z`P~)@h@ADpe>3iVsH3FS6Dim2hGPHK4pl0ybsp9+V|^qXP4Wqi$!oRk^IHDkE+=(=;yZXtv?|?8PpX zBdzkn!Odyc`n}cYFr-7au4=Jig+r8SVJ0=ifip>pV5Dy-o1go^Zm!DjRD{noOF~%{ zdqPuLOo%&aNOj;n-<+ELJZoX{q@E51&lywdrRupV78w)c-9GPpd{PT~?kHO_uf!J0 z_pQgMBtSGK{~1-~GaCQ!je^w3D6&It$y0`~mN>SXL;eTF99iX?wQS>j?Q=Z%p8L3r;{mXb4PkssZpNa zU)-~OeGT-_b6EwoZ&S9qviiPu%nWuhzAl50mFOQBe6=^CueW2c$*nCVIy+3Yh!kQc zcpFb|QBz^^D(>jPy^tl%@~NPjFJNSaL(HsS{s(SOhJ@wKB7O8BBwjm@&rUnIt6wR6 zVu@y(NL~4?rj*#e+w7vq+#ZUXyJn({rUj%EBZ`ZEeQIjO%KfF$=Ex!aExKEVbD|2Q z;k4MM{hDBTb$Mm~r)`wK1pqJb-pDxE5CNk#zNnGuPNyf|er;}EpN-`c7mX%L(8QQW z-P&_v!qlN0sGpQAK4vrbQ!LT zFZ__sikK}v)bUDwcD4eo23RXfB*T{hlX9wm^!P=}dYa=ti>Ln!&SkVdr`aM|Np6Pd zE-v+O`0}>1P^I~t=4O+6TX(+v7#Uz~5mR)Cdij!VHr2!%b%lrcb&Z>?r%>P7I}ec_ zDQ_hmt)qSoDx;`+SDAE3siuGgy{bth+|8On{$FM_1hDZ?cO=wIp+`89Uk z*0)IAlI}H+iOu$u|40o7N&+kU{;Cg72Mooy-klzrg@mx|?F80b2&H(%279TfH~HOT7{m zb(VhQg}2G!^ekC`@Mg$n?7&s?SJE8smT?{HT{%_X2XRdbl0JIGFS3o5Js#j`4bX$Q zeA=sEy^zeT3uS3>(1QT>_B-7|{uA4|F?_IjsswxoGBf_w_8_sLt`nC)TQ|#Ck+Jh( zvHe(EN!`4?2IZE-ELOXSgYGI$0 zRGn`mMqj@uxzK$Lt}3$KdCLMelHyECN?M{#U?EsL2H|ht^QZqHCc7HxmKMq!C+di` zJcvw|H-1t6n@&i3kIiSIszaHb858KU*~tED1@Gf^Qm?IrB1cW{@3;E>5H&q7BAh>o z&oK_L(7#WO28r&qDM?HOwZyG&Y;--{YACF#uI6k;$A9(gbcDe)HJMu*9x*1QVO@;51xLZn{*HhK9z1)ufMVCNo`?hBytrjmVc)Inin{R*=?=^oReY z!ezO9cHYJfEaFCo_s&mF`)8U#PeU||rmS?f8mqscm#uY?jU&H9=XP}x-yvfO|Fn7s zDtCV4=BQe3`uiOR^=?&Ft5k;;0WRFSj0vtz4-27pjRP|tSPR4#DXeyeG2J#_Njqu; zLasldu6-d_G@qyjgTcCbp!ioF`#i^cxS^;FN$MQ>FrP(4pgKYz)b0(0wQJ;;u_kJl9y59>mX(zy8}rPx(8b4x8IOdtwjw3pfP_f? z_}wd}R3lu%dkl_fl0;$yX5eF+_{<5O>zloIp9y(qCiW{unkY-n{!)K!Z7ru_uzjS& zTSYA$6q@|J?E$e8TiWYozzL`AC$mBJ@cWbz^Fl}T21JmMD?TC{0F@C;o*-#O-O3YB zH^FRT3wYlp!rG! z9avm+7pA=L@+I~nlSfUSUrbDfpPBQe{>LA`g@&tnHQbye>|YV_L?mMbhiE~hLu?7X zzT{4z_}C34aoC$`WjK9Tkn;Sz;=tVjhP(1wY`w>x4i2*s85x3GEf-;Nm+B6cc{;n; z7gR!uOd-Q1lzlqK{}L9G11*fh<~bOfM}w&@fRigvBTLpzid z1zTwD-52ZY>){6>%_nAwn8}#2d#}dolIqIv3d-@BZ8*SFX|+?}`^m3X9~ptayE`s> zzS?V}IZVT$2Wz4D7;xY^Si4Z0yOLtP+Vl|kSIvxtl{LitJ-2jX?~Q1ULO?E`m+ani zS;kbuKlcr()9xs&PdmcXnYnp*cs?;;ByH9lUYUHod>1AzF0P0!yN*B7*#AsBny@S$ zQzo-_spYR=4en!Iov>~Q7mV8_0B{%_rU1L908_Dq!x3;8LQO>;21CGLgPMfo{~;^$Sbn*MO(j+knQI6GN$Y7hfs4X zTCM7p+t_Z(AKh7XETvpy>+G(hF{Z=O)g8*FV|ERi?2-PpKX$k8J`^L=@qd+zx- zJ}#QYbYTJjOBN$lAQ`c<893rCJ!LCM*k()Q5`eBc`)wr++5F5Hg&g3lHvpvr*hDUB z5#T)n;3)|pZUW%tH|rC^P{0&_JSh@M0L%YdRxFqSHUIA5VQc@D)kSu5#)|Fq>7b4Ic3sj&mtn+N>=tsEp3YA7n5O*~e6|s#xdQ zyJH>L4;|PIQv11GmzbV3yH*cddKu1el(g=9(u%5L8L`n)1&b8aBZID$$s_6Wbo>=( zugcn-G!!<=q>`kQhTpF~O1(#LDr3`py6g3GcPl(c|%t+J6OsURx zEQl8@S>D4c4~C^CG3xUCf#f*F+H`J006Fk;b6eM)VBf_ePto_SGQZmRg9gWQU$k^K zU9N64{OLEea53<))VH8C_|cojn5F$w7mamYDp$_Yvdy5a8LXyFYQf zy{!MkBsx`^TE(IEW1W?ey2i$<*=Aw;?AIqasi)I$I+-$|cOOi{n3JO+J>Q&);KJlY zaZ&N<2n_bDlu%(k*EPK##djQ{{22L*mZup z-7pq~ciV{uQ*PPyGnO#JV~sd`pcmRXwos$N0|Ljen^|D4aI*0XujW$A*Il2f+o-9D znZ3`&iG%(0xp#dIl53;6w@JZ+U15h!a4vK*+GOe&%QgI}XT2Y!Z(*+}O<11`25&Kr zP(5c>`=>VKyk=^518jacyZ%!b_pfBrHf^*wV2Edwj}Z=&)w%-b2N=WSR{ED?7i56}BS&+D&!+Yn_ubEEB!_AvFy2VIi+KKElz5kE)=#w!a+ zwMHSAstgsSo|Idx*K~I5ccHT_8c4oo-n?;TdrR6lVoVfOb{bsl~?|ikdvo+JFDcs6YeU*eNn=z rI~@}9vb4p@LN!QKc^PWHEJvBGR;ZP#l7eCN&R+ns$T;cEqh$F%f*_CP diff --git a/android-application/src/main/res/drawable-nodpi/symbol_159.png b/android-application/src/main/res/drawable-nodpi/symbol_159.png deleted file mode 100644 index 8285e69ac880802bbf15b05a77ef652738b2aafe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5498 zcmZ{IcQ72z|Nh?L^e8DJN`w=g(|Z>j5s4Ce>)-bq4mH!0=>~j9- z=s9-@r1q+MssL0cQlDCpU9LIM+6H<61l|Pz8xFw9WeU3rfG+}obxQ!`vH)Q6c+>bu z;c^3Jt*fO0F8((PT8dLIGvq!r%V}#Kiq#*{*X?(ThoieJ{$LY97EpPXpKeeCuz^p5fQm-PUW~<*mYDpX>|iKx{$k}I2q+jFh732m zZpDN4o6bx()=7c9-=^qvy}LbV*r;d{1mRZQbjqh5nm=A~Tj4IN>bEs@@9gYMK*cJ< zCQbyX@V!s-0&q&glWcmm|K2z|D}E}}|Db}6ukK2ZHl-MXst6aCv3xgmM#HcMC6O-+ z`k?J|EkO`KO-=oYxeK@N+(zc`-u3R?yB%=&q949&7T$@uFDoRjtE=k^{xe#C z^qzqkWaVKbVOTiQV{=lJ8t5zhC2c!ejAcF}q{Yy>L-@GGs+GN0XyQcqo{OF7LaP`- zR5)jf*w(tew1-^uRtGKyz|dhwcQ|C>@G16_v-?sxM=SXtQEf>s(g+)jV3u1*>} zP8SNNPXd-g)a63OKD7tIn)xnzEf_fwHV>t>w~^=n+V}U@f@<+x&f`2tu{5}@dV25Z zc~8&#XRNHOCwSL-wp0AV!fMC2!dU$I1rKn8ff?V4Vgtnyt@i%_c4VY^SHZqbOS5hn zQt*(%C?rIm0l;7fkS79#3kpsm{eZF@j|eoGf#zw4q6VTepTki9;>}I6}i!r7M@SJ^#b*mf&D@N%XM9t8kL($|g;X*^lNV?a_e__V!DI zB@_Esg=232SubsCsIjPg^22P-cs-lgxiho(tbWexd-9hr$tP5fycvtmm1o`6LztDm zM3>u5`?Z6uU8}#;BQdAZ)Ow}RRyBZ-Nc&px^h#24^1HN@QFWaWa$sL?3@-2b^@xJ8 z-|4U!em>=xP5|D>{GFOD&DvQvm-8Sh4iR2j>%VtwygYNy?HKY(NbOF{(W+~H(D8`Y zg<{D17>oSWciv3FshI<#F9noT75hZE{=*OdFZJy+Gk*o-`ZQnpH!CSLqYV!f z@`v^_K>z4W48-w z@60pw(fnE_k+l9PdZkHkQ}&sk>)eC9)fwXexdI z*o@VyGI3Xz?)u03az=?3(=K@mmiLz$Y4tdRnyVZY-Y1iTk|Zv#g{!>NuQGoAbV0j@ zW=n$KdoANA*E-*WIy`CQmEgUd7j65cp`k6xB${?lW$$VJehmt8H0Gft=J}{G;nJDa+%qskB&KUH$WacG=`uuVb6Fbdy%a$K`oH$1+ME z4;^jPihlU}HX`Eog(2?vq+(!{4AdA+v5h&=TE!W+?kty$ixoFES{hkO9vi^8P$n?0 zvkqzO@6o+%Qjk)}m&tF4QJU04ayBC*_-W#4xVXL!cOxV?uV_xr@EFu%5mBDjHv1tEPU`g|{BU8Sve}uf**zIToT8`uM+2#?Ka}XcVhn zQSZl-@d;ilrW!>Z2(g_h6nvj}J#`p4NP0fWyzI-P_EFdw&3w*|P*1B~Z7dv$N5L9|iZKbLESYm*5@;5q!$9y2MK zhGLD;kps?}-Ec~4ngK^Z$HrhPX9~2}{ zX!cUC;`8QOy}o?(?+QHmV&}a8zx*wf%ji zd*MDSQ3`yv{{fCGXnmcdmSAcVk|(C22=cv05}$arnLxXfKPxPmQLT`iXP1{OQ$u?B zG;s|Ps7|%pb100fMX8yx#am)#fb(6kz~LKi5Z7@RJnMgCf5Q%?f1$b5Fh~OeacoJmh!QyW;S^*5wP3g>oa$<2cYe@@*W7HRNnpGhv zQ})*2N}ysEHMPcgouxn~ej}CJxHMudq9_GB4K=_k-mxCKiPO>2@Wjza+^Nw{NRz@r zQ?v`Gqe+K%_fbZ*!D1+L>|=A144OFe3BLR8c^ozJq|W7u`xa``@NU9qU!Oh$E*&U{ zdM86Wh&oUZn&E`m+z+WEbGda?WfMn~>Y}i_^IA{NVl!&>7!%N7fx~J1OwSs)d581C z?7Cl5wc6CrbPx0APRzjVpQTTRY?o|~A;&DV3&m%PtGud?c3p?s@Bh3Jj3vcgUGzqU z+8OryWGs7)i=N)rIX>;DPd2OOj(=3?@~N%Hk8eCq^Kt1m!sfmz#jj``G9JzPz*qxM zYAe3fcLY5PF>!G@T3}$ak|a14i~S7Re7TFfi|!tY@<#5 z60U0PmIr>Dg=-<}B4{LYs7oeTlJO51Ds`U}E#BT1WSQ}@Gk^O~plssMy4ZC(ahocv z>!JPe{@4PVg-zXYi`~+cg~UTjCPDp12Ld#o2OeIXctKB$@URa6^c~%~O%`p|c6NQ! zhC2tB;UZ}()n>+r+64Ux|5UF za?j4Z|1MgWFh;bN;CD+Xu4eWX$&jHH0V*&-EJ7OrWGJk!lX{lc)Yng?_I<BIum&8hHuQQScCoU3yf9V(V`HsTrEvs*6qo;&L_#{&c{hvwI zqs9C46|#v#JxB$zG{}_=6-KDaH510~`42j(>>wNonWh_oE0j~$07-ixk-J*M1=5~1 zDI;g5eD>+0+j!@FcC~2ZBc0!PE}f`u2iGNUDHJ8v_g*26oN=Rwm+^;Ii1E>2KXbqg z=K~>48{i65oS9%~DVI3&O_>DQ1Vgr}N8z~rUER|@>ANp~1kIuEzS8P1Y8`U6z~G&0 zMCF%EAah5~5p_PN<%?qrDq}p?E0Jg%A3?wEYIEQw?M29w=-K{1eMuzWtS&pkB+rDm zai_vU;58&5wxkuyCqE7W*$vRq&wjBRYNEOlr9VF=n)SU_{{ zneUCS#$n-leG)2l#hE(t{=E!CFX_T)bFwPO8^q+D=NzOOV1Ry2!G+6tN%oLU7|8iG z3l22>inp?G04nd_E+Wznn&AcF>3wx5;pz3B)D;@l-)xYX1FFr_9|qaZBFzuw-r5vV z+27i5gV47$C1bN^322#wu#T7Hvf{@N^C5|X~YKqg=%Fwml$hOL{HD>5&lUhYsk{rTQGFRL#A!l1Y zCd(HJ3|@7mGpEA0vvcvZgHPh6K-Q;(AND0;cNqDASgsKqf3gS*nItyAYVQ}*GU-}7ZG4>KcDpbVn|-8|BOr&r8-yRZ#soD0ENH^TmSH%4kw;i+au)A?tQF0O-10 ze;G_mA=a*Lo#v=I2jRqMdw5~?N1eA_SI>^i&tw@JPIyd4PyeQsl$#Dad_tXH>*p|& z?&~UQhv|*4?bxra0}Mr&ZYGQfnjMs}-4wUOyk3}tnrgmeE(u7OHM~)ESH}qy_|EkA zuhtluQwtXDImH@5uNR0j)KxIFm(dne<;b$AV1GDpZ!_r6U=ekmx2ASpK+lY}Wp0=#NZ%&z_=s40{=TxpM#=o8v$D?tre4qC?6_^y2J`v+>x6{^3Stj4w0--n zM&kF+7Ai;zTsaP&7Fy5T5H_-3hQfl0uj#=Ds z50w^epljGuWJ<8e)R=afTy~Kt_~EiBp{0^y_k+~sweRe*{=8RDv51K8*4k4^q(=dr zlRkC<&yEmod6jI$jEqkn6HK{QRcWR7-V&4_3D1b?++t$d3XT87#lk`TV#)}4WpjPHp3E6SuWT66)<*554+;pu zHy#mV8K!IP3n)M^v92sFE`WB=kLGjBzd01iBa-b!@uH$+wz``_^T73=z!l0;jDzYIRlQ)n;IWUY{BxsuD(G_HCE~ z;(2)5&KJusMG6d)AI(XQr|N-U-q?~)OC%EPLEGE6F*T_&q6HlF#HzhpJ;`#|k{zfg z*FP??#;Fja^uN|}&wI}OGRlV`Tk&!}Y62{o<(`2Z4)tVZu!PeBxzDDu#|s+**&-B2 z#3oCEroq=<`~mZ|B-_Vb`2EFn#KlHAR7j6Dk`{q8n6ybZY@h#%U0?X!C;V891b z->#ew{jmM)TW6@!WI+7-g#JsG^hhj`9W{HHQ;a1jjb90q{?$RF8{)^fvUT#Ky}s4! zmxHT0N12gdZcHT`+=+O@zJzBXbUL)PjjWT~i2hH7Fem0i4XMOAWdp(4aT<4u-`RFs zklumq);C>jQF34y8wm5GFjx2U!IIzjYlpQf%@n}KHpKh-!&T4yv%iM+TnmEp_UJ$F zpu>YlDBvU3G;&f~(IE|0;rX$(?3b&warSz@43yp54+P~rsvAZBz~ue2&%JoTi`t9X zf{uXGshamgfsCKBtMR2FCZ)krU`{BMa9>fe{pjc?WNlr}KV+VqJ>>Ka)z;II(@O{I zoQa15afhz4%j41^SJT&V=IUDvb_W#h7dytA*6*6;znX(a$*QMNpS%LLJol# zQiw?Ze+aJbHjZ`y|9?WOl_K9If%$(5hVFJg{#IVLK-I?G+Li<9YGrS0U~6R);MrsQ QKSLBC?>*3{P_qpCKbONVQvd(} diff --git a/android-application/src/main/res/drawable-nodpi/symbol_16.png b/android-application/src/main/res/drawable-nodpi/symbol_16.png deleted file mode 100644 index 590a1e3d4bdc5503364854097b81ab2a43883cca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 644 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J?3C&U#w>5UjNT*&FK;#x6zpO-S_e(=KJR#un}u(Xyv-_ zV_wmxBgc0nTI$)zA6#OR$5_c+yd)t|uqiXv?d$G@(D*;gA6UNIlNA4W28-te7S9Jl z8)maUv5H9R-Ocnje@RAP(}mi`j58{dvz{{)%CZFum|WV{STrxQbb^BQ)5B$P{9;S~ z2dqBWm6N<~|Mm~JvRv6rV&A_y*ezdEnzlmpQBswJ)wB`Jv| zsaDBFsX&Us$iT=z*T7uYz&OOn$jZpT%G6lfz`)AD;Ji)iR1^)l`6-!cmAEzROSIJl xYLEok5S*V@Ql40p%HWuipOmWLnVXoN8kCxtQdxL16_hj>JYD@<);T3K0RZPR>Zbqz diff --git a/android-application/src/main/res/drawable-nodpi/symbol_160.png b/android-application/src/main/res/drawable-nodpi/symbol_160.png deleted file mode 100644 index 70f2add8d48ac0b7cded467aa4ca63ba2b2c1893..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 907 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-1?7Plzj!{*Mizi39Z; zGcf#RV8{a+$iVQAf#EyY^gMHh1_y>eK=C|=h6V;-Uxv_7kSo)C8L~n_CU5p-SQQG= zvWkIWssqC$PliyS31D4m3=ESP7`m((I$RhUd>IVaB-?gx@UEB^og&$T9JH_$0Y zB|(0{3=RVQ`wiy5XG~C7-@wSYfQjk7q9GHL0TUB5Gb02sF|#nSurLBCX6E|=jO*EK zOMto=lf2zsOjd4u33NXLdx@v7EBh06W-(FK*1p_mpmdw3i(^Q{;kVaMhaEByXm}VH zZKbrx)perRQV&;`3%~xoPg@v1$#a%uzxC#)f8xb+)fgYt|NU!a`8Tv~TI$T_r+>$7 zi*Jn3sM;CuHE7|>RHxn3IgZ=L2UM?H@ZF~Il_k?%VJ4-bs@MgL#p^j$5?+TkGQHWW zB;XLfp7YJUe`c{&vmacW&3gTw%8u__4!qQCy#AVLyMF60>j&T27yc7E&swYZCHsLB zOUhoU4=D}d%*=`fmNH@v_7lF`55Jxmv5z%gsV7g$0Z4qzvtipPa7WqBM@>PLNnW%; zU1a{l$0b}wiTedh4#ZmIEYawimu5VH<7iml;~$lF?2Q3^OhN^MU2=wzI&ssy6S$v# z7QAdw6T7xSJ7n=0o*S)IB2f&pFZ2XSCx}HYmiU;vx9)yUgR)G2(J#|mEKfByFilw? zr|LPWCTIHtoq%wYQsbK}e+}L+^|3y(IM;a1=Z(OM$9tqRSUx#DWC&rZRV-vYaR2Gw zzI{TLj6eS$JGlI%`jPb}Z&}uyE{INNw13AO*s@tr=d&R0PYLD72)e<9irB$<~p<23()`(KO zMp3J%75sc({$KphbDrm(d!KX9eSOm`%nZPETyy{cfMJHZ@JodLw=|&3TknOQy#z`R zEmJK3Xv)4qa;CcE{H}&@Qviq*0RT)Q0GwP(nBM>pDh&YZP5_`%1OOa?&)!(7T|PiA z#s<2;#eY-wwkH2lp$>tW>QOIIQ?RoMCuRBBT?W^|bhQxSQ=3n_vxQ;skD9qQ2M+hm z&4;&mscY=X8XomH4ahU{vh%K-Ad5&>xGzA&Oi!5@SD9mE}ggL=#dGhx6H)3u)!cOmO`(K~g^aq?)B?6s=x zTtLhN-!@`wjK?pID?x-43MoT3pIIK?=wRY%=ERI0E41BHy*X^M@{R53PA3BMRWb13 z%gK>WL3ZQWgl6069H6e0jR<#vc`xf#6$xGSkkP zJGtV)Sbu;Gc=n!uC`4SydIKxk=|R?IF2qZ}=Qdqm){0c6W!pB7I`t9%En_#gUtGM^ zcp-`{PV6Ei6;AvcXz#fzMI}hK6tk&${-J6~x%UYR0RML}?NB5gAnF$7yT{ze#Q}MW zO;KipGkU5X?^Ur#3L{7`yE#uX$p$}t7OGwFA0%0eMfPO>D8##7;e1&0@F`S#Qv9)wvP14QYw@L4bYZHwuM(CAWVXcurW$i!uK_NI_fH&R`{E!TjT=LjL zq)J4)3HeSzR{48_#k%i$&dt0JZ*>^`jA!g8m&_e1u}2A|h@Lpo@+vMHYj^rHyQtod zG#5L6wT!OWWm<~GLtF&B_kjx9IA9A=Tn)$ff}n{K)m*94t-IdCh&3NePEt!TO#{4z zD}{<)TQ>C&fFZSch`r@^@*fZS{(>V%z4r>!P~e1P`{4ObLiO-lv<8LU#A$jW7C#aq z!J?p3)c3GZJbA8wvyid+$n7XX<_tK*ikjjV3DYlcRNA`3sUZ-DW0NjZ za-)2V;Nr{nztBR=mF_vgt-VckYD~TRHETmAEw~N2l?DtdXB2} Dh1I8|af%9EP3 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_163.png b/android-application/src/main/res/drawable-nodpi/symbol_163.png deleted file mode 100644 index 795691bd1144d678e120af55e21fe5299193c41d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2235 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 Tygp(7{Ad6IW^Pn!;28EF36{T( diff --git a/android-application/src/main/res/drawable-nodpi/symbol_166.png b/android-application/src/main/res/drawable-nodpi/symbol_166.png deleted file mode 100644 index a2aef6acd13bc8fb7382a9fdffa8e58544fbea61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 734 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DhBC&U#fqmwNvx?NdWkCU@XLgJdHW~Y>tJR93gSy>-`{um*lV`^&u|Nq~?H{S|q zjX+6|Uob<#{`m?G_Z&pIwomos& zwY4ud8Ypez>Eaj?aro`@*L+O|JZ^=;A|W~kdl=&G{nr#NNEY(lw%$$H`TzSRHCx&R zS%UYjojIZSTIH_r6AUf74U1TX9aN_KFdXFs(hCft9j1xfGI4HZUQy(pF~injzmzdt@ zw_565U#FPmur>S4OW#L^eXwZt zlyuMBxz^;lNW7-+5AC(jG;?3rOp6O%!8kuis?7g2ldI<%hV# z@6(5WrE^W1aP>e){95U2JB%*>(3+|W3{uq+*NBpo#FA92RC{^8f$;-!19-`{l#$7mq%ypJ8%C zObKX>KuM5aFoVGP_W=zF2L1OP<}2(kSYPkKbR8(inB?v5A~T1@ksZikFY)wsWq-oX zEGDYj+Ls&6z`*p_)5S3);_%z)*_#&`@U&g*(lB@CX02lU_kaDJEeoDIM2mdCeQuv| z*_I3GlT19bMgC5|`jV&n#8Yht9{sudnPTb~3VxkxO)YGd@8=KqxcAFJr@^RUcDMTX z{xc44cYib$G=EWcU^@_PqI{3bL*{~1jj7!M!?j9zN;fwpH`Jsur3K&p%CtkE>_J1k zgomO^wQr$u>;5HAIBu|U?+D_0VH9vc-!#OF^Y5%fj=mH9+r zTlZG(Yt37^jplqWXIN-zQYFW7+18_N|BQ%bQZl#LG?vauJ|~i=))B9lv2ey3*AuL7 znY^}Sv0k|FO5s4VW0Fzhp%$@O3lk?@Y?H2@otm}j^JeZHy&IRy@SS87k!Xn*bMWVn zYM9&k_ejI(gKkCw%y-TeaeG``^O1ALnQ3nrKEy6R<7?}C-ey8Vkb_0#0@fLt&zN1F zCp(rfM)>EHB{s#q-}NBu^X8Rj7&MQ6XV|{>sXjx-SKb3xF3Y$?JQC+gV)!t_JL=ZC zWUZN&Pi@MVT+j@Q5_gMOW%#CvQAExmi}6vlLkia>roU_snF0-8j~FohHsla}9OR!S zKW*B#JFIH8oe{qnmYH^^yDtji*4)$m-t}2*ez50duBwB3U)Jm8eN;WWc!FNzGM6r< z^OwFaFY$}{j+&$IqZf;q`-9-~79ZH+O{FYzwvXtNAk6IdXOs+XSTXVd5@$qc-Ipv(J z9|WyEUcbxa*>qTaZp-a+ReRKWy8M{8%{%@~@SyeW6(2Px$U1P^?rXfhx$yQ5;R#t2 z6x@$~Gcs$F>QAe_eUl+*N!gDjhqvu!-ti#2dBWON3B~8_XLhIb{yA8#_iv9|!Xb~9 zjn)gbE?6&4`@ddrS+eb_F6NtgVsg^8%Xj^Yy{K2)x?}E(T`3<;Z-xI-DCny_IVrt- zNBZ&TtM+T{9Uo0RAE{8?4a@?)FK#IZ0z{o(?z+BhBIK;@v%E-XV z)L7fVz{-L1;Fyx1l&avFo0y&& Yl$w}QS$HxPR6sCzy85}Sb4q9e0D3d+cK`qY diff --git a/android-application/src/main/res/drawable-nodpi/symbol_168.png b/android-application/src/main/res/drawable-nodpi/symbol_168.png deleted file mode 100644 index e6c76b60ac914df4e63944680dedc8570c8c7a29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 349 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}1iT?69~BO@y# z11nQwZ36=<1B3H6ty57nt_>H2Gd_m1!r2hL*Mj+i9jy>X{Re^l`}eoDv_crwmDN+HOl_!ZSTKJ9 zP$Vri4aiu#W^II{1;nlbSA);tEa!s+rg*7zcxZgOdujEmRi8e6{P*wgzfZvP$g!lIi8t(63uh6jn{``Q1_XZ9L>lF;n_wR2I zc%M+PJ*FcTsEskn+ucR>HFM!aAcwug)7O>#2|KfxsA_9pZZrb}(*;i#$B>A_Z>MFJ zUvdy>3(OQynJv5~d+F@8Rl%#n)@+M1eWy5i%F-$S|GUqrHf~fA_IP7i_d(_!zk|`v z^LI);)^5Ax^?&8M*!_j2kAKa&R>5b!KJ8A9Y0MSIJHM(QZ(ApslKbjbxAXQ*k>1Dk zPxoyvlin7(S>Vc=wEVkvC6dV>uQ~PQW`7J_E!7}j!Xgfh(1 zzBG06<&}{?_J*l8dp?qBb2>iPN-x1pT9o12qKxQ@{lR<&oC&MBzh)V}C}eRJJ#J#P zl;NiJ+a}fYi%pN7H>FH0uHtlvmTAnG@JYgIQQD%iS+d&C^`Bjj;LF&lbJzaspRAh> zTX`8PYD>N>Q~wf{c}I6Rso;(X^&1``On^|fC&lMKll31y-gn@0c_!Jk0_u8dSw*Cou zhfTT|j6EG>j+wJ6d|G$Df2mT#!@B>CzkYhZaAAzt(YlXk!c?XMdH;CJwV0pfX1_K* zz_=!yRU-4g>5_*lOTORxyQ<-fLBiCTGi|4MF@|wnFiUTpb@%ekqSWOZ=P_{oGxp$@ zb6WKE(DsEXB|+*>7x(Uz`>k1OUUch7V&{E{XZoDcx8;7!yR$|9gnZ-tABOR-oi{Wu zPDy){z5Bv*#rMIl-4*SZx3eEEaA~Wxd&In}^jzUvPEq5#k+T_Hk|o?z#2SyEY)_Qe zQ~Tju^GnfEs4DKo;cb&9^ESK?(&ID`i*9-H`$DrO<03|uISk4T6Z!Ws-MHOuIKQCE z>cR7i9e;Y=E-Sj0o?QNL%Av>N;tSbhx9a#ae^56{J(!{sY&PRW$*;*4tPgsR-uf5j zn7F;HOncSuob{lD=upqV?)p?cw%=J1nA}xMTq8?+%k%5(|v9^JMm4U%|o7Sl)8glbfGSez?YuJ})s|nN~39=zLKdq!Zu_%?nF(p4K gRlzeiF+DXXH8G{K@MJ2mOk-g1boFyt=akR{0OuM^CjbBd diff --git a/android-application/src/main/res/drawable-nodpi/symbol_17.png b/android-application/src/main/res/drawable-nodpi/symbol_17.png deleted file mode 100644 index c81bb7eb4ecb55345cafabe859f5a8f7b04fe272..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 795 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$D_NC&U#cRG98UFNPmewCGvgo+AKC)(A@=@!zm+o+bW|&S4{lq`{?Faj zJHWGS(Xs^X{bvsN1bD{B`vo>z40H|5bq$O|jEt;|46ICzwG9lc3=GcOv`$6Qkei>9nO2Eg!@fjY yO`rxzkPX54X(i=}MX3yqDfvmM3ZA)%>8U}fi7AzZCsRQwmci52&t;ucLK6T?S}|7u diff --git a/android-application/src/main/res/drawable-nodpi/symbol_170.png b/android-application/src/main/res/drawable-nodpi/symbol_170.png deleted file mode 100644 index 9423cd537a2d02abe275af98c781833606449e9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2561 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_171.png b/android-application/src/main/res/drawable-nodpi/symbol_171.png deleted file mode 100644 index 95d341d62f7cde37a713015058fe895d3541a9ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 680 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*WnC&U#<;{gr~4FACh zs7925;T=rrDzG3>b{k9lGLn_5)@A|8H?f zJ_1xNQ4-`A%+UY-e!%<$1&8$x2Iu$hf8S8h55x%q6DK5!1Jy7ldAqx)9%ekr59F|y zc>21sKVfGU6IE^P%Z&yKz4CN%42d}WcIr*OW(5J)wOuz@v%}pluDbI7|1mSY&;udH zYQ4S|>(AIaGKHTuS~Ito_rZ=IHjPsJvzK3Zq|92UenU_6hBs>hi(3Lqz21$ZoX>5} zZfN@3XuhOB^0VAz&b~d$yi-iwzRXftFyZq&36m?UzHRADQqU-2+#xKj@l#+Sw@l=L zecY!e>Yg|*peGto`csqB?URGL-$tn?pC{T}e%ENE(8lyvSY{QMP8FBxxxEjHctz9x ze$MxtyN+f5W4UI2rS8q&MFn>J;rexeqvrsJl+x~O`6Ul77qMt(@RqfRMc5_k#7r>% z(DSr1<%~X^wgl##FWay Slc}KO!{F)a=d#Wzp$Pyg_0}5z diff --git a/android-application/src/main/res/drawable-nodpi/symbol_172.png b/android-application/src/main/res/drawable-nodpi/symbol_172.png deleted file mode 100644 index a6f4e63ccc598c4c86d3ab988d65053a18976e9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 773 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjf$@c>i(^Q}y|>fP7Tz`xXth_>V_2u~Lc!+Q3BIIqhw=w} zF5wG=j_`#rU1_}8IEAZ)FOIK8((Ca40G^j8A7oY>5I*sD%Wek6h{*W&JFb6V{*b-! zy?~R&B-6v(g$H$H@0lIq{%G|#FkX!*=JoSS48~eaYxq7~c(rWF-tyYrlF^^;{Y>xL zfB01Xw3~b7ugkugJdHtO-QgQ4_ZT=X{kr4OY`E0U`oB+fW? z#j-)Ahvz}_bhBr7tBg|~D6|+^zWwrWAJ@XUF(>+7e>j$sAn?HRgjrXjisV9_im(?e z56@1Otok?SK#oNJ*JBw12bkQw4g|MsWaY96D0=g8+3LWi;2Vs=k%}b~wun2Kt?9`s z&-tA8lJTX0lk(!)51*@U&F^zG;lJcF$oV6`?{wgo4E`P)98gco5m@Py4Ic|nE zbt1K0HcxvO9z7>l=F;HWBM_(n05bVE%j!0xW=(R-p!C8<`)MX5lF!N|bKK-a)r*T6W$$jHjbz{=EE z+rYrez~H=1>r@mCx%nxXX_dG&>`S!O1Zt23*$|wcR#Ki=l*-_klAn~S;F+74o*I;z Wm{M7IG8L3I89ZJ6T-G@yGywp}AT3e= diff --git a/android-application/src/main/res/drawable-nodpi/symbol_173.png b/android-application/src/main/res/drawable-nodpi/symbol_173.png deleted file mode 100644 index 0f59802332f4c6836a849aed54fd39ad2c1c1fd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 652 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J(0C&U#<|0fmw|6h48 zs0*l5pd`pIn4#YxVgGx9hWiTh4GIF*pFdF6C%XxtU*p0 zPnWjlF}0XqW#izKZCG(3SzlkXx}& zJ}tY_(3HUNN95`cSs58vnHp;w7+4t?oVRJ6ilQMmKP5A*61RqZ ziMEr>mdKI;Vst0EoNe AC;$Ke diff --git a/android-application/src/main/res/drawable-nodpi/symbol_174.png b/android-application/src/main/res/drawable-nodpi/symbol_174.png deleted file mode 100644 index 35bf4427e26d23509fc3dcaf1f925c611aebd041..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2105 zcmb7FdpMM78-JZoQF6sNjxh{!n0JP8m@y9JkS&s|Cede{64|g6Z3kp_SGA-f?NqISY+w$st;lbqZ6)DP`|{XTR^C?~m_~y{`Lx?)Q0~-+lhQ*PG(u?jkR%CW|15 zyz4GUPfXhjA89dcy;Yq!hbi$R4sH$zQjsS2l`VnowF7r~x*^CZ5`rWoBgi^-lrW7T zu_%Jf`XdNE3qe#OZ`SU!K@ibik3C*a7+^;J9|$bl31!I+7HvWB_q)Ir=9uu_21e*G zM2BHIj4@z_2_J3$i^OiRE1o4Z(xBEHs?DIr9G=mj-4gn(Vaf)knefUAo|;1m1#-yn zt0`PJfh<$VCPNVgIxU5Vw`NZtMP48xJm8;EIQR+HjZ%ktFzJD|9|!4L3~TtRaNxf~Pj@&;%?c4T3e7Z_w1Gkjq!__>B=91D zi7IHTfT}WRD1(72xZxpK7tR^NEi!aiLLmwfdSI*ycok6D2I|V7j{{3}2>K7k6rR#x zo(Wx+aGwHEBw*>lPA#CS0TBl#YQWThP(3)m9bQ|*BQwY}fj}a-YXeygC~830fL(Zq zCcz~m;eZ-wkVl4}jlkpYVjZ>MpbjJ$LY0}&eBM?#K5S}OOMP{KMF1ZiU=tyN1XoRj z(XrlQgu&$Brf|j(V)fya0c4oK0#n#eY`%}pARmQPW4LS#O*A2$daa?^0xGCbN`-nF zj536^U`)f-->jg=O2`>(#F#ne1nV)Swk+!A=BDI-E9Y)Oer|TSCjDyu{fb9bRh1?8Zr?7dtgUZuX>P15VUx0p>)Uue zuU@_EXyTUUqCY=s==^PPw?-ajk9Q`b50ZfSkv>&oQt%f^zrfu%2heqH4ccQ;mI$k$`D zi=UU~hq?-@TSop6EG|sH?ue^+_G040?AXi4_neBGc%x%uBLi(uuFIlLJ-x458T1E_ zpSC|Q4=60J;a2ADRSGC7j?hHi_wJ=o`RRD9bdiAFE{-2*HGD5@BNgN7<|H*CC8oSh zkCPg42tmYlx;i>|v6=(@aS}uXrBbQsMHx3Z8S_l>@`q88SBh_OJ}|fY9|_iVVyymP zobU^am=*W?d&HO5GCg%BO}$)6K`x|!HBN*~*a&?&6%rWevW=~G*iHp+E`u&EZV4A{ z+L){RY9MlP!pt_HDeWTOFI90|_U5aOMfThIe_xo-u9hwBD4{=(ew{ ze6EbtR-OtgFiA=ItTaKyfxuRD5J^VNEVc9_b6%ueNZGyX8`l@@ogIOLNv#>YX_32k z3hzG1EiNd{Datq5bU@OC7#Ar;;EBl6Yfr69{^;CBDhLaqPS#u_AW~t{ES68v!QsI- zLkugr^^=-fZgZc*LrJ+GMUE9_3wjop7FRwk3pPt{lC@Bfkv}h?XHtbog-Jh-k*ROO=d5&n9Kd@Q84J==9v|!c5ovhui4BX89-k zqtwu&(ZknLlZtu^y0fhBN3PuD3WB6@36qtd<&>StK6ODy{RS%kFuLMhO7%!-SUBLD zXi$Bs%jc)q4|0nZ$3`A;qhEOUx(-W=>li26KdemRt!Of;b@|0_p6Z`1<3GE!A*Hb6 z^{02#1o^7L>~o=A<3xuImo!bgD5{|E=z!UgoUOh!7fv4T^NltQ@NAFg%c)e0`&B+Y zR_nJe>!p!7g@)r;&YW#72i}(Y)u*$+7xep_zdY=D(!bN6vo$jyU9-f7`zCrddwoO7 z^b6iJZV6XhD;~ADn zzp5GDs1Sa6tn|qk4ZpHIQ}K9J(%kM78Z^1OgXiChI(DVKkPL})OD!>M+FYhFgo_km z`5@lsa55Z~@8}FWcd;$8Dm`iwSpkzf!%mDxgcB?y2f1sw#7qihv67Gy;3jIdr$JVF z+NC(JLiB{rn+umlYL*{|{jqRdHdGqNtiSujA*cYZ3L(uVnU~Sh3 c_K{%EV0KV^R7WuOKSvN(CwIrv9sWsw0aDZyApigX diff --git a/android-application/src/main/res/drawable-nodpi/symbol_175.png b/android-application/src/main/res/drawable-nodpi/symbol_175.png deleted file mode 100644 index 8ed5cc68f5e3508d104487a1f2e2fadb1ad79f35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3935 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_176.png b/android-application/src/main/res/drawable-nodpi/symbol_176.png deleted file mode 100644 index 057632b2359926c30da047a96021589865df9265..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 703 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*otC&U#<;|C554F4Gz zj(`<~qAJ}CmIBJY1vB~>7(~GefR+Ju2{16s2aBI)U`SwKxX-{4z`(E`=pF`!_Y4gE zK&k)#->pmq8p0r5666=mz$oCLV6gvvLBslng!A+FpTD2bKmYvv`vU#@pD#&X0#wGB z`O&oz_3*)cO*Th4!eA8^ZTTs*0B1D6-YZ#drb)KC&l`$z z7-l}|Kd@1u;ONS$`sbw>m>6%dY%-hhn!%mHhII)a1C!eOa|vAy65=bwvjraIdITKQ z%V&J`RBD>EWIO*%)4!huRNs9$9(U*0bnQoxapCDNHz|G--(I+S(<7^Y-K=B4P(l6oh!7BPgPVJjabOTzb$ZKv;+RRns$ig@#PNlmMRL*VP>l-MI31w!f#(FG?f~gx z;I0k`*ay62I(T+@AVAxrUK*(&1!F)RDI?n-lnj&>lyW>+0!lTWE*nRpK&^yHjcg5y zw8#oYh8&i7r0ZagMcN{)TL9xbFwaJg4DoKz5^A6cs0Q``d2>*xMc!-XFi_#hi@+Ab z9}0>v#~@8(XWpv8=1^oQkfB350i%#EM@Ar0eeEK0{1NL4B9OecPK!N+ZMoeR$w5Vf z(t%QA=VF*ckSGO3*;Pn^MA#owDMfLJU5;6cG%YGs<0;Xr1{G#!AkvIV6bC@7h1Lf? zKy0i%PD}(PB2r3$GN62X6G8t8UZ?-GWwh~nvADLWX=rS0?7@R)B_*9|^~r&OhXTO? ztF?!su8KrQbh>jgnXRMap3T;8GBwY=l=q5ETW{8cM}S7BGns6T1CQs#cXoCb2wYrT z_)d;IE{DxzFlaOyoxx&rxLijkKA#j21+bEbwE}^HL1ma#Khet<7x3>i{+W!eM2E6;h2>w1!suE@Nl12u*0KYhk#Hi&ZETP7Ye=XIYz_ z9e?x1&``m#V)ORMfhgA107`?30o_>GS zGVkh%jEV}6w_OjdV*gt2b73Ww)es%HImd7-*t_BE{-rfjPSj1Q(Ug?6$#1q@zuuLZ zz3Jr&-zPU1I<*Mxfn(lP^_#XSMjnM7%3&e@c-%&R1TenuNzM0i<`&8i^smjN_aAd? z!{^`p+0TC_QsYv|=zAXsZOkKUuh#95T3ttAt)k|5S6vu2$~^SG#@_DXgdMj$r;6t2 zRomyUT5sCrbiBrPxz`xhJ-O0}a+2x$B%Uv}LbbQ^(K5H<{=ONd#?{JKvEq;l?Gw%~KMv4LDb@Wv_vUwLf@BxE zq#Ql_lAQPFr}6h+^RGMCTHBtY9*S+Ys0RGGgHr}y<-F{A&T7B4ChPo}#~I|~n`Tx- zn-lbAL%`}Z196auCE{6P|5;*bq(l-R5eLkd`iR8=VsS@c!Ds(!Fs3FXCvN!vh70toTpK1|x-mW3{?63hRf+v; zpZUx#T9^B0{qy(|cI)JXM=!*}K>?^*;u=wsl30>zm0Xkxq!^40j0|)Q%ykWnLyU~9 zj0~(yjkOI7tPBj!+q8m$6`>(FKP5A*61RqZiMEmdKI;Vst0PVrphyVZp diff --git a/android-application/src/main/res/drawable-nodpi/symbol_179.png b/android-application/src/main/res/drawable-nodpi/symbol_179.png deleted file mode 100644 index 4c9e79886af2768c47b8400128c7911dceb97025..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3642 zcmZ`+cR1VM_kUCCV~ZK3R8cJ@($q-J)=Ep1QhUUREkx`c)RvZyEtIyjv{pX^LCk8Z zMoVjy+O;~2R#4-c{`vdk_uO%wd+u|d^W1Y@_l(p#NJB1mQFZ_TxDZBq=5(s_cd@b1 z_iC@eFLc7>p=+WG01X6=BNQ|JEa_@wZUO)ivH%d52mpt4R@@o@1VaE|!x;eJ1ppu% zP|{|mLBC*exoxNioc}S*_(y4n_lS2=;)BF{aXN486Egu+y}sf((_+Myad8_0?OTGgHz!G&YCgf4FAZDg z?A>&yrI!qjKX?ZVglFnk@{`4{3%yopQ{P<>S(R?t6nqh#jAKmQYyLDUez7aG>?mgUMMAmi$tp!OLMdwPOc7Brw6~3{ za+k91FO8^(S<;-8S%+73EJM{78`!p~Z<zCt8CCYF%l*6k3e4QoTp58Hz{%x*qE+Cau~M&M0BX zG>)AFr{kcsGf#mR&#Dh+sL1^Ex6Zs*>dG&(xB9YJnw^ZO<&)WBA7yYA6MZM!bGP3w zd_6s)mBC7WMEHy>v2u%-IV5TZ1?m)30fzCb@xqj2tK=0-^eO^hGhy!7l>KpYgH1vH zV1~NACjEXp(45LtT|JL$eJBR1M9t_a(3(aDtt@sj2Tp8RO8qfD-vK1V@ZEJ*HvD9L zOz*76=|Wj-;=rapufB!;c|O7dmMmBIqGerU3}S|5ue6cOA7Xsu6^=7;g+hmMa4HV2 ztCG_L!}*4=GLQ9nH(f}P0>mjAd21cKJ0r=bQ6#`F^jkLR=b@B-V@9={UUKs2Zus&d z@N{KR+fL1_YaI&}IM;qzI=eT12<pECly!*(>ub%?%~GtRN41u zLI4X(S1D1$>RBdt0F1=(8LbRPP+=-SFSGVhjHzAXI&H)&wl=Bev1#sT)}ELg?i)Y#E!|60 zyb_f-97;LGISy(c4miyvSG9mOcNF z6@5=nAW&_#Wk$>XM}_Is_;1rb2rjdF<67!k-&)jBSuBWYzj&Y%B*dh=pCEC{KG$f@ zdD8>C%zh)LsPZ+JQOMaguWU0Mv>NGj>i*$5?0Fwd(pe-VFL!91)7DYf3~HRg{YVbn zuHV0Z^t9kU9Y}5HAX&a!L0Tt57Jx4A%E#cdMWk;nWz>iA8A*R^EG=(9HT$WdWSiEA z?^Un!^Q_Emxv9@DDLQQ!3cM_P(M)EW`=)lK4n)X=s?3;{-|0e!0?yrduOigg8wsKk zO?@TqEUJMmYbPytP9CeCn#KL_mT|U`ya@C4BJ|>3n3m-!S^S=TwqU-4n|^A(6oEg^ z7kLa*f1ft6IbbKCLv_D{_2P7ROrdFnP)nb&*TN?!|0C0I6V%dHtkVOwu%oW>4js8- z1`CWaM@(ehooLVCG#yi zp?W^z_5DAHDwnYID6!*(-4X4W`B4V6e_@bQ`vF`#Qo5Acd-}62zx$v(>q+PDBuO1a zAm65sJfAPfOOU~633$#EX93O1CdytV-WZf${+F||eCZ1N9rH%~Iu8F1 zmu;_tIDN`dK3_fUQ7gOD>T+I6k^u*>{`5O(9FdUYaXdyrOBa{P!U4hua&_E`0iTsI z?J?HnZ82k2=fJOmb-gbeK!s5AACiALz|%i^_kO?3e!ZmBwNC7maDk&M`h@Y_mwp-p z8@`2>T2-pa=A0v@P-CA;Qj3!tE>LFRU}iGz$&Yw%!A$=p`9t>d5haSM6`uVL%Qx$7 zFDW{7JD(b=NnflkTIp$}-OQCw5a(FXP`CqXPrFe*x;uoC(D=0dff8u7G%POIeT@wt z_k43wLG~Vu(LWwrCT;^&-o2D&&)AW#2+`0m(opH{+lMTRU=kmU<>?j8@2S1mE1NbGEVJO&;sT!4X<@4~Ec2vMznD{MHJL+0uNe8Ob&H8aK49 zYkAT<`4QtcjC#9pm^AL|?2^x?xiO9D*iRc^yOQta zJ!qjoT9FJ9X&-4782C@8RH3Kazs4b=`c!3Qtq(gjWv5SE&#Nopn3xz&)_h{8!@pX1 zyzv(lH8AD}2v!EXdOP8{3*CdiN_bGD+iOMfkVv>^5k7mcLJnLJ*YBcBz5H*U<$rn= zOX3*H_N}n^14TzGYhJyB1;agw7d8&G6frrDTiH2oQux88ipt9SLuWSvCz)N|i?o*X z^mm>&A5(X3W>piCEwf5NW|*6swcOdyP|Y?k(Ct+O zdZ%O~ifD~v)a9ikT@1-{zxE;0q<$O5HreM9Ss}+IR3?qA3+`CbuLtSBH7Q5>my8heJ;woZ`Ks z{6e=Eg!|*;B-ZG0IXYNbZI~o~L>}#^ZuZ|YwptBZA2;sM9-SCub*PdPV8?YFz$J*$ zJcJ3;p`y(3asP@J8YzP-{fg?#?-$BzetJ17;7QV~_Wk7-{J5&CJKM`qcJ=7*qQJM1 zzt6c#tV4;gsC<6+QaRrwXUGj6tQpCZ)eO)c;DPg0?c0(1@|9uu}L%;Imb1@my z!Nr%j6)xtcz4943Lrf18?{sByt{lppnZvf|Dk}N|bgQL!i89@KTaaPg-Y#PBv)~G( zm_G}6;TWp=Tn}6!iT|g<^MV$bgB>pdGr4dSdFgMxLSQV8?_TQ*@Z20Ga;@Zk#8FO# zh;t^t-x9rN(4AY7OQrlY8rZ^w)8%G1!fC)UPZ)=i}Ez z>{MD~!m4%@4+2}UVglO!M~eTkLf&p@B0vWy#rM@zFaP5+ku`Wr3ud42pD!m;ObtBX z1{V@Wu2ddhUl5oiRr>q%Ch$aSik!3%aM&ViTy~j6^ul?E30u+P5GrMY@jp_N>|%q_ zuA5uQLwSj@-S?5pjq6zhJYpNas4?I$wDR}4W^&i>fYy%grcG5?hCO(>&xe8-e^J}- z{Yo4|FQL?CgP{!t&6r3gKx6-7GGV3BrtQn2-!uQ-`$EZM;q4tSuSJo=XQA}Uc58fW zM7VVSbF2oI+&Y8g%bIBl|J?m~$n|dn0?MmTlsQ_Mk7YQsKr*b8Uf`$qO)@xrYn&Sj z=MHzpy3+{&g+L)!AgWg&S1q7WI1~cEc2yn%fkPl88cDhTN5Bu`=7kRb{{=cxnwRJT u;J+H~V$iry6xJQkb;G#0OCtPG9`5GuD7WxHs{7xD4nXK5^=fZ8_?)l+aO!_@$cMEsq&3mf)`k#uyE%(?*qW`a+vU3xX{mlHs$|>nR`;L`?N6J2) zFA{a=_{4lCwP9zS_tK*O3V$DXGlc&ZJu8u1xv*CK>*VD>m#oQJ*S7W5?F%!S_WXMp zIfG%9{c6`zU9k&g+zxk>8FMxna&39e(#2xqemT49$<8wq8%~CB-Au7?u$*}$U8P}D zV3O?yMUE=phBEyHvRecrm_DtF%w+av_`U5S13P2;|ATjeGZ=J@znwkQX!I#D;~VpW zi@uW?1E$EIo#rUP6YZdC#($ep;>elLDk2&OqAia9czEUEB#+9E?oQE}(I-P#-@U53 zR{pzhOH$>scQcOFJPc1iXv(ONUALWyS=eE>?32G0X69F;i#MNCeDUsBZtQf1H+75( zYdr<8$qN+ew6*g%=w{Amb&b8Or_r$ZM`3lGmr2(f@vYn!wRXw={Hw`z{n$I}l-TcA zMBG1goZL34!1;Q|oL}XC8Cj*~&%F`5C7yVzo?tgXt ze0A*v38{W%_4n3}_swk#czA)15ny3CZ)~B!!O6kFv0hu>(9p1|s;a4}$Fdh=gq>MTRJFA)HyS8?z|+MsB;xSf zshQ;m9Yop$19!h_;|gDqEATtW)jHI5_3Qut4d-@PD4rDkd*j*9X~yqs&)qqB=g7ki z8#n$ewuqHc);#>O;Pam6PZ|zrFOkShSW?2#G(oU7W3N5;vL|_;SQ{2e9AIgjv~z(E z$I6hI2m3iH7{w>dVkynP5Ocuv4C^Ev1z%1t86}UI+zlFSPFAO9?{B&0$e0;EG1)`u zYrt&@tqYv2^~x{uSX9_;r=PTa6D?%2wB-H|vmeGY7A)fOkPeD_{;}y`m_wc;hcu^6 z7;6fL9i{(BCg1DzG`m%V-=fxj)IM44&aN9qL!z;`2rRIKn{y?w& z;oRGH8nYkTIcwL2^|6;s!wr2FEPKS}z42?5P1m)@D>IY|-&%BRozmNTcK>7c=~qrJ zo$|h^6Bxa!C9V-ADTyViR>?)FK#IZ0z{o(?z+BhBIK;@v%E-XV)L7fVz{-L1;Fyx1l&avFo0y&&l$w}QS$HxPlsy?d MUHx3vIVCg!0MGJ=3IG5A diff --git a/android-application/src/main/res/drawable-nodpi/symbol_181.png b/android-application/src/main/res/drawable-nodpi/symbol_181.png deleted file mode 100644 index 4d413cade2a86dc57ea66d1d96afac6154a26aee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1023 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP~uO3Plzj!W?=YFG;&~I zumo$tLhx$;7j^qD;rCx5$Y>RedqjIb>hv9 zd(WOcd2;sV^T~TZ%sc$fY~o+ls{idfJ{`RLGG+O90h9k6Qvbtd{)k-oqk7Y4*@XY< zP5&LI{i)jiKWO3qQ;+@w!S$E_<5&DQpY(s~QK0O5g^c~GRriH#3xF;YFiBt)1UkTh zS35wd@VtbCL}X;7s9Qr(QBhM<6RThYFjPD}J^3T&pIwomos&wY4ud8YsQZ z)5S3);_%za+2KtN0&Rkt-WPq&cJa6gPW}`$D>GF*fALJIXaE1}ukCo08~!Wo`G*?D zb9+9^l%3N#zH`Tp9e*5cY~G7zy!rTNU;o|r))v$CgiKUk28Hp>WZKVT?XheInu)*`jf<@c^{PhI&*L3qINqbRtcun6SP@Z zPUbnG<5(D{QJvXTyGtRP`%CpJg`eK59N1Ur{8L-mqQP`>qQm*sNg3N8B*spdzdw#~ zMOVR&)G1C=IgDH+uYa>FX|XWu;Y_kPpkU)Kn}27y#}t`< z89k}T5;{Q>&))L9GADmdvXHs+#mTu_Z@j#DGqdM*1iT?69~BO@y#11nQwZ36=<1B3H6ty57nDxCXb9L}F#mqS`}Gb6=Wo>SIt7$tO!9Vjk$jW4wFAguFY)wsWq-oX zEGDYj+Ls#*l>YDO;usQf_-)ATO-%+oAs?C+Ni0}8W%j@S;q#WQbXYZQX7Nl*{x{9e zlkfV@+LmXg{ZDh7y=liZj*ogX?#WN%=}T-*x%glTi#o${*1wWXszMCw6YH5WHyjaT zND4bY|0U}mAs+V0`!-d@?XPxjc(eH4vhSN6Sj^o{1kFEao^aVZ?*v-`bN|N5$@@N3 z-Q<4w*idDPouTcV_%9RKzCJdbAh$^TZ@Xq+mAUeAdFfMXwl0pgOZy*Bn)lpvE=T^l zpgA8(YCircJ5ccT%WY}z^xu^`O}>5Be}3SH#>3NhFLFzqnSX+DU+>ifqZ8atoQpJ$ ztywc=Rcmxd)Jm^e{ExycjRj^cSa9Lj%KRwl)o&MVyPwOfygkZj!rh+8UGL-iVr&bV zy(CPGo4sD^xu<4}>Hd1cRo|IiA!}YxJ(tJot``@NK}PT5iE9Hb-^ISR$yxCA?mL#P zYF%k7s)}0gHt%np*~mF{oiMA{_iwjLl;$1H3H~RrlhJhPnntPS`m}(@Umvg?KC|F6 z?-JYl2Lx1k=e1Rq2g*D%aS^m@oyQjb$iUk?u*WhlmtQR<;70VE?G>_TSPw+k9ADQF zooPL7JDV75SIK&lw=9QOUC%I!OWl~z(BAh#i7=Y+D zOb*C!fUzO80$4#Gm;|c44;B>wD+5}V02Tp?zh_{W4|Em-!+r*a0-$3U7|t^=1ORpY z|G)j;@)V#h$&w(yUFdh=gq>MTRJFA)HySAP(9^{+B;xSfDL46=3j9e%FMXZ7F|gFE{?JNNgF>?IEDVj>-r zOZ*g0w+gscy0Yz=Izi;M=Vv?SoFlV!YmPA;T`n`Bbl-{{hxmRhGz$F6q!h}1%s@bc zxibiBm658KtzG(QnkXuIcK>rDg z<)2UQe_)sTXzHiG?|Zf4*&oF diff --git a/android-application/src/main/res/drawable-nodpi/symbol_184.png b/android-application/src/main/res/drawable-nodpi/symbol_184.png deleted file mode 100644 index e994ccf38217296e0c3c6d4ba1beed34ba9797c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2570 zcmV+l3ib7gP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_185.png b/android-application/src/main/res/drawable-nodpi/symbol_185.png deleted file mode 100644 index 8293726c63e9ba92e962ed780708e81acd90f491..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 603 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{Jm_C&U#<|HpygQV_;J z28IvFD*yjKzU}%upqx-ikY6x^fP=yL_X+dwGX@ke_3syK*dNJpV=7RVG0EHAMVM!I z%rqc}y~NYkmHi1jvzVxAYhP|OQ0S(oi(^Q{;kTD>i!~_-v?hu=ew?uN{{O^a>lp`* zFqp5s`sVll=+$hiy~JYgUUA)jrmfRX zy%y`>HhJ*fv5_T&zkr1+Kq`Tg#X#V%mIPnIhg3Db9)@TRM%e@6%QB13i@)`6VsAO; z&wXtd!+Q2-*X18Dczv!~z|HjMpW==N&llwf8GXF=ai=Hvy$OHFVsP&L+f6bDW?W>x z{#bEkoxM+K^0Kqv7Jq%P|A>gfk14^7@3Tc57#Ke>3VtQ&&YGO)d;mK4`j5Bz;`njxg HN@xNA-}29M diff --git a/android-application/src/main/res/drawable-nodpi/symbol_186.png b/android-application/src/main/res/drawable-nodpi/symbol_186.png deleted file mode 100644 index 778d66b9413ddbbade20570f91b03487f5362ea0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2667 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_187.png b/android-application/src/main/res/drawable-nodpi/symbol_187.png deleted file mode 100644 index ed32699894860b3c883eb76c9827f1e9454533f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}RO{*D7?N@C?X-=&2NZZ%Xg#Z_YT)C>>2hJ(aOg$E_#Ko>z40H|5bq$O|jEt;|46ICzwG9lc3=GcOv`$6Qkei>9 znO2Eg!@fjYO`rxzkPX54X(i=}MX3yqDfvmM3ZA)%>8U}fi7AzZCsRQI#^CAd=d#Wz Gp$P!flYOB8 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_188.png b/android-application/src/main/res/drawable-nodpi/symbol_188.png deleted file mode 100644 index b4399b8009fb723a2bb29318ab0bda58d26f57af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 703 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*EhC&U#<69oSm7|IzK zR2Ue53~ey^7N(~VXeC$#C;((QFfa%(F!VDp%x7SD4;H@+~`aaXUB{@N)!oO40V&Q4Ka=$kp zG~dK7aBtwbcb_5tE<=#?gpz%EUkZOS3FtOtGOeiR3lU3*YMgP7KiB+$nZk=0^WRHv z_rI(+Sgzj3yP)9Lq~HeE&P|&tzNvdxFZnd3cEZ)g_rKTpcHa)4b8Oz<)5X`?Praz$ z6Tl?Ukk2@2okIxoDe)EGpY&8S`y2^+Ci_dVeu}Y7s{hSPmUE1O!Jt~=8c~vxSdwa$ zT$Bo=7>o>z40H|5bq$O|jEt;|46ICzwG9lc3=GcOv`$6Qkei>9nO2Eg!@fjYO`rxz ukPX54X(i=}MX3yqDfvmM3ZA)%>8U}fi7AzZCsRSGiow&>&t;ucLK6V6Pvx5c diff --git a/android-application/src/main/res/drawable-nodpi/symbol_189.png b/android-application/src/main/res/drawable-nodpi/symbol_189.png deleted file mode 100644 index 5e2b50fa655a83a92a67442551943a0f2c62f0ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 568 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjfl=Di#W5t~-rH$s1)B^6TIct%1~AEbaB3<7i5req32PXv zJvgT*$a=6(X<#o@_@jDyLEOFV;t6G+&32#UV^C}naN_uB+%BKtvY~mq_Nv_O6pf1u zT)WwIcqTo#A@cTs*~HRI>ueJR*j=L4)0mI;ROE|QnOc?Y>E8SF?^X@j^C4RKOizAC zY2?>r@IRik&$uyY-0eucQAO zFDEfoeOh{qSCpaESY*-rclA~OKYKQXZTRgr$6y|#u#S`2r)VQxVR`-wU;j)kk6IQ~ z>0r$*vHpLN?kwF;j|HXJ-BeF}EO@r)EVsqHfmwx!UcGrAf)gEP#kAU9#$f=gNMwFx^mZVxG7o`Fz1|tI_16>1iT?69~BO@y#11nQwZ36=<1B3H6 zty57nyLu3TQ;zbPq|Nn31+`kT}LZBqb zFPI^qfB*aY4F&=Z>l4l^%r6MKD7_0P$C%{p?jq01E3g;HVK4FYb!C6T&MYRX+S->J z4V3osba4!cIQ(|n?V@G{fwqq|6C)y-y8Gp%U5B+JpPmapnivx}y|3o6X!ulv7&(RQl3M?54x~oAz6}5GwM+2A z0-FO@MP%0B*Is+mzOnKIucMR}!{Yfy$8%#etWJx*`pUWQm!o1IYoGWIev5+^4_Geu zh@4Qpt<2J|YE{nB7_lhk821jpW87+?f0-34^bYbpVqL}hi&HT`_kd!Y!u5zH4*81& zfxHhb6$ih+7w-{!;k%$;XyNzZe9K@yR<=j;Io*D?NA)L8o7Aqm_@mLs_E+xQm(026 zTyBgL$lIAP<-srWU72yL3qP|q7^-c&P~*t4u5Gp^ht#EMjH%Ykt~xfQOy-~cIV!2~ zCx4dd#zT5Dp1;=GleX1HF>l@5K-r^fRepz*w6{&1y!|sX^UXQF@0k350s~sL#5JNM zC9x#cD!C{XNHG{07#ZjqnCluChZq@I85vla8fzOESQ!|cw`rYa>QWZRN6Vp?JQWH}u3s0tk5+Q@9tDnm{r-UW|a6}n$ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_190.png b/android-application/src/main/res/drawable-nodpi/symbol_190.png deleted file mode 100644 index 176a03781e8c985b4ce5f6bbba296b4079e72725..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 704 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@+A+C&U#<69f(n4FAFC zHkgE~mjQDXzw&IfUI-9=~D-NMyC4tt5GuPgf#c4jeA)z-e;XrRywPZ!6Kh{JEEUKeUI5OCFG z)YKBH=Hy~?`TPIBv6iXz;vK&hJ=^o{-ee=qS<5PV@+6)~7fv>4OkLdmexo#BnUJ3L zhY3vkMFdm>n1JZmqPKkdFOHv_S3K{S$H9aX+)aV)Wwt6plIuC1NO3-09<_ajPZW0r z&#JzZ4-W2EPJCw8IBo6i;CxS{KqEn3?809puOo%NG{Yfa+StKZujIH&vdkGuR`LK+A4IW>Y3rZb6a zYTWmH!@|<`!$7mD=BRxkqlHNX@7Eu~z&K}6Epd$~Nl7e8wMs5Z1yT$~21W+D2Ijg3 z#vw*VRz?O^rpDR^237_J=WSZ2qG-s?PsvQH#I0dpqOB%SgCxj?;QX|b^2DN42FH~A gq*MjZ+{EFVdQ&MBb@0LQf0_y7O^ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_191.png b/android-application/src/main/res/drawable-nodpi/symbol_191.png deleted file mode 100644 index 260d2cdbb8c83f22714b7ec47331613511f7aa67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 921 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{Jm_C&U#<|Njp{q=Ntd z|3B1wlMd7-R1)MD%)r37f4)M0LO_GT`}6l5)(aHum@Xs>lx0lvc6Slx*&Q z^mS!_!p^Xth4B0Z2bCPez&fr`_*e|t?Bc& zsl|5sa+vI5y_o&y*I$O(56%Z1I;OmtYu@LwFu}_B;}Hvzj-Z%Vtq?R0?x=vBHGS@}T8LhYLF$GxC&-6!-67QxLG67Mf8L-WXNP zt9OfG_s&Dyoi75eKVWh^xajQy9(558`O`Z+yLulp9b_-}uw1q`{pYNQF412dUhKVI znVEg9gN5TR`?UJ(bM;ACeY+GVy?JT zH|Lw>={@r{mOJ`yTit}s-jkcC%oLQpG&|$?3Xv3squ0KfHtCuu3+xtEe3173uYKoFts#{zTa@jI&_L6W&9Qo1T;}x~n8Fza!x+xBBU;Z9mNI zzHj9J7yXBk!BhHfaqs83z*M7J;u=wsl30>zm0Xkxq!^40j0|)Q%ykWnLyU~9j0~(y zjkOI7tPBj!+q6za(U6;;l9^VCTf@FYTTP$_NstY}`DrEPiAAXljw$&`sS2LCiRr09 Xsfj6-g(p)%`GvvL)z4*}Q$iB}feu`I diff --git a/android-application/src/main/res/drawable-nodpi/symbol_2.png b/android-application/src/main/res/drawable-nodpi/symbol_2.png deleted file mode 100644 index 4355622e486eb0f6f821eefc7fda7678f234f8b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 963 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*@$C&U#<^G_oU=`50O zIZ?a+!R|Y6Z~grFbHlCG>APd)<_Ns{{Ic|5uJua&-Me?!*4ECMGw0>Ymq7FN_4V!S z>{hQ{ed^RH0RaJddHLMj+@78uul07fZrwWj?9{?5b0W6-{r~@;HLRTls6n74$S;^d z;eJ4a!29_Q`wbG#_ZO_+-)^@UD94!O?e3x%a#^4q$YC$>^mS!_!p074i$s{~mc=u+isnp-c z{0TF;deqZuq>s7P9B19&%VNV&AX~eS-~PiF)@4f>&XoN8tS-N7R!zDOtAp`Wv&V-c zwELz-bG}%5>2Xbgsm$AEj@}SG6~+&{&z;YaoOh<(HMc%aydXxRMZEEp>E8=a)*cmT zTsGkc^N+KhE06Ow8FU3sSrS?6oXG9nmpnnCt0q`DK=QH}e{S)Si5}Af$}HpRRO`3v z7g`9ldWZywKVM=s`6$O*!=sHFEpIhbW^8g+)ME8>EmY!47h?Y>n9G}WjPIy_qim#J zc#X2R=!w*9&kG@Wg5nPOPfsnnaB)ed=aNMSBp+Kxt~iio@~W^kK;%Z^p65)mHC4@G zjJwaXK2YSkbK2$E-lPLuS^}(GJ@-2$Z*#AF*WAG^W1x3p(zlO{`C9#_Jj|1pa61*s zt9NakP@o;(DR|L&Me9y4hc(CEG>cyTsZq%IlN^jr08vr+AeX}4-V|8FtWfu9oF{WM`h|<Dt{`>v_2Z8ko=N0A`EL zn5b%NUv4x|y2aDQF(l&f+i5o^H7f|X7WN*~(Jee^`~Uyc#fwavG`3v3vZrF+ny&9G zv&Cjl={IS48h0x+*5Y zvBd1ed9G`0a~nLHl&qCBK8fA(ysF5`tF8I;Z+w4~ewnyfjk|MM%!QS4?mZ2E+ZV|6 zHSGNGQ6rG_kXH&|Px`lo2e)eYeIJo7*Ouh?D z4@-k&eA#LzOx@Go?N_L>bCCj*Y3{6Lrh;;c_owyoR%j3U(%*NBpo#FA92_RelF{r5}E*E%|zS) diff --git a/android-application/src/main/res/drawable-nodpi/symbol_207.png b/android-application/src/main/res/drawable-nodpi/symbol_207.png deleted file mode 100644 index d36b78690d743e46062058d559bd468c406a6184..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1211 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjfq9;%i(^Q}y|**&W{0>-9IG$>_U2}>(;c;CUNO0um)%@@ z^^kmeGj)M%sdQ7iP|6(#Ma`0j>=a08Y=&erb+i8+^GkI`(~j z(#WZBKIF^Vm4_B-2h{L(98h-T4e-{Tz{r!6Fzx1n_o6~G7%zk_lwcIBR4HsQ`FemW zV(*gx_v+7^teg)$IsCBt_qvJ92Y5L$bld|sonxD{q_OH%uMrg(uNIC*}UgMXfyZ`swXgQ)_>(yZ63Z`+>Zs<$)BT zAmhZ=t&?~jJYXmao|_e9+$_B!Oq5kcNL+ln&CiL3p&t(~zp=z)l1ts26`zdvD_xw$ z)~hKY6aLNI_td>*Ojmv!Ncs8qr-m7;o{;_f^N9z0bIO$NJ_yf!qa>{o_rGqdUXDR& zCuiElTdYxq2^kt&wr%?>p>w2ouA*jz%>wIxL7poaE;)3i9=Npk?DOAKPQRVc9c=Wo zeIx4$p<}(Qd!$-aSeV$`O;$&^a^J3hIX(Z#i*gH#^{Pv+&S%PaEiXNH|FiRxv-5RJ zj(k>jWa>7_l*(Mx*>~UXyzK7ppVsGHx}oCn;&e>k@j16YzU%LMo0qpbS48N}!*pj| zaqa!G`oF%$JnuZ_Z#G$E--I8(@9k&b)32{$6>eOARdP`(kYX@0Ff!0JFxNFO4ly#aGBU6-HP$vT zure?>Z__#zMMG|WN@iLmZVmeqZ8d=!BtbR==ckpFCl;kLIHu$$r7C#lCZ?wbr6#6S T7M@H6l_(6Ju6{1-oD!MNS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}uj%RH7?N@C?T!6;mjguDKFpuH!!t@NAV7MhuE&7`#~LPB zHQl(8$jI3uz<=O~^al|ereyIjF_j~yxHlMV+p^+lr?9bw@0~*e$1@j;)H_f4{r_|M zJKN`Xyj!_Mwf?;4NVBujHFLEv|75ISAnfy7l#xmC)rl5)i39^J|CTDvPmRgEmy=HS zZER5E5bU~e<$&lCHjAQ``HMffbe)N9OsZCJ;4M8Jv9+s|N9Bg_qj0}QN#PS`Ow|e^ zrDt!SE}!peyY5}xpFPD3jy*X&-I~>T&)(mkO26elK6-BYqQ%{s0t;G~m6ntg{QYy@*3sT+&m!XiUb5!%tBb$WpSvm)Z!lyl6I>~LRJ}@s@5E6NkBjaLy4UGBo_p&z`L0fg z$(bj<6C{D-W>-EKphI?P0Y1 z&UAs&;>llCcfP*q8g{_I;J69@@u_F$RY>eOKf@ud$>mH@pTlZ(GYz){N8brv1sYF} z^%s79)@a-5GwR_+<`U?A#rA7c&&mU4b9OVOu1ovL zqp7`IJxa}K=JtK{{kF&3PXXgGWJQ7D2X?08T|2z?ow@`}N2(>R5hW>!C8<`)MX5lF z!N|bKK-a)r*T6W$$jHjbz{=EE+rYrez~H=1>r@mCx%nxXX_dG&>`S!O1Zt23*$|wc qR#Ki=l*-_klAn~S;F+74o*I;zm{M7IG8L4#89ZJ6T-G@yGywnu5mH_N diff --git a/android-application/src/main/res/drawable-nodpi/symbol_209.png b/android-application/src/main/res/drawable-nodpi/symbol_209.png deleted file mode 100644 index e984cdda504375ee75a9cc1759452397e840c214..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1321 zcmZ`(eLNF*9R6*#Focc~%~qY43IJ5yA=q05GBi zlIU6{d>K8M7D03;LyNFPVh9m{wsQubV&Gbhi3_BM0FY}30H+9mHSLP?7Jy7F0Pms! z@U8~HBCV$DJ0I-<8XFWq0-7`D9^TO^T{b0ztUIl%gEY70m8V8&vkfUEVtCSosyZrZ z8^dz2;CKAK+jvpbXtQ;&e_6;yl6t!%!nvVPRl0_Gx}$_K;>*8O7-(L)HZ4k8B9;_d zslGktWJVMp5>%_jp{`;N%R|S57DnjugwgT8JLk%cPbh{w@D-a~o^1Fz;osD}7im5g zB;Hx9)p5Ql^Ec3B>j|R97M?d=ZX%58|7pOTq$7o(UwW&JYvo>7Y*8H8FO03o3~b

c0fmnUiNL(GN;4B4hPSH$qC^oV zhA{VY^s1epcF3Y%OwMw?axm3T(#=qV)Ts>x3mx^FL!tB2nHkz&etz&sPC10|L@K?M zjiM4j{74^0ICaf*sWkD-K-K2mR~0KSmxm#>1{~@=`*b51jDUelBz+EbzP!g+FCyAM}V8cM+M`24cq8CBC+KjUOiRL&-z+wq33@Jt4OkD2g17drPM zZN;u-{X^p{I*}Gx=|7P?i#m{K{Ahi9YgINn)ASmImlbVZ=JzUdo2Yln851%XptQf0 z(?s)8KQOBcsGivWp^x8{+m|=d{wz=Kf!{Zk-0IRL^@63Oq?8Tj_7pD;p4zB|BOU6+ zCl|x8>PJ!aGh-6L(10RCowwFKz}xFm4>@So(QRqydNZJwQ8O+hx3T9hT?X`}hk~`` ze2?B12`t5lpffpFMe*Hf6yC;h651MAD@R72?{YKDuAq`2){s1gj4L( zo@1+VD+jxAwlIBF@y>VGUEwUh0_$AZcVTP?vJ)dvivAwAu44J$Gti<)8T z5chdE!e?A_SIL{0JUN{F;uwX_1=NILu+^K(VE12H5IkC1|Kp`+*2B<#@at!*j+tCc z9l!}Q_1Wn0+&4W$=|Op?vgb613yJ(;bxYVJ+LCcCYg}g0t;zYs%U-^EPH9_1Xthol zf_g&tZaPyrYjIoYt9cz^JpXeb!XDMgwL%`fm(D=FdR#=MRKYKbo(20oQ@Q#a$y+)- ze)K>vq&_d7LgE&CxtZQruekpHMczzHxV}brr|8}n8V*Uh^u75n3418;ZC)Q``76!K?nf&eX}z*{z-h@H zblPN1aVh7%Eg`^O9sgK8n%=z*Vd1wt50*ZbXDRJk_beb)1+Pzm0+*^5zATLtN+fqR zl$;1cYUqo(9Sz@$dB{Ua;@MT}BN^z4LUOpHwkmAdC&?)cqUtTz@r?8B@4k0F&6e>@@Q{|&t{-|W&Fwto2##!6sk$7C=8F`gC6 d#86UW5}9;nOngrIedd?`0u(Zp)a)N!_%FCmKI8xZ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_21.png b/android-application/src/main/res/drawable-nodpi/symbol_21.png deleted file mode 100644 index 0be311630b2d5f229cba4f7844ef9704b6ad99ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 836 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$D_NC&U#({?)Xm~Pz{_B8%TgyGB zh5;=RC<*clW-w^jfB$`dfP=vLg!2mX3l=U8e-D&nO!9Vj5q)~&=VBm-y~NYkmHi1j zvzVxAYhP|OPC0G=6Vflsd7%N=oR*o%4X&-_n92>n7$gZ#_%T8hTb*UE~ z{d(~6ZJYMqlGWR`Shg(xB72sfVdIx_TRDbDr3PD`EfZpBsC)Bl@7);h`;68FE6Qcp z-MT5k81}10&}N~nNM?iZrS+)=@|PwkcUdmW4fv;P*eba>==B~MGfn?fN=cy^Jk{<0 zpKCJ2>jNC?e(~RB;CwWfO*B=*3>bH+C9V-ADTyViR>?)F zK#IZ0z{o(?z+BhBIK;@v%E-XV)L7fVz{-L1;Fyx1l&avFo0y&&l$w}QS$HxPl(ZQNS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<)!wvVTaV@Srmw=<$MWI`p5*B6&P-!!?m(^DhUEb!7YF(KxO zCLY{tHN>Jr<^ExsmO zX9zh@@_L-N>AR%-xie|PzTa~0Na+8Lm)K|fd9LyQ_eJ}P8;wqBEbjSly+!op!&Ut1 zVYk;zRoq|{WBZn2L8br0t)A1ZcQ~*W6bA6PY{=LY_3pBgyF;DN;hE`^mN`9)7iQw+ z5Mo%xI9Ka{gL|9HE*oF28B9h;8rF#S)o)|xdfqTic~vsQ)`pW(2M)}6-YDXE{*j8L zLMwCYr9fRy)BXn5D-33W2duWNT)c2EtAbs1;*-zXwaN!{1k~AfEU{(sUXuJ!W1QI&~Fw$WFWO}Axb)$4`R zzs>sQbamA(+1R8%K2pt+I-8aV$~C$!oYf*F#n{ARXc(V)cl+z}S9x}SfBM!p;>8P= z3tZI^XPKoO4;*5WdT=>TIsI>VbA0?>)7bE})i*^h+6IG11d?!d?FhK;-b{uMtvA?NjtL)8%t3lr`Yy*e=Y`>#t+_50(e2i@zB zSNGN8m4XF@1s;Ox=brp>+h4h1e!S-dg-+uF)BFJTpTP}T9Ge`tcxRNjC$%XbNd3c} z7sQ>B;(E_z_Kc6G`VS?AoXL8j_(_V1S>UJTKaX~O)yL|2EBeD`H0;0T+_mPq8fOcK zqWJO)pXbKT{>#T4KS7N-#rt`qrO*Tx7QF?J-}RT+hbFGiU%U5mxUAfpe;UvKOyzX6 zGc&#O-{s%`&C}mi@7^KkwMQmD`~B;KYAub97j7H>oy+pz<#GFWdT#McMY1zEOqwKE zRvtNW=-3gb`F*{-^R3tVMr{wj^Q?SF_Tit!%J#}00`AJ889xrO{Q29^*?DKe6aT|e z3NBBsoO?I7Zu-N2y?YOcOm+~7P?Gf)Yntb;R>ph~gZC86+@IIaB(ti9_oQ2Npx}7y|1U6Z*>~YX#c5Q#~#DAYj zc#X=d>>5qsVEOeD{2WXLp5A9qz3mA6=yQJe^+JZmdnsGXew;GbH)2*PUb=gVT*E@{ zeI;Kmp1m5BwaM;|+@?R@jGKXR*!tuff+5Fmwk+-ZyJ5^d$zrGn}27NUKxb6GDJRjcSQ&L`h0wNvc(HQ7VvP zFfuSQ&^0jEH82h_GO{uNS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjf!W;C#W5t~-rF1g88M+EY#;7d8_zuHt!5~@cI8^pD**+e z;x}1X7jig>INn*g!1cmZ5ms(4y(xOTbaxai*5h8sV!o6+c4t702+Qt`9j#&)Z{3=a zre-{|QtzF2+AOxuacNtYont>)aDVUfd+%$$&-vXi=q8ca^51&V!sz8kcXi}T|5Ox^ z;3|9N+Tzh;)bt@Xw#59@&H%ZNnv~eXTW)NyeRD{&Ls0tg4z08auNEzAd@cPnrt3}_ zYu8bSDUnlr7Nv1*ev$Q<-*DP*5ecJ4gILv`nFo4))x15)`Y3Pd(Yx30Sdwf;zmS)k>=YvEaXcw_gB-Ic zr`r9R!tQ&El6LV;V4Z*V{q6n5uame~?jH}?z<-(Vtm^rF+fwscmnR(Onqw8@o3PY$ z2Gecf4i}}=RME~OQ#7}#zl*MsTKA{&*B@Ok-kA~FtcfaXa#BsNygj&A##(Gue_h_nJMXgNPyGv;IA`IHa+XEC z{|l%6eY|3xUC?dr^nE|SmFLZBI$^(`?~LksTjsORUdM}V)m`P_aO3Ce8}AwB?~}Ro z{;;ulcz)(?cFw4t3^0KGI`be{Q`FTzE4$2 zsa?Lm-7|4}&!zwwuEq(RsUdbV>K_Qyls}vt-`jmOT406J*^Kfw#|8ZD{4MuyzWjWC zvRlD9X@rle_dT+Zj;}g6`O1}8XbI;e8iYpEIH~IQ-*^PMUZL`OJQF z@p#qO_ci^+hl3YvUs|#$_+8X8kCPU&qRdP`(kYX@0Ff!0JFxNFO4ly#aGBU6-HP$vT zure?>Z__#zMMG|WN@iLmZVmeqZ8d=!BtbR==ckpFCl;kLIHu$$r7C#lCZ?wbr6#6S T7M@H6WpxHmS3j3^P6NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjf%%80i(^Q}y|*)bJEB8Hj@Q3euGF8YGIz=4GfPUNl1l$* zY&jet+LpI!LB|%QseG;*yASEO2rSj;2q_n1d*$@vP}##nb2ao@*1d7kZDMWLEPG>d z!!PvKxgQgICNIhV^yyx4;r-)ZjNdQyY)|^v{p9Jq>UY1N*Ppljeuq1@sqr>>IPTJa6Y* zjV=8SpCvjNts)o9cU0isrRQU<<~P-#flYLQ59be7gN+0(A zrtZFUv4rrt>usjHa(v@|Jh{$&vAxUVz%jO0k=K`-n{Cd|Se$*kvSa1@V|H^_PGsT{ zwP>{K}QOoGKa& ztZWTEp93!}t*JZt=B@X7-Y75oXK_o9$pkF-Q-964x$4KIHTrk*k?ahgb zB{nNfLLFQ~9L%f=&$NHh4!%F{%)I&YZK~ev)qM40#{KDS#r%+{v-MDgtZX%DvUHe%H-ytt$0W_924MHOwQTav7= zyjmi?C@W+*zprf_+D z&t8LnPnRADy7R{N?EF5Xq#F_&HckxKXD4p*wr<|qoTc;YF3IO}-b&xUpy%Z^mR#ir zk3M%F?7IK`id^~8{=3`j&tz|{tACd>MR2yhGjGRa=1)%^e%XC{{s$|GV^6*uif_HM zO*iUL_V33_4+@*C5R{30KcPXx-FQdkgM$y}^BteOy-2fu+Fkw|R~G&}y|C5BAX<8U z#IN7aw*9(key`suPNK`mFlfn(154%$n+rya_v09S{;^K8c1}>`mDCqzQ|cCW zU|yfnUEs|2{m5SjhQh}eKZt&ea=zDkN9OHb^_<2-tNb0s!MSdA-+u<)MG`$T6k1Av z#e!;yYeY#(Vo9o1a#1RfVlXl=GSD?J*EKK>F*33;GO#i=);2J(GB7xA(>fJJLvDUb zW?Cg~4f_&pHGvu=K{f>Er}@;$eONl88(dOGMhwXV~o?n&_Zo9oT!W|N7* z;V$%Ad|sY>*btl|ABJ4qTi=|O!B^1>31QZ=dQR2XrEai&M0XQJjavyK>xBMB4?Cy^ zafyA^;(`LeYZkI6V=hasvPHEs2dmJ3xqDAK?Kb!BBJuDV-9u9PXt#V_;9uH@Tni>LPYMMJo z8Is+u7Jxu&Rlv9}iyG#?@%`z=@Q2jBT{gRH*gIu>WYvddo(VKZ3uR=MreM#L6TK0+ zv<*s8GrQ#D#G9aQTYjjb$E(1UGG$D@0E)3%OPwm`IT}3i%%U}2dJ^PR%UCP!E+jgc zyG>&QC(gDnZi9~5m`|1H(28`0oRpyS<#yeBrRPRtT?|~+20UuhlQ&Yi(e9th3;ndd zM+sdRf^~^E|G2O(uN7vGPSt|%+hN8(c1{7RobuXmBIzMIe{21wbCUj$(V;|ca;%)o zV&dtY!z-==kzL6VW0eAd_Kku`QCGngt$3hn3lCOWiS^wxdA75Z%b-veN?tM2Wlx6o z^=OQ%85_e5w)4%ryBm~bkw;w``RkFtVp*`RXjUxdc`sew%6pf@Z!!8hfT$dmv;NF% zC_g=ZhT&GUw6397-SBeNXxN=8zEWEKel4JlxxV0P3seI&6t3Q>_fpY1oJ@b3gAU+N z=tcA#Ada;DE>81rEj$%3^X4rR-0`e=+7;fpOR41~^(amSC!hBhA zNl1OnkW!hX!*N`jy_p$Vvn3R|$DNt0Z#FDjZvcyFuK-(YS$H}~iwsV5z~fh5YL zXdoQI&!Z-z@THoDA_(H~>~LxA?2Hb>rNiXJcAY=cQ@FZ%55mX}zJ{FH7W>FXsKfQw zxT;MzC$f8V-!ikhsg@>|F?`Xk)S+`jSuC=!la7MyEuSrVC{0`D8}3irE^3SOgUCyg>kzEU)* zI?at7@e5zl?k|WTBE3p0A6)pKwCOG+%fFNLskn}-Xj)Okt(#UE6NPIM{<@eW?HuD6 ztWQiZIfiN(#GpzEppYn}8SNS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^TjfmzSf#W5t~-rE^_vqc;wj@57ezH{eg6}5v4)Kq5OaB*eH zb!n1sO%P`C;d)Xg zym-&V9WGVZjTrdsm<7Lk1~VL5y72w#g>f%-v@E@Sn!UB&ish6T^P??{l12y090YDZ zSoth2Nj8E-Cv5L>(~yjvOk1xzxHgtqHOL)Ma7;~YIKspw(!dmuCc8n}`2fSC84lKW z!`U7)E3{5!(OklKiQ(Z99Ru!}OfoOy&&2=gXpEXs>Zl+vV@8R=8H3}JzwOksA6?h^ zJ7b25*-c$V5f0|V^?Esnl%`bu|Dkk|g-JWUse=7HbF9N8zXg;1uB_9DH<%yiH((Ov(7wi{_^*>(v-Nk?V5~Cx8F`w;!WAmsI*7o{oSRz z&OAR?%do~x)=jAP%oH0bwuDKnUJ(awt(_>$KK1vjHxJp@R6qK?D4?8!?TqyE(9sjXe^hfcpXXzof3V+2@{|QYjSzi@VDkas?d3Uk; z)y0>#&yz`IQh#9OTu|+^J#G2nUV$Y_U6WaMHR@P5UU{-G8VrFuKtzP)eOOrI9Cd$By&_59_=2ekbq#WeHaF;1H5)Gz%*D+GDnU&z{X3 zQ~oZW&*jvfu)gxkjJ*0P*)oy;Tq{`Su$D1+_N;Uk{k&PSj=Ai@&EM(^!kl_6Ca?%~ z1ha2h`QzWiAc>EnKz&D)H+<21Bk@l(V5Yv~rBH{M*Q+I_r$-!C3Se3n-FW$MXw;tE zeN0;W#8N}<>VNy5)oj}y>(BV^yFt+Mg=z=3ElH0)c8GI3gJKECF1FIuU)27*Y1T+! z%=UPo?Vz;SmvgrkYkR|fd68G=9lAuc1T{r8nJP;s2P4)+hjx8L5N-i0e{}|TDd_BeS;`te1W>PJ2 zjVMV;EJ?LWE=mPb3`Pb<2D%33x(3D}Mn+af23DrV+6D$z1_tMCTBo9D$jwj5OsmAL zVPB%HCQySU$cEtjw370~qErUQl>DSr1<%~X^wgl##FWaylc}H_&fw|l=d#Wzp$P!g CS-SWD diff --git a/android-application/src/main/res/drawable-nodpi/symbol_215.png b/android-application/src/main/res/drawable-nodpi/symbol_215.png deleted file mode 100644 index 007206a575c5e1ee3074d89d0dc70e473c607da6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1387 zcmZ`(Ydq5n82-Dg-4I1Bxy&(+h}Kw_NjA((%r%#2ZJ1TFAGtJhskxholw4y%7b+o> z%QE4lh$EyFrF4kg;)vYN`khbb!};(&&+mEP-}Ano-iPl?))4qu~#BpT^!<7^KA5xM}tiwA(8k``|Q0K(7!Fi8UdTn+&2 z3@T`FIwBcJ`y3-#0h>wbUCj~&4kgV9V$8rm)TyD-4wDF!S(dWbj~R|HKN)x z^Tx=!y7z?9LlCu~1NKV#8)QqiHt|zYhBeEs$DUHhPQKb+-~%4<67=N=<27f;Y8+MKJ*k!JN@z+1|^06_8?S017U$x`G@u`(@Vsk|f4AZQ&+>#4_n3R9NC z@+{_5L78HcY@V{9#Pl=AX*5C>Mbg$(b+keq6O-CMBT;vwVz$}< zXPkMX3>azeouBav5Phj^xa|mb*p@06`R{Ud014NNIbE~SZ3=ZW;t11ellbt~U z@2OF1TnnG=o8siz+RZ@ zIU&4h!(8ZFN9esFaLZI4b44d3YK;pY*#^qVE4+Kn_G(+>YSVmZ0%rE{9h#|`y7q~3 zxyHW2;}{X!d{)-3YeiP~c0ry=NS7zdZ~Q7BjzHv4$q)xZRKHR5tAd&X?CN7hg~|)# zjNP#okT|5)B5$+Ux+0?Q{&vgtZ0OCkWxtbg4Aafd!Z<|Ne)t4cSR9Ge2Tb&1&X)5g zx2I#VxY(i_q7%E|${w5kMn^|RhC!tWFs8J=xP}G|Fpv6X%W~W3_?hh6yu3O*-AZ-} zoMGXutqDXOUSeXecav6wM{9My!Z&M6VtaalnZZe|d*Yc1QY4l=-*A0(6)s#u{?!w$ zv?aq4s_kNdC}WrMFxA1L|T$xs&B}9o0t8TB}m%tt-`@E%FAmFRgC)B~CyZ z?mI^$S}+!57O6%=j#N)`%$~XHy`^d(5#X5+O6>FA8)oOZdVkLhp7*>Y9N>p9?trol z$A;2`D`UvAYfjcs9c9ts%&9+zlGV-4@IgvLrW$gfEIBv9_a04~hd~S#59tJW@XZ{d zxA_cg0-x6@mdoD2xogyP$$Nbzf?e?uqu0HYs*36{`wXa_pu`&?=HBlcJB?<`!>a~H zO>3GR+DcYE6#>^5JX?JYzS`jo7W(kO&LX=(_kagIZ@ZhfPkq#fB0m$sqmP=VvcMYD zhR(&xc0)+nm#3HJTJ~+B>|I|`-^c$MlJ53;U@s64k;6B#e_&BohV z8%L2#Hac{sBAoBl`LbgJCQ{)yt#et8DOt?uHbA3sXmrn!gslG<*nxg${JH;cctSVZBQfmy rb-^XjKa@icW&i}gKpzH@%%(FL&J4OA_uO;FuLK0hM2gh|3tH?y(imE_ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_216.png b/android-application/src/main/res/drawable-nodpi/symbol_216.png deleted file mode 100644 index 2eb11517f6cbf842d7d19db8cd00412ba43f00fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1387 zcmZ`(dpOez82*jL43D`Mhpb6WIQ!+^4z=0TCew`ECN^zMTExVP3_0itJ?3`0EV&%y zQpqKkT*^epAvwnpCkjP5O&rq9a@P6p{Bi#H-uHRG?|HxPukX#GdLGe)8^Hkp&?J+H zGzH_n6%49CfYEwffzWU~1rGrCbJaJQ+Y}mkl0>5b!1+A@Ah-ko8;X`-0RZAa0QkTF z0BkV;Y>&Rt=H;vyD1{z9LIk!latFHbw1vEEJvca+6EQI~*r3xZ$7qBPyR1)b z-H2Uk4gcPUir=R1L+!C4b;K+2Q?(z|igtjGr`XI?-bw zn7c1clZTu!!Nk?p5Rg=uPPqu}HFoda+Fne~GxOppw|q1{6^f|fKC{%Oj*Mg>%=#vZ z9Ny}#G!)D7cVMx2q7)tETC$#ENx@X)>tbZ)C2bzo_VA_S#zpPtd5C(h(dRq4i1&3Sn~%@zlu8R9;UL%=l@|Nv>l1&s zmqz8yqju^FFQ8~%BUL|N12u=I=k1(Zik!~U%7+G*oEed3xn2~Q{_k|ypK53{XJO$| zz{ojaooBDsG4P3o1#NEX;B^W;adP@m0pfB&^D`Vnd*W_Wh5EAC+S|MNx6!xZ#C2jh zV1%U-9#VrEPo+RDO5j(atdTcw7Gb5KJH6RRhDd2&$!$Y%#0R4Rq4J`!-XC^)^uW3= zMG=}-kMDL((kP?4l$@{iKkB3ox)+;{o`Xcy4C0+LrV-~RGGgr*PrKxx@8#L zz9cNG+)GKjo#ofnDP=fu;`{f2SA!!_cO$z2jT$AD<)oQv{Ng<|2t4rUxCC?v4Ax5M zT@xoo_xr&*xP%mV6=(gh!z+j@Ty051Ye+c)cUn?aZ$sI_%6oPgS{^FQ#%Xs|n0Ad8 ze%C0Iai!_)+=xxvWV7??DZOCJOhV{NM_o{|tkBa=<4Tli5cg)D`hbayEbO`Go2feA z*7P2iiAI!ZP9?00HFE~$On>6lz8uPq-kcSE#EI1N>ridb$zxYUabLxyjy$K)r^$aw z`p`-o6e06{UDR5D2mgp<)K7}h&*$8yxjV<0DWF>M|3{gT~1`<^^tfrosP5=}8OxuAu}8dE;78}wVv%(5Dice{>E*=~kV zp}?}%uso!m<3X<+KesV3Ga9Q&#X=nOag3LQf1ml2Ab9`dzrw=*1&99|toSc5`~UgZ{}cB7Uw`la{ZIe*Kl$H(;eWtZ$-x;|f8QVAAh15+yu$o~g^R=A1LYW#yxm=dd3MK419I3)Jbhi+pRhBFiK@2t z9NhOmdfl>ZSzj7evfkHh{}Zozu|q&y zT+C6z^TWbLKeoyHD_JgM%pa?!ulVEh?3{May<89ZA2tn(yJt*d&-DG| zd5XDZnSwgk6io%6f}<9JoTmIA!vtns@4l2)>|COtp*?%A;*%7{IcpmfS9mrp`|%)K zaEr=8_1N{F?;jA`Q~HlL=isFS7dEo`u4QH2z`FRH{{b-_-Yc@v7p|^TcM#BF&tllN zU}X)f0_)`M4096ZI-C?=qwjcFoX6@ubM%F&Sjr!f7H%V?A?Tp?*9+O|E-$- z(atwi9T?!MC9V-ADTyViR>?)FK#IZ0z{o(?z+BhBIK;@v%E-XV)L7fVz{-L1;Fyx1l&avFo0y&&l$w}QS$HxPlo%O2 MUHx3vIVCg!0NxreBme*a diff --git a/android-application/src/main/res/drawable-nodpi/symbol_224.png b/android-application/src/main/res/drawable-nodpi/symbol_224.png deleted file mode 100644 index 7de04d129b8fa35059b095c4f4d6ea315d65c5de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1366 zcmV-c1*!UpP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 zVoOIv0RM-N%)bBt00(qQO+^Rf2Ll!rC54V{TL1tAIY~r8RA}Dqm``XNbri=xvoo_Z zyR);TyCo^vppCXRwzg?>(Kd-`g{Bv!p(=P01)&~1RPkmJ18Nm7M(M?a-n@9IAc7T9 zkzNE_!J2eKp~hOpL(_=HWdCG$XFSaOcCy>e?#y<}Qrz!C_Wj;_zu$iI-uwN9F1qNV zi~l>Mw)eAx4HW8h1UgP2cnYKnahZ@S+1P+Z8L)r=iBMXkEdi2C18gk7Zl$7bs}wlC z3ZM`L45C03u*d^hR)J-}rVRK>M8_i#tOg{vN0>O!Lk|!KN@Rh*k%25=xi!&t0-{G4 z6Q15NxC>THkjs(m8yRHEz;&QZ@zzA33hzCie8g)d-+k#!E2H=&AORsHzyJ(3r(^4X z9>&Hwj|E%I)b^SzLt%?RD_aJwT=Q-p^` zJk!h-qQr?4`(i=p;>j29L$4{qn~s1WpzTYh9}>zRFaI7QiiwGN>Nn5%sZk|;bgHC{gGF3HYX&>+zPityRZ$vcJo%lU0Htg-?Wa26^a-+KB(VINC# z*59c92-w(g@=;GQ|1H;9VFkzoA;R!!ZuxS2n`6H_y-U4Vs+3)WgK6^=*x1-uSiOfl zxcKN^H6`TLOQ-&<=X3gVPo6x|e9UHWCXk9s zl)isHu`8HANs1In3=G1A(J(Mbk}6&GyxyFkk3P2uH#`+IuL0-jp%{+kzPCbPOYqql z^1vEJpae+RPBfQ3h)&@+adhz2Ik$gpFHysMjc0&t#en!FU;Chr5zR4P|)I(FU6I_*+TuZI7> z|0kOIes*A=8_@9-bkRi@U3AfL{0Cwi3ge|!VxIs203~!qSaf7zbY(hYa%Ew3WdJfT zGB7PLH!UzTR5CI;GB7$dGb=DKIxsNLJcX42001R)MObuXVRU6WZEs|0W_bWIFfuSL zFgGnQGgLA%Ix;XiH8U$PFgh?WzF|En0000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+ YQe|Oed2z{QJOBUy07*qoM6N<$f?>l=*Z=?k diff --git a/android-application/src/main/res/drawable-nodpi/symbol_225.png b/android-application/src/main/res/drawable-nodpi/symbol_225.png deleted file mode 100644 index 3aa23639cc6e3ee19d711bf141b26223d387ce98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1114 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjf!Ws6#W5t~-rE_`9ln7Q$Lq7-7pI+(IsULGKri`_#Pt|2 zFQLvw9)Tw&PyF!UWcQ>!iqj{3dL*Wt-||Fg7Q5#{H_fz;qLXVgXBGAt8>fG}clz+X z^!c`D=Ir(RW|;DS{mN z8{{@QXeUfy^HGTuYJv7RqxM)+>wO--X$0jUj>e%1@my?4<%E~I$E#&N~Q@fmJcP{!Ks9)C@rTB{Z`+QTA zm$u&`veHU2zrHEldUfYj&e;|VmmQzq5L;KOkW{tA+HOvc%F~)DhHtJoKhnKjEb`^Y zznQz`7yTCIFyTCJbE@C{So5a_-l^PS+e)9=mvC!)FlniztbIOZPQKf}ho>_hUijs@ zv+(%jYR#>&u9Xf|FRopUjg&9-Yh0Ro`n8+S+=mS#@ z*ZGtCuI%_`B^iEt0&Az~-Rc8ntCC|zN7BD=kl~CZeG5tE}3X`XN2-qZ~#-X zpwf|s$Lwh{KgwGf{@)4ATdF0l5hW>!C8<`)MX5lF!N|bKK-a)r*T6W$$jHjbz{=EE z+rYrez~H=1>r@mCx%nxXX_dG&>`S!O1Zt23*$|wcR#Ki=l*-_klAn~S;F+74o*I;z Wm{M7IG8L5J89ZJ6T-G@yGywqXk>aBO diff --git a/android-application/src/main/res/drawable-nodpi/symbol_226.png b/android-application/src/main/res/drawable-nodpi/symbol_226.png deleted file mode 100644 index 9aac0dcafdb26d8ea67cd0a5a0c95da086fd3a91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1455 zcmZ`(X*|>k82%f>2xSsEcg?s)N=-v(9P9WybBwDnD>E^Ub%Z93YmFLV9WxC=Ba|c7 z%3Yy`DAyK~&A3ZBBFPn#vmGDz!+v<5=l8tt?|I&DPYTY#>Y%8+C;$KlZLC3OKAY^1 z2$YWip~;PpP=8ZnI znrpdJg!9BZ+l3t0b@fqI8VHuu3uIf@d21WL>g!VvuB&I!+{b^^b=-~Vd&Z0JH{y+7 zfnmB4H^ldr;M~%?p{*+6#Sa>dq1>b(SA6nenPSHySS(zatP^~amVeYk0BLFRhf0yw zn>y1EY!66KrzTOAsNNY}4_GCJEULl)xcHssf`YzV=B~Qwj1h z*F&^slEquUxVOBO7Y;>Gg`phehNA)mA}J~w`jk>p{4i>%`lo0!@!j9Q!?kp9mU4+2 z8X`_PUIq}|F5j{a+h0)$x$rn~PJNKIOJmxa0D<@REpXpmL0A&GM_EUn|lq^Ori~*B! zdi%q3X6m+CS7J`JI25Q==Dqex!b`o(8gFr;WF1ha+L)l2Y@s>^ZX_*rbyuQw`Kg-m z`nV-d%Y%7u5RRa z2!OfuW0e!Q6K3JHZu1I+n}KBsa?~fdMW{}@3Aztbi6AiGZ7x1;u`4iSJB3ivW_MI1_=% zm!mhIPwP4$4~cJ9h19e#$5P1bvy-F3_h&`S*Q|o-p`9582^nAGYJ0bK$;AwXGYvGc z?&_0)af5GVm8MmdSFWYdtiRH*Sb1W5p?H7#oorSw-H2wZJ2LIw>XUxHo^6mE8F4Qw z^7-JE^PB58&V0TUm_8cGiQfK#iiuP2=caX73yJd1?+hQCxpV!)tq1*)_L9QTY0=V! zkpW4U+1AE+wVm&$zaH>2V zGR;A-GconGtIGt>ye`Xis5QhNWl)iJ&h|o{T&jK;gD!K5z7hX;b=k;!z*i-RFqR}zFL2mzp%Vj_EHDUw_F!jBBiG;8TA^MY?NkreM@E+2Bivl(l4&XyG H!u5Xv{#Sy& diff --git a/android-application/src/main/res/drawable-nodpi/symbol_227.png b/android-application/src/main/res/drawable-nodpi/symbol_227.png deleted file mode 100644 index 679f348849308a1a08dacad127a8c4bcd03d3680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1166 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjfw|Dr#W5t~-rE_cv#$h*9IN+Kdug-fmB!W(!J}HIbaYr3 zE>I|4%sstpf!;2G|BQ}Ho64TM3AS)4EtS4|b876gMM=8_@BUy|s~^y{w)RF@TyC76 z+RS!~lfJ$yllI+InN$6)=6lWedDTS$!o2DwJEH}VMWYRqd?Z3 zK0BvXXg(1$OJFb)YjQfmlIhj(u(9+V=)Re}#^v1czf9I-rED%&~ z3pppX|Erj{%l?Bme|N2uP`J6luyDcGfM}a{x6aMkW&1-%+pK>EixJm?8==`Rq|@eE zdaVp!YB;&-(&T&Ze0DuMxAa?`)P_dO1BbrMvJ=^JuJn$M*q!Y@x7RJ15wE~xs&vly zut>1auKgSJ&%4Jgp7!R{g@(4ao;Rg8ngv$eJz9JwOmId*)60d+MT?KenS_L-q^z&! zG!^~6XPwRa48hNwMO<%YN$3PA@IPskFcVOZ`!Ov;Z>IT@xl@13+n7uZr_r9n5;Wp(gM8)x|HVyNA3d#M!Dj;rcX z{G9?D7$>_bh_7CiU6#N4xq(?p-HgbD#zn%8yKOETaYUptRUZ8!dvw7$@g`&&Fzzt?TAqm?v`L*B-^G!2GCM;u=wsl30>zm0Xkxq!^40j0|)Q%ykWnLyU~9j0~(y zjkOI7tPBj!+q9x;$jwj5OsmALVPB%HCeQ{+kPX54X(i=}MX3yqDfvmM3ZA)%>8U}f Wi7AzZCsRR%1cRrmpUXO@geCwedFo>T diff --git a/android-application/src/main/res/drawable-nodpi/symbol_228.png b/android-application/src/main/res/drawable-nodpi/symbol_228.png deleted file mode 100644 index e8a4cde2918f58ceba3d7dbf088a96fe64cae687..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 858 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}Z|mve7?N@C?G5j|%K;+CKHlFNyg-*fuv1Vdslg$Ztvlg_ zn1pd6Yfh`K!bbKq4-U>FEQ*Y}p0AI5OMSqunJcxuRFvtTcju&R^?&bvp0oXa@Bk3} z_j~bkU)PPl*HV_=-DSeKH;Z@eg^){Lc3L)FZ-4Vlv63=;rD3da#c0<1&msIe*#|fN z3uWi5-^zM*tBCUL8{2wk=jzl6i=IgN(R64>?}*E)B#)mM$D z60;wuFXIc035gM4iQe|+#@5##Ux#lL&YyQMw&gmKM`fqO^XIv!7C;Py-sI_lt z1@EK{N+lVV;_00Z9q#hCx?8qxd=SB6XCwVI(=ke^%_B-pb@t7z%QsaSy^1^__|86} zLUU@__Vl$n7Tk`E&w4#5ntXx(_cxQJ7T0x7rk&WG z?|bc7(+hs?SFs2F>`Qb$!0Y2XQ8SeLTkx9~*&-pU+m`%0zG9E5oh!?fwGAgzIU<@> z&J@0|KK148zr8lC6^9sBuR5Zk-dWmvW;*wa^zxX%Ydg=MG55`kGtyskrzy|ffp-4Mp5+AP{y=Km5&|%HC#5QQ<|d}62BjvZR2H601toX}Pgg&e IbxsLQ0Q@UrNS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}pX}-47?N@C?ToW|mmNe}_e-k#KHAX8rFBp!^KHJ2AMd@6_1c89lTW{=O$}4twz^J>6 zKmSL$!Y4O7iIuDzlTWE^y|Tf!#`bVr$tv6Y8!DHs}@P$%Bj2=d_c>9ahZ#QO}W_=7lrni5MB)> z1qLN02UYdQK_O?FWb*Fsx!;z@-;&jOf$tAPnP1s`o%_GNls`OpSGm}J-dmtkttYP7 z#Oj?`utzjJveCW2-|o;;eTC9$rnwuW4_ysrTBgTckjr%Z{rA2Gy9E-=ioyvD8dJ0z zyCM^wgEN7Qoa=UdUG-E!jVTtct~wihuSqE1 z|5r1Muk2UNaXss|B2QyPUiL+AY0$noxq;y}@9Y*QQQd;QRyWUOeCuMnG&kS%fBi#I zjUurdT90?W=llLIG~&PQL#dMwnIZxfyY)($n)SukIecFE{_5-qUY{B5^>gTe~DWM4fiw0U~ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_23.png b/android-application/src/main/res/drawable-nodpi/symbol_23.png deleted file mode 100644 index ae14dd664c0560315bda1a54319bd67dda0ad5d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 833 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_235.png b/android-application/src/main/res/drawable-nodpi/symbol_235.png deleted file mode 100644 index 02bbb710ded17d55534c0d125a65169973fdc254..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 776 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjf$_Dci(^Q}y|*{^=iLerVf!%uKMRM3cU#C^>kk4vwLLtc zSKD7Ie=+@~^!Apnq}7&U6^*4Vvu__v2#^x7=5q@B>-*vtSN-$f=WM^rTwdth&iCJX z(Xrjm#!MeCo{(!i5Ex*(ien;2=FV-~j!E(Mcx1oP<#>~Q?LvK2qN8G6&ptc7)9T#Z zK7#Y|kDL@;F^zd5OYLHQ@qG2$M{m#W-#+8LW`T%{Qs=^j*N@G=-!8O$eorqiFR#mN zk+r?oA_Nwvn@GPAo1X4ATR=+Y_^MI`C#93$L{2AnzSXQWi%NA=Iy>p^BdcjyIR{UQ zzThZfv0^HnsgwtOrPEXd&S)})?Il#45jpY$LOV@R={b8YT ze!F#N^u}mLZMt)*%x^|=YFqX9d2^(t1Wp9i@@$+og~jMdo$|U%>RXO9 z8n3A&w(TtVm;7z2g8!-0D_ler&i?p(R)qWJ<@(rkE4desxmGT$KVKQhzAR$r;Y*jk ziOA@~&f5)*@Z0fV6R>`S< z1-J12b!g|4wJNc&{KuquaN19w$$t%jDM7WwHKHUXu_Vlzq` z7#Ud^8CaPbYa19?85o?mX`PCqAvZrIGp!Q0hJA^)nm`SbARB`7(@M${i&7aJQ}UBi e6+Ckj(^G>|6H_V+Po{#BCxfS}pUXO@geCw7F)!2r diff --git a/android-application/src/main/res/drawable-nodpi/symbol_236.png b/android-application/src/main/res/drawable-nodpi/symbol_236.png deleted file mode 100644 index 3caa619c7e03f2f5351c8b8f70182286c897c4cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1229 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 E0V>;zCjbBd diff --git a/android-application/src/main/res/drawable-nodpi/symbol_239.png b/android-application/src/main/res/drawable-nodpi/symbol_239.png deleted file mode 100644 index 49fe5b502abb76c12767fc30e2c7b2f335662461..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjfmz(s#W5t~-rE`W8Nz`w$L-(iWlnON9mM)y#JVIvyW^-U zhnOsDU_p`Ck)v1d-n5^r#22*t#iJ*SM0H9waqxwfT;OX>(v;1~x~wvNw@Nvme)-NT zTfXb{Zd>^M?4;wr@9uv8{`c>__y68&<`7hJx$#;+cH88FE52K0OJC0ye4!EkQ1I$S zn^R|xEPZ0e7r-i$Bf=~gyhM{BaQVYN^B{p6zIvRZT)VAUiu~ANAFY6BM1hA__X1IXPIQtgLLeId#63pSQ!e{b6 z)ze{-Q~aTvB&~oqTvlQ1e9LZE`-L(xX7~zyQ9f%4zO zp^!=p(|Nsla@jt$r&pG@=3Z|+x%y<$Cb{nubJBJgZr*0KamhYE38q>5`C@i$nt5~e z^(UH4Pk*&%ymq}EnqYk9+?`pR$@j}Rq8`7UefqIOqfnmxhkA}RYo8U#+uQ#)*?Nd8 zPdy>9t0q2La4FIth{+G#Es)Sj?6_^x9Z& zxLrhAj`61GX|pw5Ns6zU*4;Sv_QUC2_A8&AoXE^IZ)&W)?2axC*>k%b7}-}OGA*4E z->9T|s^MkiNtsMwT$fl(eKgC#@R|Nv)*fCKvrA!4;w=lfru^g$(b{}esi7drG|X@V zhibX@ig|t2jUt-;A#w(Wj<)xslaD(uD05Y=2{*ZPe}cGS?D__kTQ5Gz-rskB8Po0E zEABiy9eZBMr9(jR(7j{weNX>(vE96T1(<78OI#yLQW8s2t&)pUffR$0fsui(fw``M zafp$Tm63s!sj;?!ft7*5d7IX$C>nC}Q!>*kackI@XsZd-APKS|I6tkVJh3R1!7(L2 gDOJHUH!(dmC^a#qvhZXoC@V8~y85}Sb4q9e0Nb~@p8x;= diff --git a/android-application/src/main/res/drawable-nodpi/symbol_24.png b/android-application/src/main/res/drawable-nodpi/symbol_24.png deleted file mode 100644 index d2b4e9d72273f0ababef24cf53228f24ef70c358..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 997 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}f5OwnF(l*O+nE<@XB!9{vwwb_af{YI zeq>P*p1@n6-r$p9#hAi$!=bjI+0V>FrsK;(ySQ`Pj(ne9667cTAkBRD&Hs7Quh$C+ zZsQQxaR2r~r&e>B=Zjl47KqvF3UTb);qcD!&*PPXpPr~@^?!P<{_Mo|drx&araNi` zILxvU-1f$F%?D}sl4sNTHSXF5d&#bfI=ekgb^1nym`{vvC+GZ^Ie14A09=Ct_o<~9P2$@aVw*W)B)AK!HkmALsn+# zzD>TnZ3c@#)Kg>Q4ZmEid%t<;1{S#gS^qAUYtN&PMfJ=KQZ@^uUMg?Z&S7|OC2?%c zk;gCcW$Snr-F(}3eao8n?;xJp3p<=>nrjlvr&sH%oN-pm#_#?yMS+nc$ z{F#e3Gwu_%Kgh`2z{YNKc3L{qkz+C{JC3t`e`j)BzM=BZ4@0#E7sCz#VfzT-2Q}F@ zB?TCZl&vZl;&(7KICR;r+TZ?8OtImx&(BDP^o|QBq@;|TZ9bQXOy7Hauj@vJc^hBO zZ>x!)At!?$E#i3Q)=$~!yJlU3Nqg#(dzioaTrev^* z9jE~tf1w>k z3{CZWyi4ytYGIojw`j#z*5p$%KAR^nc~~FF`|)h^k)BU3jP0CJizdsZDK7hzb;?li zBA=5gw}R2)4#w6Rj}N;d=Elx56=IsS^|<$gT`D&o+`e+VdY{wWEl*XsW~ToXw)S^? zvN37SIq#*cW!UO_QmvAUQh^kMk%5tcu7SC(fpLhDk(H5wm8r3|fq|8Q!Fik3sVEw9^HVa@DsgMr zmuRaA)F276Aviy+q&%@GmBBG3KPgqgGdD3kH7GSPrLyp3Dk$$Uc)I$ztaD0e0s#34 Bk|zKF diff --git a/android-application/src/main/res/drawable-nodpi/symbol_240.png b/android-application/src/main/res/drawable-nodpi/symbol_240.png deleted file mode 100644 index b0122b7ba2c126c4362e94877fea4cf2e995db82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1557 zcmV+w2I~2VP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 zVoOIv0RM-N%)bBt00(qQO+^Rf2Ll!rC54V{TL1tA_(?=TRA}Dqn16^=RTRfR^WOY; zv$HeXI_v(@pjA^h+p-)fl|XT|e`O%y9y5vH!nH9?e$s3_a|FwNZ62YA>*UE zt#0S`%DEO@I+rhx_MC8_;KWA~Co-xz)iD;gc7d_h6`-1%`abfn5LKz6qoKp+`ckmC z;r>8Yqx0LHpE;C`uj(?-#JdHXNtfgq3~Om<%wWq}fc z@Zh~-_<>m9>#-W2{2BUAylq%oOt01iWMu5PaW@BqaL+fyi4i5r#k?o_=~kh0$6Y8W zIB{Y}LK@%N)&wLZ>?kNzON4OaVFtKFlqeUtzy)J?qFYY&p33TY{r5GZ;J|_7Y6#>| zF)v$+{N9l$q}A0a%6C>@3l~U8$SCi&2vMw$K?aEvCr&c=BuJ8sofmp5XJbP$XI~)P zt(T#B4%So&QEv>D{L{|pUPFcM-cfBWcAD#+4_wu83>cfaj0>ow5>l?b+3BcgfL=Hs zxaJn{drH%{CXgY6MtVnHbhpewLBUOh`FNV9ici;=RcZOSkggLj1rX3N6%|IRJ7%JHXiPPDVr*>V_$hvTQ zL)*$1I@h(;-g0YJHqd{d-?~?83#h;_aR~4CDI)@<5_0}qgdzh7&35TJR*js>D& z*D>NoJy!~+WW~jRj*9x(Q6XHo?D5%V40!MyJ1cA>bT)-d|Ep+)V_>3;NTj1OZV1|* znB~tUTMsOXocyiNu+XmaP4R_`Mm9dv{p@}cKrf&%1mjb%PRX+C;0n6^Z0kdkxz6p5 z)k_0)!7G<*X`nvDikkWw(Ik~xv$ZF}WmF<$P#G#@gA!A+BW=sx8d=@jn@qv%rqR+R zU;Ncg1n2;U&D^-)T9}xCgp36dMybET@e#< z-VKS3tdH{t$$T}oC)8D*4F z#tnym0Rt$`g%eBARsaA1C3HntbYx+4WjbSWWnpw>05UK#FfA}QEif}wGBP?cFgi6e zD=;uRFfh+Ng_QsR03~!qSaf7zbY(hiZ)9m^c>ppnGB7PLH!UzTR5CI;GB7$dGb=DK zIxsN4VLd4T000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o00000NkvXX Hu0mjf$U?!G diff --git a/android-application/src/main/res/drawable-nodpi/symbol_241.png b/android-application/src/main/res/drawable-nodpi/symbol_241.png deleted file mode 100644 index 7bbc9dc404e44b889c02c77b104e5cc552803de6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1153 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^TjfjPy~#W5t~-rE`0JwAaF$LpV;n|t&4jpI6<=}u24PDpTe zY;x&fo5~`1(`k`lri50B^WH|mwM#_vUwKE%+Zd11;M}O?rm0LqSGAZHN^WuZ zl=5)hX<3y7Mj`g24llZlSQTs}>;9&5GNoUd($du;Da$ndG=o*8g1_7go*Kcq`gPE*XX)5U>doC*zQ3uF^-7^ao~4=c zf(5!SBfeW-UUzS4j^(#UZtp9#8jgHn`IBa;CdX8J?bg2h=U3i7X3fZW@#N&?(04)7 zTZ-=%FIvJ59Vld#V^N6L4&Y3FFf+?W3}UB67Te?Xg>u zch`qwNr%p=qLo2ca<{+XFy5U}c|!O8=Qok>ebqviU7yo%Vo}wfisPck3WEdsZl1pN zn}5x{7n`;Fi{xWn9g-9!)~tOgFa0%pC+ltNE5BB9P4JL8%O`E6Rg*F!(e6W|px2ZY zJp1^6?p=Li(b4|@#}zN+?hEFABH8dY)8t96@7tzt{Bycw{|MLFX1AQpWlKG_x2u|e zMcUaDXO`T$`bPdk14|Cif?HACvp0*SZMYdB;js3f>62*RH7W1f`1ttP*tULK!5}Ss z`*);|f#cV!2`BPzwJa@C@-Sh!-gfBIqUQJ8R(vOiybF~ zd#&exP;8T^TehFy?+%k%5(|v9^JMm4U%|o7Sl) z8glbfGSez?YuJ})s|nN~39=zLKdq!Zu_%?nF(p4KRlzeiF+DXXH8G{K@MJ2eTww5Y L^>bP0l+XkK;P3DF diff --git a/android-application/src/main/res/drawable-nodpi/symbol_242.png b/android-application/src/main/res/drawable-nodpi/symbol_242.png deleted file mode 100644 index ed7053142a158f152f414aacbdee9b02287e23ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1489 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_245.png b/android-application/src/main/res/drawable-nodpi/symbol_245.png deleted file mode 100644 index f47a7d9562928afa82dc8ae76d5b2a68db5a862f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1319 zcmV+?1=#wDP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 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 KKbLh*2~7YZFZ@0L diff --git a/android-application/src/main/res/drawable-nodpi/symbol_249.png b/android-application/src/main/res/drawable-nodpi/symbol_249.png deleted file mode 100644 index 0310ff975d29208a9ead066a8391bdde213feec1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1169 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjfw{!f#W5t~-rF0#88M+E>>uvWo|)pb=pu`#prF0O5wC;2 z+*`HH^LB085~a}*Aihg@RjF#3a+r%qVc@O}p&Fq~v7QI@y1F(Bv_!Qih;HQ+5t_8+ z=Zu*u#-C&Mn16Pg;dAdayP4JhyS3lqE!e#^;KOD}UD+O1zHvOAzeoQvy3apL>p^J-_Pxt}%o4dSGZb=M#~DfEl)B$CW!@{&?Daf7QYqG44}~1WInO&gMEe z^?5s=`r4l}_b%VmKe0^Q<#}~O=*MkVzaKo7-#%;4$BS1beHOm464N=xRdPYWd#0#~ z>FJjX&1T)6TQbk;08sc zEK}#JnOoYjhHH!1(pvHP6>sJ)SshdPb@u8nr(Yj_+f;F6mC&hEizclpjJ_ez*y8qY z>%-;txxN3?#m}8Rkv*rIb?=MI9=AfZrM|ah^qdVl`d;?+&8b`JcGP^Ce)i=2xJCzl z;dVBDmHBGRv`qb_xm>6TzoR?tHXwO!oIRwf2>X5y`L}0x=H5vMDeT3lpNVtujt_Y|8cGECh?__ z8)a1^LFwLA{J-WOUiEJx;cLtc{sXh5YKdz^NlIc#s#S7PDv)9@GB7gGH89sTFb**? zvNAHTGBwsVFt9Q(IB(NB6-7gCeoAIqC2kG-5^Xhs8YDqB1m~xflqVLYGB~E>C#5QQ c<|d}62BjvZR2H601(g#Fp00i_>zopr0Bd9Z82|tP diff --git a/android-application/src/main/res/drawable-nodpi/symbol_25.png b/android-application/src/main/res/drawable-nodpi/symbol_25.png deleted file mode 100644 index d04db3a09a956ba8390ad2cd6b3766e682a55689..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1536 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_28.png b/android-application/src/main/res/drawable-nodpi/symbol_28.png deleted file mode 100644 index b233b4d3dd051157b61efc2e3f2e88c7afd8725b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1326 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 C9CwNU diff --git a/android-application/src/main/res/drawable-nodpi/symbol_30.png b/android-application/src/main/res/drawable-nodpi/symbol_30.png deleted file mode 100644 index 10efc5cbbef745276ece5ee7dd56d130c2a3ca0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3388 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 CrAXEQ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_31.png b/android-application/src/main/res/drawable-nodpi/symbol_31.png deleted file mode 100644 index 10205d9222d2f017fb2cc1ec64d99538eee9f038..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1657 zcmZ`)e>l^N8voi4MjRDJOyP{1q_gHY`LVXqh6!Pujl-TU0SmqcLn1H+`FfdpXdYt;5MT+u5=Y*HxEXxa!2w{k8lW5xpj zG=@a*i^_iaQ5c_PN3<-GDJYya%%y^SYY_%))dtoA?V#&c@>~3DsIgl{OkTeU%&zwz z-~qc8I}8B-yYmoH+~3cLy^Bmt5+oPDm!$_su7(_|*`lm#;W7V%TadgMsd=f!cV@k6HEH2XPSZ2OBJsl}YR1L+=XM}qpYxaMYGyh7(b%$r#jZXUzFk*{_(PSnOlgU*}{#?xRyWE)dQ z)3?)*u=Q}urQ7EfpLmfj25v;YYj%sUo@JkH;9!muEcE2q3g80C&h3T4{13JulSf(0 zytB0rS9$Z=gNW7d{oxCbxR2>8P844dO>Qzf!y0lLinwS3Rw;5achbNSC0pRp#nE!kTz<>^BH(C@0ML2K^k0r+yW%cMYks(= zclMm;9S)^c$T3~A{)L5+F3kb4;4b}kVxT z7J@7#8MWIYOR*M3m+C5qae?0^U5s%4>M`77#tc_2A9Y*UT6?a;@t|?m^xO*V!_on8o3f7fN zYz8|atmg1D>(SW7)~;Km@=p6x*9Yq)u=ElJ(4(Vm=|@ z_d7G0r6PDnP{f=MHgVZeH-aGb9Qy6+dkzu?<|eC-KBcu_Jg@U*UC z#c)#}!;k?w2g#Qf>AEUh^P8GwoA^P}&IIUP(|`dxst}1CG0>I)=O+HNZfHBXG@(*+ zi%qY<&)v8z>tk0PBM)&2^m%IIV&_?r>MsP#0XL8I?&;So4alGh3R*-go~i7^o0%VJ znX}+lzI&;WjBQ*YIJ0i2iEfxPRz}xuj(LhZMjW@sjdcdkv13k2r#Lywl3B)m+|{1a zBH0I!Xsx;qg}`eGhwwcXkCv*05wqpp{dc3(!4R(}JB9|vg=PE6$9TJ=uK)9)%aDWZ zUIVLkon@-W_b<#=cqkibM(&r78L4uCv%I`0y0bsNS2NjI7OYMszhmX3`u>YszuN}n z!a&*h%TzaQa9O#yxoZo`xxB}agkY>?ED7d4A4!d9{S#S zE3JD-xY5BJ1;=Dlpr6N={e+ZW%e z?}HOn(+DjR(($HJHt^RH{y1}_@4NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5l#mPX32_C|3{(C?Q2&Mh z`=9&=f`(K7?|=I5u>SwN>by#z0_Kt+zhH)j{j;<`bpW}HN#5=*Y>8<*YJnW~5>H=O z_9yJjVxp?8eYw#$q5py911x-vKl;ItZEAt8r&N*r8s)DBqCU!CIm2s zF(igB((*XW@NzNNi694q73|Jc5}^kiycFBm*rqlGGBEgO=!KnE(@FyxsaoP1QIe8a zl4_M)lnSI6j0}tnbPddP4U9vKjI4|dtW1ry4GgRd49?rMPDRm>o1c=IR*74~zC>G1 xpaw~h4Z->7mc~<}c diff --git a/android-application/src/main/res/drawable-nodpi/symbol_33.png b/android-application/src/main/res/drawable-nodpi/symbol_33.png deleted file mode 100644 index 18b742edfc1484872dc12a7faa790f0f0e1d8334..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 746 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DY8C&U#<*WUe45XCLq zUwZz%U)Owja|d&cHG#%52*@bd=QnWh3FrqW-8!<^2Eu|F3t2 ztpiH)lmz(&GYHIoe?P(CeE<6W4PoqamI1{Xlf2zsWM4BEP6Tq;OFVsD*`Kg8i;1eX z_T@$cr2{-&977@wznyx!tXV<8)%TXkUY?Gk%P;=dr%N*GCvMRGb!DrC|1M_h0}3Ib zo}Qj3&8EMW-ZSm{?Op$mufA(|ed>d{1@;G?-}zs*!v26N*FHY3XQ@BzG=BV?&vZ;; zIm_0L%&7YcstiGyJ(}o=&)PnL*@bfrgFG z5;c|_DfRNVtO6-KcV!Az*=aL;)Zu8cRIpvK_G~}H{}rrFJyt%Aci3;lB%Up(Yh!jj zv!&+Hra1~}S-t|6`^~?uI}mQEs&H29$!U!Sr5zL5MR|UQ9;lr>>4)i!Oa&Wlj(*KZ zqlyWFUpfy6@9t@S%VF{E2Oo#h;WM#PRb1X|3q0CcOJCobeMaeDsN1%G2P)$(+;uc zrD?R;NNk#})K}0-BZ*~I+Mq+XXrn5El0`~48c|6!`o!dqcBV5ubMHO(oO^!f{_bZn z8nVya)W#G5%=rP_FiLaQs)-@ho@gc;0DaHsWdTs9 zL9HmrmX|?Mb(MvMgae)AU@Sd~G-{Rj7@dXC8}*omXw;+HF&tIuF;YWtG%Sr)sV8ub zrja1V4&N@bq2LCwf%~`?(l%s2Wf;r&!93$BV?&0OLt&XD8i2N)&-E2V-k6Vw&Klrs z4l;S6@YLIvFYuhdrTyereLc`A?7ONOCU-;-El_=xzPjpyH}ktIcT~+C->+aUWoN}7 z(TVs*_I?E>mfKd`i{6L~ObIcFl9v>)yJ}8w*|Gtgwo zxGS@l;+pkKaT-FRlAh5m;D=V0Gcok?F-C4_ZpFE$jF~i}+C65IFGng%j(U|5jGI1N z|1x+uoZ0lb&bzXdEUXNI4XV||{B%N6`AGetPRVQUomqOfUfqCX zJa8Ag)QTP)sr}QATa;7&!LEXr(wo6fY;VWkvSLl6oziYU(eyZU%RT$d`1WeFbLy^3 zKijKSUQcoiS!wa@K~LH&zp>mcdo`&mMpW)Dmkb|va>P}x79T1y^9RA)z@IUxK2|W1 zn{ylGdwciHJMv=WCYH+!o09Tcq81HPo2eV*Amc^KL_(R^BQ8};DPSXP#2ImSMqCAK zwg(&WaC3D;5Dx^=dKQ-d10a!#65})f8_+KFq8<~xvNl7wG+vf2OcjH#NE$0<@g>3p YahO;r%1r4IQ{M{!pBKVy@Wb-|21#h``Tzg` diff --git a/android-application/src/main/res/drawable-nodpi/symbol_35.png b/android-application/src/main/res/drawable-nodpi/symbol_35.png deleted file mode 100644 index 2775f1d572b1d83063ecbddf407f2e17c79c939c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 656 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DP5C&U#<;{gc_4F4Gz z-hxR?W!u2wg`&O4#Y9zG z`*Nd!LN`5K977@wzrFgFugQRiHNcFmxUQiqs@?hM_j->&@y0%lDMwb^{Cih!)>3K5 z2cQ2Y+Q?j%<6`J|;iB_U?Bt3AEOLP%4v`KO2bkqPFud7%&Yj_M^U5HZl?Tq;I3r$r zDpG0T)XA04cr=Vk=VhrC1_m;_H9IFL9u)0mv~pwc5EOXWlq{?f%OIc-&-Bbzq0MiD z%Ym#Hl56g6b=H(VaP;N*JFXp-*0XojpDwKWo6nw?ss(WMyPvWooQ#U|?lnaNeeMDvE~O{FKbJO57UuCE98NHAsSN2+mI{ oDNig)WpGT%PfAtr%uP&B4N6T+sVqF13Q8snp00i_>zopr01f8MumAu6 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_36.png b/android-application/src/main/res/drawable-nodpi/symbol_36.png deleted file mode 100644 index 992bec8a8bca626f1d853ec4b029eeeb29f604df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4396 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 d>$_ne;4E-hCx1^O?!OfVps!=1U5&y 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_38.png b/android-application/src/main/res/drawable-nodpi/symbol_38.png deleted file mode 100644 index 24fb32607708a02a9a21b609db3e86435d6438ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 448 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5l+X?E32_C|3=C7ykg@S1 zUfvmJ&YYP!bDx^p{Is+UQc|=3|Nr0pTlX4JIa^7PUogXd1BZf!eeB|ofg+4a-tI1Z z`FjogfgJV{PhVH|C+y5(qN=TZxzRwONKY5X5Rc=@2@2b zf`M$aT&Tk;rY1+<${aqnd_I2G)dvzx*?fnC}Q!>*kackI@XsZd-APKS|I6tkVJh3R1!7(L2DOJHU cH!(dmC^a#qvhZXoC|DUhUHx3vIVCg!0HdOSQ2+n{ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_39.png b/android-application/src/main/res/drawable-nodpi/symbol_39.png deleted file mode 100644 index 5180f9d56df0e267a21c0a6184a0a93a21f42f97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 592 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J?3C&U#fBK)W=YPYg|NEc(Uw`kv!HWL{hyTyN{{Q`t|NR&K7r92N z0uAIW3GxeO=-)3;ps?PdVb{bJJwQRmByV>Y-fvqHzXCbzC7!;n>`&O4#Y9zG`*Nd! zLPtGa977@wzr7a7-=rYYmbhh8-#5pGj=%ryrS5IH$&siYoxA7yoOHf(txi|6&P!>n zwq5hQzxA_Y1aq#TgSy^dTHacVl;DP& zJ5FR;PGz!r0Aw;vVNv6A$YYaXkNB1uCX-;P9LdmoV6KPKq;pIm5m`kWD|;dtET!d= zj3&m&9jG|AM{9%rgZAD(_o@RL^BHcny-5Ghul3=+!*SMgM?d#g2=3apqI*T{2KEW> zlE3=$1&0AWq*~${QIe8al4_M)lnSI6j0}tnbPddP4U9vKjI4|dtW1ry4GgRd49?rM zPDRm>o1c=IR*74~zC>G1paw~h4Z-@n$;S&G= diff --git a/android-application/src/main/res/drawable-nodpi/symbol_4.png b/android-application/src/main/res/drawable-nodpi/symbol_4.png deleted file mode 100644 index d14d2760234b046e625205ee5e234be8a0e87c79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 890 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*@$C&U#|bBdpm1NnV8d&-R-hDPlDE5y$fWxxO@SQt5>H=O_9yJjVxlUaI%CfQ zrB`{nIEF+Vemm`?Q?r3UTjtj8u(_)Y9ikL;uI}3R|FNXn5uS|OKK^n){Dl+trA%va zxws;5vD;VEnQ;v6(>L$?-}AJ0*0*Q*^Vdl3GQWSGGlA>F2Mvp=SNe&J2R@54C0t}T z`1_yDW4%RTyqbmI?!Y^IR}>GlWzCLUUUIuH#r<%&r@#S)qLQGD=%|agW^%AtH08Z5 zI$*`I!r+O}@>?PtCoZn@H3`i&d8Fa6`%dBuuH2itF_ZZHm~!@&ne|%~H@&=bZ6QNr z9LqA}pgsYIms)9CiYs+pEF6BSl$=eNV$8r9TbT3LyHM{yTFT^kyeo2f4B0OP^y_u6 z>u_Z7Ty+2TB{ys zEVEAEmUYQoaMKcg?H3Lgm-J4}SC{0vVAjx+vbiwbn_)rF62(~i8zmWn1#AB2ShqTx zpZb_<%c8?LkJVeh_JHVtdF&OeJJcFP4@kd%zJqOsfWzLi|v2@_``Me zUJO55_!P_UO`CeyW_^C=ar*X)>1sT8T^GCk)vsl~5x7)bi*MmGU_`2xxJHzuB$lLF zB^RXvDF!10BLiInb6o@D5F;ZiBLgc_V{HQiD+7b`Hmy@pH00)|WTsW(*03+pRuiZ} v5@bVgep*R+Vo@rCV@iHfs)A>3VtQ&&YGO)d;mK4`hG6h?^>bP0l+XkKV6aZ? diff --git a/android-application/src/main/res/drawable-nodpi/symbol_40.png b/android-application/src/main/res/drawable-nodpi/symbol_40.png deleted file mode 100644 index ae4862eea603126d387424b60ae1d4d50f04616b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1124 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-1?7Plzj!{{Np;#P z_xXpm`)^pj|LpevKkxrP5&wUuoPQAJ(5Kt5*+HR3g&|AYpjC7IIp6+0F7H3Z|NkBL z|F8Z2>p=+%%mj)R{{M0P|4*%8rS<>6I`>~j|Nkfa|4-omzZU=h$p=g~nt#;u|6im3 z|0Mta|KA{Oe*@@5fs!DNU#jVe%%G0EHA#bo8imw$mA z_7YEDSN13D%wnRdt$n%C3=B+-o-U3d5r^MSyB+q*K)_+~0;WYFebXH@1T?R9iC_5t z-#q=2!A_IhO%=B1xN~RSY?-@I_}ITk`WolXZ5Cd1UH!mO&7YBFo(-2jZSG;%d-;<- zM*(Yj`Q?B=yZ6^~*j2PlVPyPuqWaP1ouV>MIz=5%xz_*ucrfbFS>rSwPJ=_YdG(95 z4W3r)b!D*COrNtq;h1T$%AQ{hT>E1~c63eUJ>h-sz6|Tu7WcUICg)ps-FUfv+G(5k zD-BF`*SfyH(@4na(f(Dy7&`a()kA444-N>=V~XXRuh*bg5h!wrp&&+6;wHnIr~2mp z|4X=dC#23>AHQ+Z-1@`3VNT2e6%A_zveMHdSi|`ac)VbGal`)Mn|;g%LL3a@gZgx_c87A74|J%>_Z(>~+8XvS$Q%nS0G z4qx_T-PUqU?~Sm?4IvwblF2Nr+gO+_%D{BKc*zlw2%$p_Gnl-cBm{yN@YlQrvTGk4 z7K`L)JbSl9nCE|ic-K5D!)-0~JGfh|K9tH%U>9_-FFPdX#;{mIVbOwryt0O!PY<82 zyd(PY&wsr-#+F6rofmkY69J}A)e_f;l9a@fRIB8oR3OD*WME{VYhbQxU>ss(WMyPv zWooQ#U|?lnaNeeMDvE~O{FKbJO57UuCE98NHAsSN2+mI{DNig)WpGT%PfAtr%uP&B Y4N6T+sVqF13d;Hnp00i_>zopr0Ap9r#sB~S diff --git a/android-application/src/main/res/drawable-nodpi/symbol_41.png b/android-application/src/main/res/drawable-nodpi/symbol_41.png deleted file mode 100644 index ae17cee73149cf2447bfc00f30324c48f2556187..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 687 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*EhC&U#<69f(n45ADS z|H0@Ts_L0wL7)PlYywyc$Oc+AA1v}7XgknN3=HQP7z7v?_A@ZtXJA+ll=}ZabBZ}o zib1L*$S;^d!9igE`+)NX>kAqh_8Yu^KmUGzLco28goab)R$f3=j7i?^F6z4cE0lp8 z_7YEDSN13D%wnRdt$n%CK%tkOE{-7)hu==U$=75c;QF$OV}-_pYhH|j|NjfC>Tm@+ zFYxV|G%x(wJfBSKtvZL-Hyd2*6h0-fS^O1Kd#Hx_#xHVA@i;6E^p%My7S17?pQdOKX~ICh-3t9Z)q{()CH zn`QYmfgY<)c?2smjCK zE0|`^^;);|j2t)x7$D3!r6B|j-u!8128JvAsbF{QHb SWGW~XF?hQAxvXSB7Odl_>I$&ukOg!l?#dp zF&x_|x@@+fnK7H13QK$>PhXpGUIrf%1MA++lJlmDGBa?1Efqg|P@0i}nTOhJxKMBbT=OPF8YR6x{>hf7^Ib{3z!L1UF*XOl=vjgW#Ii?EiXgjS%WR*9`8lsy*g5=cA%szD-8EeZ|swXMT1b{$=9n{pr)E6ZgN$nk1@v)@f)d{Qv)7 zrTOC*py#Dag8YIR1RN6PH=OT(uTT)M-r#(L!ux{#3F`#{?mP4^%Gv~sFb2jXZ+Dm6 z-E0hNfgJV{PhVH|C+y5(qN=TZxzP*^Ow67xjv*0;-%g5lzGWcMCOEg)>SC1Z!j;=r zC)qHvG3R}bnCiQF(ZyV?yaltL|NZ}ZDI?QmrcCW}8}luS_doB;73SEId3jD>Li&co z$1A2YHLTk6QRju+{0k<&;rFZNybm#L`=|I~V}qfkX!p@&%Mz!XA3XEMB-_C9`r}MH zi}j%q70+ESNIz$~@Z9x--9c7Q{`gJyTRL_qY&CgMR>!bh)NXz1w8D%Fu{Ou#9YYsr zX6o?n>|9>cWMw39_(a3`5?3*u#N)|(HqAQqfvGCV()aoiuMHJ@w#~be#V9>HVug$5 zy*s!1l&3TlsLwuI*C?R$`1QMafBQ}DRMdHFDv$il-X+zp*}_-6^NwIGrvc}b$GX>Y zRbuLE0`!gw7cue74YmLK?Qi>E>&8d7pS+nfRU%i+UqhVz=O5J-3!Z&ex39nW)TvqM z>JPUo`hn8-1)d8feS9kPrn%2G?$~VCiIq<4)a>QWZRN6Vp?JQWH}u3s0s3iwp(^ MPgg&ebxsLQ0P!NIO#lD@ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_43.png b/android-application/src/main/res/drawable-nodpi/symbol_43.png deleted file mode 100644 index f51e0a10f5f607c2d3c36808bcf80747a654727a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1367 zcmZ`(4NMbf82;Kqxk?L16-9{KtwZc^))PfoC(EHN6tvxmWnc@^qd&;6wRTWQD94Zd zNR+OMvH@uUkup)4$j≫_t*P)*0dwm!-|JWD_MQaX;CN>@&v2&Fo3;{mc7)_dd^e zxi(UjE?5-32mm0+P{^{NC!ReB2ijhy{sDABMXAbE06yyoeL@Ap9MdbZlmOJk0YEna z@Fy(MzX0$d4#12K0BIKh%gj9!+cyEgx=LFn$4>*?wF_!Te=)7#tI+S)oW zFaYDRu`y_0gD6I@9mk!ZEr($dnh zvNE&TY_VA2K9C38yr!n6y1Kflsj0TM)@HLg91gG7J2W&@Sy>6GRa8`nM565M>{F*s zm6VidG#YpXP!p(RUS3{qZY~sIVPU~~C3YNMWR^8cwF96ouh&JB1b)V^>+pHKw3$F% zexHBNOJigQj?&&azY8NU^BJ$VgYfx%1m^c)C`qG)jy9ub%=jEV=koe|1WlXgPy!FR zs~du+vkJGS%Z`3jy!suOgjh3_@{pfGI7=f}?mtwn1%S=Zkfo|~FY9$t!2`NmAnk-Z zpffE+bjC(@Wf&5OEdx1-5D_#sJVeAuGrPhQ`8FA23vinp2)0y~_UIBn5Xx&i)YjH^ zFpWNM3sNX#bgZHA4~mNrd@SNh3lcWUnmQ8gNDgq1lO+Ulfc1z|NTYJDtfdJF-^=+? zoQT;c1&Xvptlq#8ZWkzGzXlNp_zE76a$l#>lIThKFss23g&s5!@g8<-<228(oaSXs zMrK$xg&p3`MqjQh>=ym?h8&1@5rO*kU#%tr> zUA2roKR?)4n1CJLZw$Ujs9x*d7%X2YCM9%?V~D+2ovp{fbSULUrs%@+9;xJD^e39T zn46QM>C!q~t^#(@;NW18;MSVPhWP_eZp8PvC(^>du-Cdj;EaayOYhIbnCq{dFs0=E zc0VSy>sp*mfG1v_sdL-+ZSHFi-+i=mC)w}1cy@%Z(Cl0+C@Y(N@GbwAPG|P4F2Bgp zXtmulL@au4Ix$%k69@|1^7F)+jRQ3OBfUH$J_$FFiDU)z*%u(ymLq*<>PLaAe&&|Kc~}FT^S1gpc26H4H~_ZQnV$ zIR9baG$^?J_%A9d@H(*pIWGPo{5=4QggqDT9l5p*ekv=i@?5KdvKpm&ixE1IfG6N< z@T4{PdUZmAGy#_;u3wGgQXKbf+TZ!Ff$}|uVpH}14}3+XyaflAKYPQDJtk`vWif(O h!=6GTmQhX>8MBO(p?dF>5&rD}$dIdKr#I^w{swA562t%i diff --git a/android-application/src/main/res/drawable-nodpi/symbol_44.png b/android-application/src/main/res/drawable-nodpi/symbol_44.png deleted file mode 100644 index ed4685a94e0b07783bb5c2448f9066f37735efff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1000 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP~t;?Plzj!R-C~~JgQp3 z{C__KKI90N1(L`}jp4rp7W7S$>x(4MK3VtUGPXbx4J}iN7W27ABm#ONauJK|To#bq zfL1Gkta~ph1T=GsX7(0^0H8Vl|Nl=4;g}8dvvWz1Uoe9~L&E*@?+XOhJIoJI=-(f3 z|Ghy%!1)G+eusX6{RZ=^U@qWfgJV{PhVH|C+y5(qN=TZxzRxBMo$;Vkch)?C*KS@WFXRZ zd5Z&wLSBcpp2E5X8XO$D04Pl;Nta4jb z^dEivchbd1?vHlZ{EvGabl3D=T$9i6N9|lccR+KrMSRPT+(V29v~?ad$p!=*VcoqT z;l1ctI}M8itZ(kKwl7%F!rkX^&`?jKv1zio&GHEgYz_u9x+`#~rB7JkBoK1C;lUgu zC(#*=K~3|!Kd9;7_uR=P8dE=^NLXvdRn3~cV)qW|x)!kCac)-1aF~Cnb`RqpF*&>X zr`kcxmreFh+#)f_eMWw=O>%C>`;tP&YOd$izD(zLeU`MUy->tEft_1)&ZzW6b9TIW3ZloJK7VvUd60^>)u#5JNMC9x#cD!C{XNHG{0 z7#ZjqnCluChZq@I85vla8fzOESQ!|cw`rYa>QWZRN6Vp?JQWH}u3s0tkvLAz|tDnm{r-UW|o4tPw diff --git a/android-application/src/main/res/drawable-nodpi/symbol_45.png b/android-application/src/main/res/drawable-nodpi/symbol_45.png deleted file mode 100644 index 5a674f8d033a3fd490741321595a156d12ea6696..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 825 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_49.png b/android-application/src/main/res/drawable-nodpi/symbol_49.png deleted file mode 100644 index db6449006d568f565001106d84f73be37d2564cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 920 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}U+wAQ7?N@CZN&T9*#-i&AJ;Rl5T26bpw2P#Knl}j&Rcm6 z>KSGQW(G4EY#MJeST&wxdBuL=r3%ZoX3n1rj*Aysy}tMNC_@Dp==4~>wmZgr=;m6v z2@BtJD~C*&U-nkf=krN*sr>a^jb`%O4h6h>>Upl)Ygy11k-k|6z)Sk#xp0XH7yefZVq{>Sm`7UNsH%V%9)ZaZSFL@3Njw!DdR=e(bA@O|1({~Nrw?14wr8&QpX@Ae&9oYeYyUj0^ zxIbWGdiRivL9y&wLS#9Ml*rwhfRIOx#%dx953IY+T_(hpb#S4eNuxva{JxdTZFD7g z6(o8NuxfVfO3?aXzvcW2o!qG{LcB+AvSdhy_dc?fK2n(<&Us7FUPuAeNxKQE9u;66KxUxUL@ zr{(gFjP;$WB3p#~5z_oQE1z?7+4;u=wsl30>zm0Xkxq!^40j0|)Q%ykWnLyU~9j0~(yjkOI7tPBj! z+q6za(U6;;l9^VCTf@FYTTP$_NstY}`DrEPiAAXljw$&`sS2LCiRr09sfj6-g(p)% P*@eN=)z4*}Q$iB}Me1sn diff --git a/android-application/src/main/res/drawable-nodpi/symbol_5.png b/android-application/src/main/res/drawable-nodpi/symbol_5.png deleted file mode 100644 index e64a46c7ef7b4ef91205be9995ba6e26a3261e73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 816 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$D_NC&U#&<=n_(-04Q$_2_1=lVSSCC`5dqGxTmu>H6$-Xw>|NsC0()z9n zw1dAS$S;^dAt1q^f4{)|^9A=E-Z!YS9i0l4VodUOcTw1!ZQB6ku$OrHy0SlEXBHDx z`P3PE7AW22>Eaj?aro`j+eOU^0&TuIw`RzNn6Q}~{9b=rODc8xWvBdGGyj$Ie6Bt4 zt}pFoeO)cz@jp-1|E!$z>DRO~^S!4kUET2MWLvMlNk+{i#t)oqN8F`(>@FodT+9<@ zcj&=`lWgk#CKVNv4xSd~VYJIQP-CikjN!*D)3siQvlcOaxW4Z0rMn(%2ku7+_!&g} z=;OYqZ_at2@k4Xdkxyj{V-{K+`1SokfZ6&P`^6`Oi@*5(RaQ@z?Mi*=6Xm2udKtxa z2lw(Uxxn&1<9t!7_m+CGdqKJprvuj-#+N8^9x0x(MDawq<3tsUH%-d7X0_+@aQanA z7w=FnUmz5`!?mETnT7Xp%@VWSXG9d_B(>IZoZseU-_K)wF}L@z8?TOyNzCoPe5U4I z8BZ5BK7QY*SMb5?@T{~etbTG*N6wv|mC3}<&&#}D|G2;WwDu{=t;atb%-G+`kbfpc z@-#aS%e`!ck8;ct%cV~2IV^B6nm2IIQGt`vZ5eWsLKO)fk4&AF_DfFssq=frKa2VC zFaO*>VP2S!`FYod8`;2!QY~?fC`m~yNwrEYN(E93Mg~R(x(4RD2F4*qMpi}!R;I?< z1_o9J2Ip;BLD7uRkei>9nO2Eg!@fjYO`rxzkPX54X(i=}MX3yqDfvmM3ZA)%>8U}f Wi7AzZCsRSmn8DN4&t;ucLK6UF@+Rg0 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_50.png b/android-application/src/main/res/drawable-nodpi/symbol_50.png deleted file mode 100644 index 1e3514ef7c1f0e83f73ec8ccbb575fc21c219857..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1090 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 T;0KRC77dshS>Q`>E)o9$Q>UK2 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_52.png b/android-application/src/main/res/drawable-nodpi/symbol_52.png deleted file mode 100644 index 67e85f83978bd09ecd874ac0e094cd467ca11a59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1216 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#N0|R48fKP}kP(i340p#bw zprgSERAy=*;qAg4m0du#4x{; zVe3qWFJ~AM!WhybMAl4Xf3~05)q%lKml5bM2Wv*47l1%Uig9WK$hC^{jBKo|BEo{w zQsM#ve4Lydygc0O>`Vck3};re1D$GYq+_73nH0+J=wO+Vo?KI1866cG65^Miz}w&7 zw|Md5{JiYM#F#mA=1iM5)!ogZw6w_2*S)E!p|i97|NsAtjf)op!`-AL$S;^dV1Gix zdx!J)=NB04Pgwu{e8c|v@7FiHzkh!H`uFo2_6HceU+++Get*A%g1~%*{`Cpx0~DBN zm*xTWGbVYvyHxvM+WH5`VK4FYb!C6T&MYRX+S->J4U~T3>Eaj?aro`jm%*1EL=HG- zdM#|ynC`&BvSrF8rd>BD72F75l{%>PRD<{X$16o1UY7r>$}X4iI14eQvdua9-uYhp z_j~%gXW!*LyaNbqw6$zbSWZ=A((jiQ{yc-@hTwCigDww*J(H#wEpzWJ>^a`Mu_GW= zX@T*K1vS?eAJf<>fs$+&0C#&}C z>oQ`A_-A%nxxUo*!84ILLAU&i3kCPCFx7d)JVDhgU>Za6Ni= ztzXBU6D9EvYR>bSli8r5#MSc10`^jHhbc-ZQ zlJ%2s{Cthov$u+*thUa$C|EG}pPp95^=p5(tGLU^tX?&%T}~yMGiYy2pV-_3zc0nT zOFEf5`^m}2%yTA8iE2oge?+%k%5(|v9^JMm4U%|o7Sl)8glbfGSez?YuJ})s|nN~39=zLKdq!Z ou_%?nF(p4KRlzeiF+DXXH8G{K@MJ2mSYcrBboFyt=akR{04u1tZ~y=R diff --git a/android-application/src/main/res/drawable-nodpi/symbol_53.png b/android-application/src/main/res/drawable-nodpi/symbol_53.png deleted file mode 100644 index 0b8332cb4e9bd69c75160f7c9e14adb43898f37c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1947 zcmZ`)dpy$%8~=^mmP!Lxskm_=_Ve5P~fV;-u=^=+1d+Sng}M9Rn)UF0 zv7qQE7Swa{>~r#|;c`CW+&?l#r#{&3pwJbluP_m{=-P z1xr@N!`_oEn%sYQLJckyX^TJJ51=%=W$8}4-1p@9TJ6qDJMZ)i{!W_fdN5Q*E%Fot_|-+|?4!MAiqh+T^&&;(;$_F&9KzT@{KQ2nmT zpaa>vqK~HS#o0H$RC2>dO~eg2mt7Ogv6xZ|gtKziXTPmxuqjA}lL8uj7@T{Cf%r2a z#1ojU0^K_T!EqWv$1I7ofoY3@OG*H$7aV0g($LABWIS$P25ArH`BvNi;cVJuQ~j<< zw~lFsGd^wdj;kGr>8MPPW{;0OqgR{^vT(+oOCK9|;>4$9lgYs!y&` zAegTyB^gum=gwtOw)>ZIwemxoAGO`7%W`Bt^@w}5yEyM{+dkCHZa8>S7?J|}t;WA? zF+ZGZ61}Z%TVsq6>bM}^q%yB1%Z1h;T5F=O=J>>y(X#A-yClX}aX>Mp0MU)G4jYCV z;|g(j(UNtHG2ZtUiOdwd4?WmmIeY|mym?SSY~T()&41H(F@z zF&XjeUu@LdIgj;Fybt)4yb_n`UY}*gmRmuzeA2Yck349Txz$`FKXQ0F;2`}GVi{oO z63Amdoep|Qe$DzMA>S{pQ{4NZ5Cw5w7s>p>X|3ed&`k4_c$CThjI7ok%xb8Ia&_CT~iSEnzQ{U9X<0U0l^6h~W)BVfJIVwaxB9IMwaso$62pM@XPB)yo z+vG!qC$dx=n~u$k8uRJYjJen3u~d1hRQ1e=r0m!7@x1!EKa*Iv@<1fbUz3mVG(~HQ z<(Ur)sd)UyFNMFXu1Z%YzNOEM3<*0b>BoJtR%zpiE#o?yNo(JiPSqsEUOtXmd&8JL zt8Y}C#Sgh%HYRWlLP;{Mrz>>~;RWKBey`~*DZ|Uw^)enjFI*Y%S&JV@TU)$qsCIExRpm(5McA&9= z7>pYR?dFU{qS0<>^egw=(*F@8&?&LeY5!mFB;pr)wZLM1LjXNGIVB>A3g9U8NGgJu b5OIR)PmQ3YFlu diff --git a/android-application/src/main/res/drawable-nodpi/symbol_54.png b/android-application/src/main/res/drawable-nodpi/symbol_54.png deleted file mode 100644 index 27c9a4f69c04520cc009c32e0c2e45e389cdfe40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 985 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$D_NC&U#gaQJV zG&JljDA<~iu=fA|{|X8{4i0nn@4t8d{`>y^qwCjSGccHP{`|A~^UuA1|6M?!`A4g? z7SIxbk|4ie1_OtN1ObJD{rBewyg%Q+KIw^*9Z-%j$=lsU^y!VCi-8>W5>H=O_9yJj zVxp?8eYw#L3`|CzE{-7)hu?-}Pi`{cadC)in&xgRAn^bH`aMgQ1}xRRID03*`F7)5 zJR5H331!&6m#>#$w|8jy_mR0sL_NoK*4%rG+pVIN&MO)HonoZiAryEh=LGYqFP6m$ zH_xUYxO0L(ukP5l2Vpm!?-q4pk{4NX^n+*3F)r@^GlW=YES;6EHQz8in>T z#{ZjH4azodO^6Jg%8@0i6FzUF?ou7c!?g-zS+;wgOFKi@zlv%mx=Fa%eVt=3(foh+ zjt)DmsS?gYVyQoQQq~C_R4KaDeJ80Y@72x&Y8M`-JlJz+{(}Qna>8jWHKqK~>N-rO z(|FVLJ9JIChYM{@n$>wh+&WK>h=r&Ofz=o zsGT|XCo9ozSN8JR6>nYMHupT0n)JgSUC_bq;Q6DBm<8x=)fbRKe`? z-j0k%k8V2LzR!K!va{%r#+>JCYFm?@&nY`qf2`ehUBSom)g|TL%j{bDpPI}!^5`cSs58vnHp;w7+4t?oVRJ6ilQMmKP5A*61RqZiMEmdKI;Vst04k(}g#Z8m diff --git a/android-application/src/main/res/drawable-nodpi/symbol_55.png b/android-application/src/main/res/drawable-nodpi/symbol_55.png deleted file mode 100644 index 703743088d9e8d9d3f2341b0d2edfa30748e98c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1264 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 P5-NkItDnm{r-UW|4s;`$ diff --git a/android-application/src/main/res/drawable-nodpi/symbol_59.png b/android-application/src/main/res/drawable-nodpi/symbol_59.png deleted file mode 100644 index 601783337be9681b8d5220569e37746d9b041caa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 825 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 P?++}^ZOv*;d{X`k1=Hib diff --git a/android-application/src/main/res/drawable-nodpi/symbol_60.png b/android-application/src/main/res/drawable-nodpi/symbol_60.png deleted file mode 100644 index 2e81ceca0db5faab19dfc10478c330f88ee9b6d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2865 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 BLr4Gs diff --git a/android-application/src/main/res/drawable-nodpi/symbol_61.png b/android-application/src/main/res/drawable-nodpi/symbol_61.png deleted file mode 100644 index 47d4e85aa7b28f923e9120b7ea44bfebd3368ca7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3157 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 plV1Ry=m_W#yly*67)1d diff --git a/android-application/src/main/res/drawable-nodpi/symbol_62.png b/android-application/src/main/res/drawable-nodpi/symbol_62.png deleted file mode 100644 index c61c55f081a4bdcce926117a4571ad33167cb730..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1042 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$D_NC&U#nA%Jy_|42d}WHvHnGRR%n)nhTnQ0v0Uj`2TeB0&6=BL z&rNJQb9tNWf0ygtadqP8X!TfBVq8_<@$hWlZru+d2QF>Wc)spkQ#O~_KZg5nx5Q6> z#}a3~e(C&!U8?(!{Fbz+kas?JsJcYJ#^%8EV>ZPf1+1gBQt}wi-VEfF=NGUNy3te~ zs?@k?)hce^_^IJnpDbcO`=`G9ooK?!rXYv1*zlx~^>fxOt$2E8!I7D6!j~ErPid9f zv-;%f&Pxq$);|;tTN%^kPFe0$IdW4jQQ~SWkLa=cSDwo*kn=s^QUDhpipC(vIu0nv0(N7{bi# zEBGy~Y?;rFTRW~!Qrw~bKJV2cFYiMcnk(nt=Tx%Q%4Bs}nH$2eSnQ}+!78DdlOHtA zvVAlER@S;TE`K=cm~@^bZ^(>EKfA?Ywd4aW=l@zQTR1(GB(n7x#e}#GrXT9C^GvX+ za@;W6O?1sAU4xALhMgRnOndjdd0Nspd7JFhm?Kg3a|7B>-DKbC*>h=+zv|r3_g}wt zKKE3f-#%&QgbnSb9Jy6mN!eTp`=;Hk5&cyj~rbJKSZ0~pFElP!9Mc3cKYZ1{<|~& zzT)Ta(>bz?y?%rBzQQ?+3WVq6#Jl{Mt=f4`^ZWEe^Z)Mu#(dy^@A9S6DWL48TH+c} zl9E`GYL#4+3Zxi}42%qP4a{{7j6;l!tc(n-OpUb-46FX AivR!s diff --git a/android-application/src/main/res/drawable-nodpi/symbol_63.png b/android-application/src/main/res/drawable-nodpi/symbol_63.png deleted file mode 100644 index 7da08ba56461a7a683a636626d855136c8cca6e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 922 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-07fPlzj!W{~}c4~gvr zsR06@GM*#|6G{R_kb&f72Ei#%qgWIfcrt;KRoDOnv!sQE1+olC7k3QEFzM$Eta?DH zqN1XZkPvx!c?M2j4i1j&>}+vyaWyry|Ns9_c@V1rRH<7M?NMQuIx|PnZ-m^Tl;dOfzqv>E{-7)hu>biS=MAA!1iDR%k)KSxtDUsn%uf-DE0Q& zKmKbQt}tlT5w@%+Dtfr{mvL&;)BUO^g%p#4UVdjITg$@S;JQ$e|G6ysIwDzsM z!0Nn^y^ZNFH5?+FL=GvubZ0sx^uXq|JJZu%55Fn? zQVhY-f_fgp4KZ2{+r%Rr<|^OFQ+D_)*xA75_5X_F0p?kAJ6hQq#9y|s9r%&8Sa99N zhVwtelykOuJW$(bb!~xg!GV@=EGp1cFAWh(LZj4VbQI(^Ta{+DNGAJx&rE+SGb!>5_xbjC`Dd$V@+7a^c}g@Re@3m( z71i8Zf6DhUblU9vtmSWd2^dGJC9V-ADTyViR>?)FK#IZ0z{o(?z+BhBIK;@v%E-XV z)L7fVz{-L1;Fyx1l&avFo0y&& Yl$w}QS$HxPlwlY=UHx3vIVCg!0CE&MJ^%m! diff --git a/android-application/src/main/res/drawable-nodpi/symbol_64.png b/android-application/src/main/res/drawable-nodpi/symbol_64.png deleted file mode 100644 index bd7e147abd342957947fa79ddf0661ac6f1f8bcf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 855 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 GiTMwoDFJ%` diff --git a/android-application/src/main/res/drawable-nodpi/symbol_66.png b/android-application/src/main/res/drawable-nodpi/symbol_66.png deleted file mode 100644 index 4e0569f17b4a454e71d7030ef9123049b3649b1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 749 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP+~%WPlzj!hJgR5fMFs7 zL;%8obAf_DHUz=h4JR7*KiLmaBQsYqFX%7mU%!9<`S+`m#e0Fu8I!!-U6=)Vd_Dm=>?NMQuIx|PnZ-m^ zTl;dOfzoWAE{-7)hu>a59dyV+p!MOwlO7xr4th*+4hO>mKK#9ZPAhUkz|5DY7oOrx z|6jlQ-j?F)v3a^*^Ijc@+I#J2E@%(smBf8PiOofHx?QcP*kSghbIaR^|Z*>psxFy|CWTeXS;cFc4kM^qdtcNPs zvmAP}C!A@nrK7_{VHO>!D&7FIuUrduPG|l%QQ?5SAWKVnQ$vM5OB@IDv=+wIf^2)1 zRWW{;_NMZ|`2j>F0!uX<@pAP^7Nwvf^q9i4;B-JXpC>2OC7#SED z=o*;o8W@Kd8Ce+_SeY7Y8yHv_7@W6hor08-nxGO3D+9 lQW+dm@{>{(JaZG%Q-e|yQz{Ejrh?KSgQu&X%Q~loCIAbDDwF^K diff --git a/android-application/src/main/res/drawable-nodpi/symbol_67.png b/android-application/src/main/res/drawable-nodpi/symbol_67.png deleted file mode 100644 index 49f9246717b669bcce7c872274e3bbe1aeb805e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 722 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*otC&U#qlDE5y=Be$iDnJfPIVug_y~Dc}#dHU3+5%`?gI-GIAEPKk#62*0$Y{t<`v8zjosl z`zasdzN9o)&5zgL8U1tl%#iQ%-V`u;Zndq_YFM{n)wcWVe^|7%{%x|i6|s6%Dp_E2 z^6lm0_Y05BsEIL<{kn@sL-O(*X7LZ)jHfI&a0e7H>OIhBI=7UsnStd#_l_wR>wFp6 zYLpLrJbs5^uKDq2%hcsx0Ygi*#5JNMC9x#cD!C{XNHG{07#ZjqnCluChZq@I85vla z8fzOESQ!|cw`rYa>QWZRN6Vp?J XQWH}u3s0tk5*mZ2tDnm{r-UW|Ob+ln diff --git a/android-application/src/main/res/drawable-nodpi/symbol_68.png b/android-application/src/main/res/drawable-nodpi/symbol_68.png deleted file mode 100644 index c5ff4abef1e000a5e2a3509966574572b426a18d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3567 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_7.png b/android-application/src/main/res/drawable-nodpi/symbol_7.png deleted file mode 100644 index 385dd85dfb7f201cbab3b33dd95880691768ab63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1918 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 F^FM9pXBPkf diff --git a/android-application/src/main/res/drawable-nodpi/symbol_71.png b/android-application/src/main/res/drawable-nodpi/symbol_71.png deleted file mode 100644 index ccf8127ccb896167a23078d3b6fcd57279258a56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 429 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lu!)t32_C|3=AhBNI~I3 zL&FmXhwK0U|382J>;C*m zy~NYkmHi1jvzVxAYhP|OP$<;X#WBR=cyfXSYY0n|1w%}uA)mnuksWPqZC1`l9{Px| zzI^)h=}7_Bf@dq59M>!;R+HHBIHZAvZGF?yg$WyK0@%Nt)x7$D3!r6B|j-u!8128JvAsbF{QHb SWGW~O89ZJ6T-G@yGywpcP=m|> diff --git a/android-application/src/main/res/drawable-nodpi/symbol_72.png b/android-application/src/main/res/drawable-nodpi/symbol_72.png deleted file mode 100644 index 80616a53a688d1a0f609a3b0733689de2365be5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1442 zcma)6eKgZ+9DgK3yVdF<9Oc&%OV{yhT554@VYaY4^Ky`!ZMKr~K0~6BRF`X-^dd9# z;^xK($*iV#x@q!KTrazsdr2hpLdEW{e>$f>I;ZD+p6}=Re9!mu{hsrj^E@XQbdRM= z%$EQFmeQzhOoT~awt+4ZB@OB02rb@A_9g>RBSL>>>meEnqcXh#IA{%kFcW}}NJ=;g zKmrWF7z+U6SpZhW6v=&@0MNlRy!_me0&w2t$FaYdXzr~+O=A3nL$+z za%m2HCfyg1VuX+q!+yPF}?gBv9kmg4A3%omVYF}ap$tcSP?MdBP zpDpn5{Ebsc3YSDMA#?DUcLAA&06qAl&#UT zqAM;r>!uoRkn~yXVaAC|kavjeURpX%^O-vv?xJfc zO}ki4=kDALzAq#k&J5Gdv;NP<_<&ay*BZFIBwS&| z->25Q6^Ft1N8p}XBqs~!1GrwC9_p-lX>t@>dpBI*^*lbHEIBH87;+;%t_7e{_zUOa zF)$qTq}Dzz59{o8#iP^Nt9i*&o5ulcly%&6BE1fX?FQ0PHD_5e#O{* zg%uSkGXrv;`V+b4ZKr3%Aha>PD4;2m(Cl4;XerA7HYJaNtkQ&px%dsr<)mcif zzpF^+xOR8Lh}@=p>w9ON8@^+XA}5L+^JK0Ifz|@jNGbMmsSUYVj zj=S7VTeMkm`>Ao`Ic3l>^;0#pqP=*Lseo~0y8_Cz98H|>lt|LeP~o$l52qgJmn*B& zMB<6i<=8(u}-t1fa#%AUfxggj_o*j-gXx;BP7GSGh8qF_uF5r26L!5F4? z6Yl18#j^@WgZslaJ!DW{?$#Cr90tMbTsyF;3vzA;2bbNB5@{=VTB+j#?GF#9sWH+m00ksZeaWNtKv e2hk$gdwEPAo0}Zl%0oU*0BG)Xx2heijQ;^0j*pN4 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_73.png b/android-application/src/main/res/drawable-nodpi/symbol_73.png deleted file mode 100644 index ed3aaf8f12d06eb583aa882179d7f7a972a0e1e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1184 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#N0|TQ=fKP}kPytsUu?VOb z8L-S|fFSm2WML?q#gBn?B2)oT84&n$Z~zfRi?M-$rMY=vU|@ie5kwrw#sz>b1Omnli0hlPc;x3@1|yja;yVeZ_yO-)VePSP$; zPBUiASg~S-hr7Fbl)H1hQ+av0FfT9PB(9>OqTb%#Ns}g}r>Don#QgvN|Lft?zk%*E zFA4GsW)N^FXh=}FAF$ux{QCF(4eR#@C^$3(6wG(HFHrFQ{QLX+=l3`4FL+;&;85UT zVDMgGzQX;6^93J|{i*^Q!IOoOmb4X(capoTvEeOi=&T$tJ|bmg!+9t0d)P zVs9g~Z;7ADtPDGIwxUP){M~y#y=a%2ljPyOdV7VXURTC_FHe|Ka`^1_>1sc+ z&m8TU$vR(pndQ%{OD4Yic-x|RHm%ImCDRd3}$so~v<$^VsfZ8=F$~+ss$5 z=67n^{*)_wV_0l>|Jv~DfBcs2ImpVNda!N(zMWgQzLeiC`uP1l<88uI>|9tvkClBt zaP#(4^MwLA-b?!h9b4ZjC(Ji&bF485%w)ad8pfV>wdsMDdxI!vZcN7;rhvbte7BaWy~(g(pTp*FzWh)A?x`}; z8D>(x2j+!yJ=6C-H}yi4!2FKf%q*SgDPmSr=Nwf{$h>%Qm!g;c?&(25@UPcC+UnMH zIonsj{L7$P;u=wsl30>zm0Xkxq!^40j0|)Q%ykWnLyU~9j0~(yjkOI7tPBj!+q6za z(U6;;l9^VCTf@FYTTP$_NstY}`DrEPiAAXljw$&`sS2LCiRr09sfj6-g(p*i#Rda| Mr>mdKI;Vst04!vja{vGU diff --git a/android-application/src/main/res/drawable-nodpi/symbol_74.png b/android-application/src/main/res/drawable-nodpi/symbol_74.png deleted file mode 100644 index b464cc65203210ce65e03821ba5bb9f8b9d232a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1351 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_77.png b/android-application/src/main/res/drawable-nodpi/symbol_77.png deleted file mode 100644 index e10eb3e38f85d5bf67e9f8bd51e43d51267fe7be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1214 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-07fPlzj!CKbra%34`j zX=`hzrl!uDH}B-hlh2+#yK&>j+O=zoi;Kg;!glZ8&Bw>*;o;HP*f?Rr1THQv0|NtJ zU*F8kOlN0jVPRo4HMN;DXV%ozSXx^4_xC3xB($}))zqvB3p?iPd#1Q}bASJQHMM69 z4F83NKgr6z;o|z)*0#*j@}_~o{r~^}TPxXn0v#<-666=mVBjDS(7*ru`~-#d_un@Z z+z_tV3Y23^@^*Kzw&eSg1LUxmc>21sKVfGU6IE^P%Z+AWU^?dM;usQf_-)wjq(ue- zqO7di92(nQTvlgay;Ziobp8MTiPoHooGKi5m)Cx<$vk6uPS@C2;!dHvdC$XwAN^M* zX7<*$b-wkn_cWLP!=`p_h5g-`p<5Jq#IL4bf30aaXUd&a5p|KwHZRfZZw`Nd5xd7L zt0T~_Pu{9m;^K*i7J(CjI%i%ysQyeptW)gctR0CZp9*JfS@ zalNugo41Ik+FFOiYhouYKTP}}@qAC$H9`A654|scR&twHo+;cb;F{nmbHQ z-?#Vgw!Kwr8Nitr&Ec29Eua@VEsx`IW_^mq+|0s|eFxLsl@or~X?)!NL*t={2bV|o zA(6ZkrAxOjZ)|(+kfL$6RLy})?9fTI{UIkJTa#mz)b_M=Fuz#wpz`$Gh=aXpx;+ni zULL+|D{s1^L%VU7=j3XKC-GXBUf;f+AM@})FN^%1wua+xnqt}kheHzf>qPA9r^d%0Fbhl1QaWzaIYD_^({}B{`45>_XH3WvZMc8qZ@<@r zQ+)HDc>mw%u;ADOe&HMU`W&yEIaHl3mK1v65&yq5*%q7LvsN=c=UrJY^w9rJTLWXh z?#sVo2@YpwufO=zQDJ@I`cF%*&p5=pbo=c^k4wHa_pVc&xoGJzS=mmDOiiZdnHhT~ zUJ}0O_^NXPbNuFw6+z+4V=Y(6r7qSM7B5|#`oydJN6dlgcX!U=u1TA8a?#yAGMNS% zlQo}A?sPdJm%;dSPWROXX41xWbDUW2PJ8Lq_Sh+oZxho)Q>U3VZPD(@Gf(Ym;ySdQ zZEZoGj>VNa4~J-m3fo_mSB}NA#{Rj)Rxg|VU+(AKnvQ1g9)~WMs0&LfVrx#g?o3{9 zUSzV^X!+*4)zw?I^b_`<+Qg%KI4km<>vYwWFZZ^3ON99z-dg?kW^clbd8TYP=4IB* zt97sc!@8~KSjowQ7HPmlu3F+6QIe8al4_M)lnSI6j0}tnbPddP4U9vKjI4|dtW1ry z4GgRd49?rMPDRm>o1c=IR*74~zC>G1paw~h4Z-wQ+%04AmcCZ@^Ed~?4kU1`S_h7&5bGgGVALsH;*4(5gxkm2~&(EVm^TaPDY=7?F zp&Q1qq0CxR<^8^fp6PmQzYmog#e96r8}d)4zb!oT1^@0(68V=5%#3{Gynl$XWy!CK zH$S|f%iQF|r|=JMZE>>v4<;rC#s8C%OVCvJSdxjelDk*P8|W zoV#6Z&!q)F%9-V^2paFTTjPF2zqg{{>Z5N9mV7gO*4hxSbn%^$!@&hH z2U`0W*b`mW-%*!5&l_N{ThQRE>JwH)yQIEJ5{mX>N&d{bFGN}8I3F>)GTEK`=U}87 zt#Ble*J;i(v0{UBEH<}`R(w-*t!~)c@#K-PVo*&^7t`}9)){LS3uvYOSl!9CSwp<$ zSmFKIn6mN_bnRAA2hEwHA;j^a;2AY%Hgi? ziv@4x&&^pL9bX@Ld&=^}SfR7~pWPRl^Ka^dy&(@~a+@t>+I)KMAzjfe-SXlawl)3i zeQo>z40H|5bq$O| zjEt;|46ICzwG9lc3=GcOv`$6Qkei>9nO2Eg!@fjYO`rxzkPX54X(i=}MX3yqDfvmM e3ZA)%>8U}fi7AzZCsRSWlEKr}&t;ucLK6TB@OwT0 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_79.png b/android-application/src/main/res/drawable-nodpi/symbol_79.png deleted file mode 100644 index d56d33d46597ec64b936b47fbcbdc0049d893999..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3510 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_8.png b/android-application/src/main/res/drawable-nodpi/symbol_8.png deleted file mode 100644 index 44a2f1ff2597e34fcc27fedaf0df8f96606b4d8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 855 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$E3QC&U#<|0e>xfB%2~ z{{QFC{}&MW57gn{@V}toe?!CngoOVF2LJEh|F59%KOo@${Q3Xaum9iQ|Nnu^tA3!- zJS9PX!3+xX-x~-Ntl!^|;J}c$J`pI+nB?v5!uX#__a2bLUgGKN%Kn6%Sxi*rQ)ld1 zp!5Mx7srr@!*8dboYt%$;Cj|Zw27lh<^TV=ydFYx98{L?7O#{JFI_9C(Y1bGRrcn) zj!k8^eec)JPstOkzW;B*+rXI$OE}s23s?>;@e(-5;Lcybv_SJ)s4JtN+yfqif1YP6 z4rn(NOI&zi;CSLILt=64I<|oDwK)wj+!N;7o;u4I&#$r7GSB!_M4QnMZH8~041a?e z&a=)4TeEVq51WAB-@iwL7)_gW8jMuWFlZDo9GsIO)KHo%5u>i?ko;EKxX)>?_|LgI ztW)Oh{mb^rfO`Yqg)ANiZpQxfH(3=kKBh8!e*95x<=Lu8wi%H}lPshZ4}^T};nrez zxR7wXogpblKiBW36GPAW5TDtOs_BdstGHa+Lw9*iT3Y+SyPy53*^Y1TektDTtYe#? z*;v3E+QxV-^y2BJo#$WtxVc$1RU#qwL%z?oxbTLE?7+z#?0NEgtmb#A2Qmh&f3QfJ z^T^^{m9>TDUB_}?-k-V1dZYTC9xLTtQ)^dt-i~?_GvQV54u83Ti<3LIoLO_|_?=io zu8xRdP`(kYX@0Ff!0JFxNFO4ly#aGBU6-HP$vT zure?>Z__#zMMG|WN@iLmZVmeqZ8d=!BtbR==ckpFCl;kLIHu$$r7C#lCZ?wbr6#6S T7M@H6rFI5SS3j3^P6j`EU diff --git a/android-application/src/main/res/drawable-nodpi/symbol_80.png b/android-application/src/main/res/drawable-nodpi/symbol_80.png deleted file mode 100644 index ec13176c788f92a0808083975d0cf791c8a7f7e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}w87KGF(l*O+i4qln+*h9>jgqr@i_RN<;ZdFoxvPv%>Ht- zQ`W03d6y?KGL?&Mdg4;mfA0V7I-|3mK)o|}O59wc_A++wy!+itH!cjE9r9q?_6U`| zk64z5&zQSsa!9s;b-8YP-_adF@(dWbOEH&w&R| z<}T@)$OBa*@FShETuDlquhMdDLdv=WQi>n?vffVqE6%`B!_fW0QugWTNk%~XRZCnW zN>UO_QmvAUQh^kMk%5tcu7SC(fpLhDk(H5wm8r3|fq|8Q!Fik3sVEw9^HVa@DsgMr zmuRaA)F276Aviy+q&%@GmBBG3KPgqgGdD3kH7GSPrLyp3DkzK@JYD@<);T3K0RZ+y Bl{)|c diff --git a/android-application/src/main/res/drawable-nodpi/symbol_81.png b/android-application/src/main/res/drawable-nodpi/symbol_81.png deleted file mode 100644 index be72fcb79877ead99c2b3ecfb16982adf27a6f88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3278 zcmZ`+X*AT2_x=poMyM>4b;vr_u@xhXi7X-eE@l|}GS)0(3l&0|EK!IgLe^v%OGr$z z6Jn&qh%DK+`T4&5zxbcKJm=nfp7XrA=iHlQVyw#o<^cl$z@o3GZFYvp|ALYJESGx* z%$>nGcP%3=0H{f4K1S1>)q*a1W<~%IAqD`k2>@_-){0#QfDkwUtT+PzA_o89x?Ni8h?k_@iPuIu?YwHKZ-L@l?qO!Rn zw^rzwhnm;6<)O>ko1Z)q{{6~_OVg$&F>6hKz?{>jJ(h=iQ>H!R$ny9Y5B`(4SnA5B zWnX!Zt>IWrlVHyGHsQB#8(vI)+rViBoHLd+r+B4r8)Ug0f@Zuj8o4erJgO`HYF<<7 zl>S#t7{KK@j5J)fTt(<5w^sON&(UwBwz7@)8eAK3gk?!~P=krdycm#&Q=cP+-jw{~ zw#8$>y6gJXeSxO*k$TIYlM3 zm^Qa2$GX(|KE(GH#BQ=!I(RO}=8D9Ri7NvSZ>BKq6kR#)vy2b&GyPg(eYpQhf>k%a zsdZHel>jqd;uF;GnQKqm>!msRD}!j z?iRyO-Iz1_vbp2F-pp<|B7ZTHgJqdrV1W-1KJGbqRlNX(I?P!s*;jG5-lGck=A|rXfqi3sGvTjoo(0PX5AYb zuR(giJg)JTEXx()T4a6epm~kId5!qE!hsEdz6yP(sv`Fw4anrI|5lUywc+#a^38mw z$I0rpJ#$VycOb}oP=^e)bdt2kvG@d61h^sT##;F%t;G*`i(Ff5RZKC zlqcvgi|S?3t6)Y5Fwx!k5Vvl0`-h*ixN{a>&-rNbc63)+jqK2yhpq14#azp1M3^-M=}Ps$p{>yvr80QG89HmY?EWbLywv`I>}jt4k| zKo6CYBJ7RcZYU{>(Z4D#Y4x>s8G&e^3MIg9Q$7ZG`@A>latAlWGIkHVMz(61vaQgl z6!s4?&$Usm#U!quz+)%%LV*e%!1znfW){oD(|B!~1RalI;vasIB`mvaa3l5H-GPHpAbQh zc6lnh)v8j}$pP6L1lzW9oon1T7wlC59r?2YJ+FMj7{z5S@BmPm1!H2&{=jkZ?;KKM zH!!ofuQcUAVFIE#A^YeU%N=)17|RMWH&Rl%zeLxZvJe0yuoG|?l=DqypE-ykh4NL= zO)RPH^jAxx??^?rJyedgKo$TP!+%J|4J1Mu&JT&_Yd_$hNrvQPMcwykM=G@Jxv?Sp zh5T+vCCy@w=|OL_B1#}*arG3bZ|q}nN)PyXJI31UP=nxz%wJQsEBy?W#;nH%x^d0GL=F6_E2K*iAZE=OblP%up3$YVHq# zpRHR$4HjFBVp*z%HYR57Q!`vs%9}nVo{!Mu7RxrIO}UZ|6s|A#Z;kVAXza?#RNGn_ zC>jsnJ&ZS`X}ypj$OxLIxuXvqUCczczS3@9)!yq5}uteB)H+ZW7yG$ zP8tNdf|!m|lFm6!$c5=h!5Q~fk^qu&xyqODLPbyeqXlai>YZ3k>IAFIw%clElg47pXSaxT?Z3A`875KNJ4k6AJ*%Qg8T)2A%%whElVR_(Odv zX9B$X)vmL1-zcNeXt}mUPUlh#oqX^}Z3DI$^`M#_Ly8qp{YE zV+UPVY#KbogG2yp$&@C{IpDr65|fN$uo$GuQYQ}(R98}^GO!O`GzQWqSamU1H4 zsUO9NA5`BLphxLzw^NzUj~s9?(u_5wD+G3-?gW0TnH?_R_fFfiYrKPJ!2J%ZTw>rU zZ8QZW#3rYqrb(I?j@RWrl(i;Y)oA;rJF9!Ku;O}m5vSaxI)6o`2W^_iVrJi zBZH#5P-0w5>*qLl?c9&a!w_L z`UyQ*W~z&{rbckMgBofZxZZF~_Zzar9vCS-V-5YOtQrnrbRT| zzm+)O)vyraF7J<6dA^fSH71DSBX!Mrd4LuFI;w0QzD5#_`ZB;v77>zrP~|2i+St2w zy2|3y+pTXDxtE{m;Xprr9Mno#5ziR8! zw2h^~+4i|Hiw^JAcupWfL3D*piI^)l(o7R^LVE*OuV}YW{a4<5>IiuC&S!dt+mV&$V~hKA73(o76WTnF*o4$wF|| zd4*Wqf@nf$HKx-_<9khVd>+?7e4pr=h^M~1JklF5tWve0VWIC34(TZCs;7h7OHh;_ zhpay6s~PLc}_ z3S>23)|uI|S*p{<8tQ^QmhL&|x=5B}!U}WhC1jqfNG8|+lx?7sy=yx$p->HOoOaUE z%kDBoCTaYQxL26rY4QQIa&8h@_*^;6>%C*j_x5tLl#1s3ys~GxXHK!(j(LXDG8V!4 zSDfAQqQN>g!LI0FEW#xadj^04Tmdcvza|4$v`|n$D8LcQic)Ym0uCR%o|yT62)_QV zo^Ij)KcNk+4m%@o|EFN??-qO)9f$?AT>UXvL49AeJJt+~b`1~c!~XYV0Qx${+Epm$ Gd;bH^>FwVD diff --git a/android-application/src/main/res/drawable-nodpi/symbol_82.png b/android-application/src/main/res/drawable-nodpi/symbol_82.png deleted file mode 100644 index 8170c3418e1c8fc34ef7dbf6e4b69592b4ae03da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 969 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#N0|TRMfKP}kP(fN+TCDek zgpj7Bi0T;ksX%Uo^$H*v=hu}OUK{N^8z>v)I4|0DMwG*X2&RVt0PU!M5$kfR>ha9g23`laac=X3ml9yaUlrtCRf?<)xh{$~)cAce#7% zO`xUCv-VZ?tSoC^lv~-8RnpqIlCUU^GSLD{+U=dWG6 zcKrB>9Xode-SYqcfB$!#X}|z7D+%%oW-w?-aOfAf?@+LQ{rvs&&%ZzKpm4q*VE+C0 z0S@!u&kwl&e!W4!{)GPb`wh-32&_N9zahZEK*6W*f&+HE)g8y{w1D3CdRk=JoXhv|eh3RAkaPH0&-D@wKa@^>Uq<9{&yY$Dd5Ot1;bledf1T z$vf;tmvuffnEbBN?Ws&WC$nQ$*c9nS>k_t?TWWF(KUz?(w1{!l=Sxgm&)gP!FU#LQ zO}*E= z`r4b0%j=)qHt5M)e|_P%=q36Ss_!~D=r`Nm$lJ_PXFX5ujZu2ue)c5ZAJqXpx5U5y zy&v%8AHxwTj<163hioK`@&qkmCW0JSK3+Kn1OF`~rFY)wsWq-oXEGDYj+LsH|z{ud~ z;usQf`0cd2LQM(+t!KMj>sSQu{SRdhaoW3K>71;#V%9SsHtIa@G4l<*>NVZkFPC)= zi^2v$F^Ao~|M(3!|M>knryb$|6ikRYvEjyQqXxMk3m$ET7dCOq&dd=u@eC4@*$&JV z7UjG4aI&LYItta4HGLt(-_pzm0Xkxq!^40j0|)Q%ykWnLyU~9j0~(yjkOI7 ztPBj!+q6za(U6;;l9^VCTf@FYTTP$_NstY}`DrEPiAAXljw$&`sS2LCiRr09sfj6- Tg(p)%DT2Y%)z4*}Q$iB}PI2PV diff --git a/android-application/src/main/res/drawable-nodpi/symbol_84.png b/android-application/src/main/res/drawable-nodpi/symbol_84.png deleted file mode 100644 index 54180da278f16016ffe9807d2e9786f1af6714e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 803 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-0PlPlzj!CKU)V{FjxL zEh;Js3k%cM*0vQ8_~hX5J~Q*llP9ZJufBHe+S=*U-^a(l*uDE6w6qKi z4E+E9fAKk|li^*S$3FpzBe|3CL! z6U)UQi7&b5POoiRci7~r$>dJA#TPUFNgRID__6tb3;&sVu{nR466WsOC@bnH9UWS* zFCiwTE_3;G1<%W0vQF-7GYxCF$W%V%LE4%G&Wd%$?^t;5hl$;}c3FT&{LbBCIl1|p zuI{q+-^-diuTY9z)p6FGV~GnAK2K8d+!iRdC-10s48LfO@yS(RL;0dK?hCHs`gAvL z$#tDjc~-?G3D;A8C4FY7c5+$i6E5)3;bl|&)<fDNNnBTE}>vq&sHsQeutiG=*EenkqKJa=?4_`cY7aQQ9UX0KeLm!j7iBK zfA(qXbM8fI8DIMx^K8pbakgcW8=9?b4llcwY&y4h!Nm-d#g*)n|3RpX?6ckS^j<9me;FSzn;JJjdtE& zg^d5AZvO>L{lbxvP{`P?-t?YVI{@f<4k-g}Wd~M41qlg>tgNh}q9Q{>LrqOh zsqp!{+W(uHnm9N(s;a64Od41P8w3Odm^mFB9UcFQ@^S(-%a;WC1v4bRWs3bpIzTl8i# zM1M=FPJezk&uhZ9tDHds7ZfMIoyd6NtJ!dRg-wXluezm`s7jw;-Qfekx%KgWwpytuZ z!sx^$p-+2*7c61Wy4TcoH-63hM|A^)d(n9kA4{_8@6mo z=q>-Kd-HvCa>QWZRN6Vp?JQWH}u3s0s3vpz8Iy85}Sb4q9e0Ow}F AmH+?% diff --git a/android-application/src/main/res/drawable-nodpi/symbol_86.png b/android-application/src/main/res/drawable-nodpi/symbol_86.png deleted file mode 100644 index 2144d722dc837d1326871e9b76e973f76f014383..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 935 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP-0_%Plzj!W?(o8Lnjy+ zf#^68F*6-wW;)8ka)g!jFdOS3cD4iTYzJ9c4*^A3n2$0s9b*D2V>kiU$e^U86bc4u zzP>4behC2qi6J40p`l3;eu?1$aiO8HK|!&BfoY+k$zWx+d4Gby;s5{t@8AE?-~asm`#Wcz~#S%2qAo!WJp`P`|jD-BWs z%>RrJFfnv+Y~pyTox`5&6BELAU`mi6qnPE*qSK2v*61>DtPr`zpb+?uzB%ku5dnKIxszyz@=1t)|SwDBSav8AGQH^U;GZ z8ERzSR=i>gb-3jr%20pQfz?6c#PS$+hR@>Bk_XnxH*B_J@P7W1@y0)Pv){f<-ogs< zp0V;5Ry7D+1%?8{j{ekHX`63mZMUA=p7(v@_1E8jH#_EA$n?%T_V{^Nwvpju{rDay z-{tE!->k8V*SR+{57M>gTe~DWM4f DI^R#} diff --git a/android-application/src/main/res/drawable-nodpi/symbol_87.png b/android-application/src/main/res/drawable-nodpi/symbol_87.png deleted file mode 100644 index 995df58247f843417a79b5234b22bd0599483958..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2491 zcmV;s2}JgZP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 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 O0ALrCv3#H4rhfng`70d& diff --git a/android-application/src/main/res/drawable-nodpi/symbol_89.png b/android-application/src/main/res/drawable-nodpi/symbol_89.png deleted file mode 100644 index f26946abd1090ebacf06aa52232bb4708c7a7849..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 551 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J(0C&U#<|0fmw|6h48 zs0*l5pd`pIn4uwIzQB2d_XYjy6&&{8517x)SP7J4O!9Vj5qz}Ob{CMtUgGKN%Kn6% zSxi*5wJ$dsD74no#W5t}@Y`#r`3@QIxLn*;c*#k4#{d6OS^^%5`qJJxuOh$CbKUdO zci;toqWHZ1H>65xy%!vL`1zrl02@di*j$f;=uh_Qv9pmwslsDURbPItFS1oak zC`m~yNwrEYN(E93Mg~R(x(4RD2F4*qMpi}!R;I?<1_o9J2Ip;Br=n=c%}>cptHiBg zU!tuhP=h4MhT#0PlJdl&R0hYC{G?O`&)mfH)S%SFl*+=Bsi4?n@O1TaS?83{1OPE1 B!vO#Q diff --git a/android-application/src/main/res/drawable-nodpi/symbol_9.png b/android-application/src/main/res/drawable-nodpi/symbol_9.png deleted file mode 100644 index 2d2dff76665f09fbfcdd4c2259580b28f3c06974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3828 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 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_90.png b/android-application/src/main/res/drawable-nodpi/symbol_90.png deleted file mode 100644 index 002bdf759a98ddc7cddbd5afc47e5de58b9c092f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 705 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP@*NkC&U#<;{pE}7;Xa% zWnh@ezyM?ekpqTmh&Yf;U|pTO)ez1am28IF#h5!Zz0S1Qm z3=H>yvj6`ZdA`Ap<%y)aZYap zP#t5Ex4VnB%FZVoKn{C}r>`sf6Lw}XQPtMI+-RWCTTd6qkch)?r{CmjG7xaRxlm7| zqnc5>>%sr}1x^B|eUb_~_-D)ue>QK+(wUy7z8{NA4sUtGSlJ%_;>n)S=R05XMl(Fm zS#cnUNi~2;wPW&^DMwNcrf6kdiril{yL9I7MTr|z1n#KWPG&y0NVWO?j_#2OC7#SED z=o*;o8W@Kd8Ce+_SeY7Y8yHv_7@W6hor08-nxGO3D+9 lQW+dm@{>{(JaZG%Q-e|yQz{Ejrh?KHgQu&X%Q~loCIA~y;3fb7 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_91.png b/android-application/src/main/res/drawable-nodpi/symbol_91.png deleted file mode 100644 index e962f3411dc387effbcb0a95895321da69150247..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 375 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE<(}6y@pS7?N@C?TwAR4GIEn7vab%ElIb|$-to{Ooo(HT{)?7g1$}EDng{T!{ytau#Xo)bY8#Ov@A(@yoh-e2*K9Ap zh65wl7Zrc|jeI9=vhHiCsH@dGAeeMio`0k0JC7sQladb~cntKTYKdz^NlIc#s#S7P zDv)9@GB7gGH89sTFb**?vNAHTGBwsVFt9Q(IB(NB6-7gCeoAIqC2kG-5^Xhs8YDqB s1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H601tkv#Pgg&ebxsLQ046oj(*OVf diff --git a/android-application/src/main/res/drawable-nodpi/symbol_93.png b/android-application/src/main/res/drawable-nodpi/symbol_93.png deleted file mode 100644 index fc19a49b1a6dfbcd9d26d961104652d439eb47a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 602 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^> z;_2(k{)C-bOjNbCFE^Tjfzj5}#W5t~-rK3S0}mSrxbho|BxpIvE)WW8vQ|)?!RN!e zkomIX3x#(I%b0dEw{sn0_mT13w$$`lbK?1b6>E-9ednbeAmSP*;`;Oboj;%cNSjT6 z-*vSFC$8 zH|kGm{p5f^|GSN!Zu8juH(_kO zyo=ZG$Eu(0cV;Wdzf9K1oc!eXl0|PfeC|4PC+K_NPgc!hUbBh!isN)9r3d~i(t3aO zjb`u}e(iJg#9TvQtms9+~w2N+G4x%8>g3uKE6Y5=?Tk^Wy_iqJ;t!jyD zL`h0wNvc(HQ7VvPFfuSQ&^0jEH82h_GO{u25J;93GxeOP-s}+pRixxy~Fzb^9$~u5121-{``3Z$s4r}KqZVx-tI1HQ5-Y2 z0y*p@p1!W^PuQ8oL{(e+azRGC@N{tui8%ar`fZ^m1%Wn4m!&$V`7$);z4{x!QOERd z?yMs(54F87`~E*gWZFc5!~F}zHvep~nQq!wcJHekQ|3#qBgX6Zvz+GWIl$4gK-A^q z%Q;7WHMy?Jy7aXC?K*}Zt5R9Ln;zNZt7W*aiAxbW6f0o^0QT>xkKcRWs!7|%79#u`;J=PlioaM3i zuHQcSaNkM!FQ2|24iVeAYTeU0&l?3L4%T!02syY>&>)tP^B&&^!5v?7ANu}GRSbDy zf6qWU&v&s)E~DYT8laz5OI#yLQW8s2t&)pUffR$0fsui(fw``Mafp$Tm63s!sj;?! zft7*5d7IX$C>nC}Q!>*kackI@XsZd-APKS|I6tkVJh3R1!7(L2DOJHUH!(dmC^a#q UvhZXoDETmWy85}Sb4q9e0CH^KJpcdz diff --git a/android-application/src/main/res/drawable-nodpi/symbol_95.png b/android-application/src/main/res/drawable-nodpi/symbol_95.png deleted file mode 100644 index ee59829b2f7af145d09bd0e5e8bb96f9ba9eb176..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 907 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J(0C&U#<|BoaQ{r}Hi zZ@vepQ=lZsFPI@=zrp$j2Zez7_xs-$oEHeb-fIk$V@&dPcM*KF)pi$&pIw zomos&wY4udnt_2y(9^{+B;xSfu(y56iagx+nORQ!wts7Bur@5JRQ%n)*zA>4W;Ssj z=~VpnpuTZqgW~e|X*CL6W`gr%1@HauQ&6nfx#)=i(^IF<&Vfo3TXdN&O)O@*sM_ac zt8#$L!j(}+(43u5HQOv9wKZI0y*pDU}mryr^2e(}xgc)GyU1ehYNS@v;Cu4q^9y}vECBVAZA^yqoHL}${924mV9_ z_80swRUI$?%Kcf$c3M)rF}+;><0Sc4#p2OVs)QEUH7s~wuy}*p!A()u`wMw|{~plk zpAomgCuu92uk`;FQ_GL+QM~x!+8nVH(kIVFJb3nbwA8oK|RqV$=23Lk7k1yYviX?0wCvHFKH z(@gDztJWNBpNrVOeCKe>*5l#i<-T6yk!#8Pi{qf1h?t-4UunDV8~N`^)icaV5m~k9 z;!03DS1oakC`m~yNwrEYN(E93Mg~R(x(4RD2F4*qMpi}!R;I?<1_o9J2Ip;Br=n=c z%}>cptHiBgU!tuhP=h4MhT#0PlJdl&R0hYC{G?O`&)mfH)S%SFl*+=Bsh}Lf;OXk; Jvd$@?2>_cPV^RPB diff --git a/android-application/src/main/res/drawable-nodpi/symbol_96.png b/android-application/src/main/res/drawable-nodpi/symbol_96.png deleted file mode 100644 index 9bd41f559108e389ac1b590f6e18adc886586f95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 797 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$DY8C&U#<69Wtk820aH zC@5fXaA5fVpW*#`1_1$vh6V-&1%~07NJwC~f1ly}d4~RehJXN|n*U!jJJWzh z^OOYn1v3Z)yuaU&pfKNIe}O48YZXwOG0EHAMfNpw;Y1*Zy~NYkmHi1jvzVxAYhP|O zP`cUE#W5t}@Z0N&`Ar4_Yzd;GCFT!g@{GR!uYX<@8+7ZQ=&kHc{`=-1XfgNa*mLCW zyQ%dj_I>)rY*H%f-Vl8DYdS;5Eh`3xaMlWQ-l`_XFV3t78Qk{NzTjkWm~(}N+rfKB z#=86FVhNn#z6W3OFHo~+nD&4{t(^5BvqGH~hur}oK2Zj5i)#!z4`Ub|{%ENjVK}m} z;{n6r45JHy@h$}o6WNZ+ruE-0V&B8$eBxd>b45Z-fP=z;Gu-<&b8;(a9B@}V$lStO z3?^MpNSMnvFpKi+5HR|7mHomL2A>Eg4u&5~nwDG7HCD4@xNuo`Pv~u7d8UYi-@?^c z6oMM-_ibG-*dU(cTf?(Jbyu=oBjXECuIW#=S$*U=z#XPOkJ-bfb^n^$R11dZ`}(!Q z)#4aBJpJ}CyioU2TPVu#EwyRJgc(2jn1xtB9oepMhjC{EM}A~ONTbO|C52E0-#r{2 zZNe!IR`!Mqc@C)W6FIQYNH*h9@9ogg2YaVXU#%os?-KX%GxufJnELMtdrW{aq*~${ zQIe8al4_M)lnSI6j0}tnbPddP4U9vKjI4|dtW1ry4GgRd49?rMPDRm>o1c=IR*74~ zzC>G1paw~h4Z-h5`l#0kHUcuyY$27=U))XJF`OV3^Oq z5CD|=|6l9Yb`79$;w3?T!3+Wo`xDO34_I$-zrW$V!+V8-`|tM)oZl}ocOy^cLi<{b4m6N_c$@jm?Mj49q0<$c47j<+#C+> zvfRc4Ol&MG9Ja8sihbC}cS(-%%>lXHtQBm6If?)O3C!$#XSghO+W9|Oyw@^%KFvtE z{De9DZJ^&PIlg^S|9%-wbyxIzzJ4Bi)B@K1iZlMKmATIJ)Sk__#_9fbC0yRj2YzWRzD=AMbN@Z|N$xljE@XSq2PYp^lb44$rjF6*2UngB*@(BA+6 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_98.png b/android-application/src/main/res/drawable-nodpi/symbol_98.png deleted file mode 100644 index d31c253d6464111d83fd7494f558f3c671d8995c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 639 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP{J(0C&U#<^G_oU{r~?z z-*WQ;piY63AirP+1%vkj`{yS(obNAKf4?E%-lpaVpd4e8x4Vnrqph~PfE@M`PhVH| zC+y5(qN=TZxzRvrR!M3}u-apM=YM00Njw6(* zxn^V7hvgmm%aktaiLLl>@w8x+yfV9YO-^o?g65s`<{J+wRmu1*GtH{AV5M1lk1DtSvSU;=NXRW>{mTRlBh?buh?11Vl2ohYqEsNo zU}Ruqple{RYhWB=WMpMzU}b8oZD3$!U~t~1bt;O6-29Zxv`X9>_9fbC0yRj2YzWRz pD=AMbN@Z|N$xljE@XSq2PYp^l344$rjF6*2UngCw};duZ6 diff --git a/android-application/src/main/res/drawable-nodpi/symbol_99.png b/android-application/src/main/res/drawable-nodpi/symbol_99.png deleted file mode 100644 index 5e4676001aee04bb49f6e2131af8537896a21402..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 819 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP$D6~C&U#7HHVpaQ@l(|Ns9NY%NgeQF#CTegDz^_1D(VKR18>z5M}80`9-RpRhK;^_Y?= z&~=#ZAkFq*p3>ujyiS2^jN zU5+o}_piv<%$gytUR=HDu*2KOGyk){$}gG0aNz#?5}D`nPmV8V+`!5Fz=L^PW5bWw z13!fsoIIp>7W8!c*_?J}SR=65i;MNb>=~WG3Ju&3RrWB29GcL=@a|Tq$IlDbO&KoC zmit~d;Z)rd{uSbv*S%3(!~Bck($U`8`U;_SX)RB9vXs5jX1wxE*ofi4EDsij1ntf{Z}cy9 z?P4(Ro?q^NrLK%AMCql{GPb+R&V|-~{=>aX>DuGDLSX?LvNVqh80t2tuAOz=<&?OC zx`O!SRX#fcAH_7(om=#pdzY&e;~u7f#hY)QI<)%QG%@e`R!4^Bgpbze*mutPCCSD- z>#DrbZZ4~ZTe3YRl5f5$`*T9`?QKSJ-VSEQa9)pZj{kI>@>@6T?_((8_~4$g>M^I( ze^FhLqv`drJiq6^IaN2)e_f;l9a@fRIB8oR3OD*WME{VYhbQxU>ss( zWMyPvWooQ#U|?lnaNeeMDvE~O{FKbJO57UuCE98NHAsSN2+mI{DNig)WpGT%PfAtr c%uP&B4N6T+sVqF13QEZgp00i_>zopr0LDTz(f|Me diff --git a/android-application/src/main/res/drawable-v31/ic_launcher_foreground.xml b/android-application/src/main/res/drawable-v31/ic_launcher_foreground.xml deleted file mode 100644 index aeeb65a8..00000000 --- a/android-application/src/main/res/drawable-v31/ic_launcher_foreground.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/android-application/src/main/res/drawable/capture_service_notification_icon.xml b/android-application/src/main/res/drawable/capture_service_notification_icon.xml deleted file mode 100644 index 9379c0f4..00000000 --- a/android-application/src/main/res/drawable/capture_service_notification_icon.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/android-application/src/main/res/drawable/ic_humid.xml b/android-application/src/main/res/drawable/ic_humid.xml deleted file mode 100644 index c976ab31..00000000 --- a/android-application/src/main/res/drawable/ic_humid.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/android-application/src/main/res/drawable/ic_launcher_foreground.xml b/android-application/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 6fd29bdc..00000000 --- a/android-application/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/android-application/src/main/res/drawable/ic_rain.xml b/android-application/src/main/res/drawable/ic_rain.xml deleted file mode 100644 index 7a40e264..00000000 --- a/android-application/src/main/res/drawable/ic_rain.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/android-application/src/main/res/drawable/ic_snow.xml b/android-application/src/main/res/drawable/ic_snow.xml deleted file mode 100644 index 968ccd47..00000000 --- a/android-application/src/main/res/drawable/ic_snow.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/android-application/src/main/res/drawable/ic_windy.xml b/android-application/src/main/res/drawable/ic_windy.xml deleted file mode 100644 index a27a3729..00000000 --- a/android-application/src/main/res/drawable/ic_windy.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/android-application/src/main/res/drawable/wave.xml b/android-application/src/main/res/drawable/wave.xml deleted file mode 100644 index 63af3062..00000000 --- a/android-application/src/main/res/drawable/wave.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android-application/src/main/res/font/anonymous_pro.ttf b/android-application/src/main/res/font/anonymous_pro.ttf deleted file mode 100644 index 57aa893826db03a74c98480093e5c9942798391b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112072 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 AjsO4v diff --git a/android-application/src/main/res/font/anonymous_pro_bold.ttf b/android-application/src/main/res/font/anonymous_pro_bold.ttf deleted file mode 100644 index 1d4bf2b5265bfc9dcb92eeabd5d3691035361a9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107624 zcmcG%3w%@eeK&kAl6;qCTb3-}Wg*K#*uuz?toQ=h;9DHW^*kY5;}`?R5C{;*7{iA# zj}gZulmrqAG|SqQF~ZBkWXYvq(p;9NS&}9;ZyuVFlF`fBEM1ayDeJP-KD^)G|LE8j zA!(oI-I`kRIX;~8zx=M>-{o*T$8kD*s5tK4KXER(`|B^R=lEqG;%v8n#XW(|fAe4^ z$1iW@IQ380ZC$(lNQ&_&$A1M^i$7nt^P&8N`_8E|%j@1?VXow+!|EM@-@s{4J5=-B0zc-@0pP{XOFxU%!as;{LI3!`k(? zvQGYh<15bLdQTrt#NR8th4K6Yju-T8eP~y)Zjl9l|7Q&N=UcX|TdUjr!|!pt2Y*-n zeCyg>+f|QtU)I)ib}Aa^|&s|)f|LEbs0O1c^3bYtqIn_Q4v z83+o_tTDk*y_y|xIN)^EtH)HDn?XT0rqSG7TxvF_n0fq&{nO8jH8Y3!Q&Oke^!sm% zr#L(hOCg>T|Ax!r^0@B@^PNGnGbmgi6SX&k`MO}tR4~RlrolmsE|`D=T`+knsL=&e zrh=j_m^Ou{1k>54iJi%2f6bke2dBe$bo$8P^f=Hf2W;3FDI2y1f6?F|oTcGZj&QOj zQRToSgQ_X|jGYQ*>4Nc7!DL-9m3HPJBlFHfQ5XI5+o1*qMaEgsoZ{ zSbkEGJTMI#7*@hcD>1&gXm^pYW?4d9k*UaD$G7EJnslJdy{#wGm7MH3E z3vFJ5F{MOwmwCLHX0B+ADYT{Jis^c-5R-1<%W&lJ@OoUN(eMN3-_X5iJyo->r{d!2 ziPn7`F4f-~M^+r@t8v{o8kpd_Ivbh;Qflk670o)sm8WxGwDA|Rsyc?+_l>8YJ+G}> zzjuYA&yEO5vplt|Pq$jm)!aEf$dHj;3TCnG>_iw!;zND@L?HV}? z=jCd7cQ_+Xg_YCB<>Ip>u3F_-X3}U4+Cr^ITc`DFd$l{Y4{MKUPirq|6W5HtqP?oc zN}4nohK#}tPexsaKchEeXU4-B$1+Z5T*#nHGOlI_YeEZhwOE?q0_XVa3*KEo|0ZsM zX@Px#Z$aaN)eAN)7+Ns8;KYJw7hGD9xMr+8?&kRG)$dlb%c@P)_G({sWA*ClP1Qry zqtz#>pRK-Bowz1gq6@CX+KWyw8Y9d&5N4dhTrM2Ah)V71<(N#CIt|1SryDb?Z;roa zzGkMI$C@+DMdosIgE?UCGw(7#Vm@v@W4>s{&0V^&3iZuprkDz2g{{I{QD3pDVq?W% z#Yn|BD*m?Odli`44=a9LA*@+k%JVj!FRK<@OL7I;QcFRJ;ME&kOFZtfLQ8?>%l;-# zOn-k=Tsb{%U(x9<>#DWeYrD$aoh$6esvM5$YKNnWZ?M;PdR$#A?DiF1E>CBz{Yg4a ze^!0)*~bC3QTkWcee@6SbJ0JkD(n@$ zipGl76`D1&Br##}P0CKFaiCU&2iqeYgchhxxY<~d=H{}bm?C45t;kzcU$m+SkLxYk z2?hl!b11FU5Md59xuNH zKNgK9U2hP%a`M?Gt5(`m zvB4qzP_R08tVp+7mzU-&E3T*$+>Iw29)IFUO>=qoaP$7t6%CKKH}4HN?af>2YVY?q z(Y zP77^!4B9S*tG|PWiUD245GipnOzw*Emqz}IlfM$>uVnUx^|cz+>KJR9B~5L!TD@w~ zC7Afkb<*p+XPxw`>>p-Jzgow8q}SK+nb|)S?)|~}qesraBAw;^ube+}^!yKaKSsrI zNzlPTE`jrg1+56N0^JJL3*8zAO)AI>5sT5qLVt!6NJ~caV}dTIf$oETx1^Ze<`ft7 z{3&QQ=^#Ha!4L4m(xd!Cm-&aJNAa91(xbvKcNy{-l)}k(<#AV@Ew7cgqzS{)$4^gO zp1C48XJL7r>8D1O>vu{N%`T438KArm=LYpw0y_NI29uVmIt)3&^kRm zje8~DQi-S3es(Wob@@;;kFEJ`i7p6iMTcAJZp+%{6+1zEJPc*XjLwqFeod9&8Ttz~BtV>&6O5s1)ojVANG$ zDzF#$3K|Pm7iiW57feBQ$Rxm|i6UB(u^h=n0)}KYi6*sfER#e==1?XR8JQWGMVaN9 z4Vi&V+$C8zmcztNjxooUxCJJ1^Hvi#cyfv_6c~+vND!5-bwEyPBjvW&>_wWDh z_jm00{%`kp`UPP{yClt&`VR&J?X8lqyoJ#dC&oh}q;jjmDM=A}N{-lMY=+8oRhX_y zvB~0b5U(64yErDml*C%b#gauyc3&#!&1`nNQnaGQO*3$%xWxFGum8W=m1_r=t{CoJ zI(cP6_*H4MD{Hd2^WfUwf15bZh|L|vzUFfM!8|7!nt9Bqi^uOE_Uj>4d<=3Jb@4GyGQP8favQ@R%_8j{Af4$Lua$u!6-ua?m z+7*_LzRdq;-5#H-$(jDxq4z#3?Rt!6l?7@&j#-s)--UH(hQ4zoWs*$G+|B4EF4L50 z&-7(BX08Ukgi`0Uxn0U{5OM1=~`l)UZBtHb_jaC?2mHIMIIJclNf#{(bxt13iPspReur zm-ck++5bw-&eI#(AKzMKS-!SnMPGxJ@9`h(@s#zQ+L1r}WS@Uv{pHNE#?rP82afcg zAEPwOiP!a z;nxV-nNMhMRoL6}7?YLz8f@{P4f68(SQ?3xwB3xz;?hiM_B3BwW7=vE8CIN3{7mPV z2`*ahR46ZVZXdI-k6FslXZO*pG5o=O%wqc($}^Zj6t`~}i4QVAVj%p}%_%Z9pKm#E zzPsyNLrt--#P8d)blpnp$hP_+%cNL3^K@sh{rH0`_zT@<_BNFF9q-B6anRAU-naiq zWv%e$W$FCT@tMlB+4iqCm15h@TBZ2HZ1X z;Nf1y8Zrz;hH^uL0q#|nI+-2=CMaP{P+}~xm3T|)OIDQ-6O`;MVU~1+zGXYk05=KC zr4`aWY^h>oGKWzE(^?#_-+OlL(H9;lUjE4IkM^8jzTLHTdHY`miu2ALYCqmzJ2|p% z&rx&jrp9fD`RBHr8>%5eeBkEyAE>zN8^zWYd(N!y`^$#C=Qr*-ePVBQUu*GEq9O9; ziLQ0<4Cl46NpH5x&Pv3OEbJzjG< zc3nKR=XiU*@U~Fg^R0oI-(M8_Rb2-@y2VLXU%J2-^9jG*`xE{c>DAw1N6%qLZJZ0X z&)ebZq2GE3UZ^Q){fX;g|8=+MTtx@3ohF<7nX(*=rJWX-xiu z4A{y)hqmn4vBl|V z>h^lqHaZ-QYrWp?CI`Q5%1z-rHJ ztMnZ&w$|=BvtiSIuv+h)(k9n$b?sK{Zy=N+HkTk>) zx>sR^|BlTpnG45|z6*=8H4d8w$etTwV7gQO5h^EUu8?ic_1^la@SgG<*ybv-xOp#u z3m;3n1_e&y2Kk@zBSR8?+ePyQW+@(mj36xV{%}lEEFQ!qC6hgqygQi@U$QCLp6p9* zOkSM~o&+kHGlkEwJOz%7;`VH4y=<&7ads+EPU=u9qny-?)S}e#)P~eRs%)KURb*_a zBHGMG;@LpEA|7(LbhWszy4yP2-1pSirAz*TQyE`P%H^4a0CxH`=(o!b=Mi36d%^loghF%IeDeWxZuP%N{N} zR(87VLK#6)Wmn4}9bw0|6S~)F=q&8?bk=qHJBbB52RaoNyax+%k75Qa#lcdnPI#?a zhXG}(SAk@8M698NrT36r%v+U-ui#o;&FFoqi@hR;`@g0Z++kM5!mGWu`fz& zx?#^V;6s+1M(_k-PGn;c(<XD%tv zulkcE2J`Z+s?@@Qte9`7rx^0|aYd^Rt>18HmCd&5(1x~QPsN}Ap!4x<_bxGJEV+04 zV_)sS@2(7KU8>8JyC^3q$+W;|T9~U7&aHTKM?<>JlOJ#PEzG#9d-t-Yk&RV}rb5$K zq?G*ZqLpjPHa-8?pRPLg#z6n;$5!1{+B59x{Ig?cR;_;a*q?pXNNNXmH zjC3iiE1(Qx77gvhBj(q3%0jp9Zx_zj?%GKDi-v^P_D~?`_%8yLZoL zjuq{Wi3vyh3PA>c7rxw^A$ z#f;Ye6YEBwA9A|~FCK6Nnth3vFXz^*UlG{8A}g!r!N9&zJAb(QsRt^_X(uP%P+a3U zDWz5ocHZTG^n4%?Jm`OB6cU)IWD-=82z;!EPz)opyA6c$FhEQ*_F zhJ2GJ4_&)<=p>+rkHVYPru#!5?*I9}O?MKGs6?s~xT6dr=^f=VH6 zN%1Lo2=O!sici6LVL!7mst+WifH2r)>G)-7pJGWA!mi8JVQQak`*CmuA{}~u)YjHSL|Rza0}nhxq)+8Y zAMsa&(F31MY-1?X&F3P7T3WTW%^4sFo}7`JWPK?;~0L!B9$@B z{2~x@7D!gMiJ?u(fkGkdGQ}{1logni#hwA)1b73Wsee-HoSfuOO$rsXZ!_-+h{keH zfp4_fMVS_Xc-`TF$}<>H09GLyL~Idw0gwXhbAp0vSpae3aiVtS>uo>ZoRc1j+*TqU?JWHO_5syU)EQVyQ{^j>j4VKQ^bxE0z{Mx=l_$$p{@B>abPaVXVXQXY3SCge?wngvs;uy)2w zjF3%6lg;Ec)tgqCh>%S?O|W^PNnk>ZZ?X(Am?zefVJWhdTN*3@xSzNCgcQXjtVJ;? zh0nv@S<80>2=LBY-VgBm^N2TTO2WDW=O6V;M3M@^5|4<%dPEX~>1?0$5sgWS60}bV zH1UMp2~2Aym=f#>zJ$hv)d>t(xHH12D9vz+h9GpPPQb0CGc{0@*sCRmIh}dxIdyfE_{wds}T*RPkhuBY9T4zjpLKBA)&L65JJ$2@@8GMPjUnuKFFLr3BqCWqbOb2K_u10A`;?is)#269ek zK^Pp6+J{U^HKy89y{Yx7tKff)_onWITSjRdSUYU!V%pHfLkQ5q$zPnYxM*?t;)cZm z#BHND6qX_kLsvRE_=UC-@ryRsvF^mS_{R>UI*d7P)9cfw-Xk6M$uHXIp&R3SQ`a>L zmjvO`c*fq)yAR#A<&izV06Cbyf$qi(ehTMzN6zmxckVp&BUg_4=5Br6M{29j!ggbrBR#hj&lLHbNO-^Iwmy>|HS zqx<`B-00sg=omq~Hma-&@v^J2N4Q7k1O`)T}-TEma zZv3)vitxI{_#1*^6%mllhRwDq;?RNvi*lfZ#~B$YBt4eG$RNd-VoUL+)TgXM>|wk& zWhX)sp;&baRxN1JjTI9e6b}_MIw;O4E-EfBZYT~E19d926yu_Z0g25geaTpx#a2KI z3gF6Y5rU`*YcnE-u)k{4<87T!xF;rxn|i!!9<(g)s;vL|_PV8;4z_d*TP7xkdOHU5 zDmp5fjy%-F_jVlWDXVE7zw34}ItY{KeRFxEmPfk0ltF%}lt+GOj!U$^R7{V8r25hrk=@dj_+b%wH zDL6Uv#9N_@;xl3uZ=UX)fSn-S;IET*i`WS!Sn(jvEGCnPDyN`I$b=`EWK?uVlrqb} z*fNx{&2HEi^R2Q8NLhf1q{vs&Bc&Uk-m>+Z8%rm(@X~7AOSF^xm2Knu>gx7g*e2FZ zUo73!;qwLVFBKbL*^nQ613aaHL}j$Xct9BkQ(MXb3mHQ%gw#A~XAFR6POx}G+Vr8c z=^Bqn3wgfK^#7@f!@Xa^y?=pwCnB={`FpeVSMJToRYB;K2eE%M%Z4I*YA9CzN>IiC zt&abbR!>V4fARX&{vB6ee`nWyKkVE?V-Z|4Z$gzm&VMFp#BCVU2N=^uj46v7l*bfB z6H(4(lr&Is1jvdEsW_H|1bY|m84O8mFNi1+hNW%_q0&&Q{CA|ufqjirvS&+CqO6Fm zDT<7u(hy07&6$?QzC;)%7bSnw=xC$Vu|xW-i+{TPz(^batquPrJv71Fq-zrs{5Ad! zq_ExK&G>XnHq7Y5$c*&d#;{1(T}T%zVt?f6C4#IHl~qo|L7H-)&{!~yc}k=KM9ct2 z7$grMRAw4ev?6&bq*Eu7aEL^KvF(Vc5k~;4Q^qe|?2>L=nR#qV`e_&c&5qNjI{0s@ zx@Im&r!nddp$X$1Myz$dg_XqpDH(vtj7zkNuggz`fO68~z>#X;0;I;3Xi1cNJG(*9 z(KK{i81XFKa$-a}zQ7RE&kGGw|78TiUgIDC-bL}W^w0b|Fzop}jD{b8hPEN|FNU*( zHFL6p-5jbDkZUB+$g(PNN7+lTNiBTn(@&*?F%1)+6@&MqG94oLt~!SIil->kA=s?Z zG~=qh(m}x)c^XGKAM-eap2lEanhEF(9LB_s+blSxmQO$BL(;*^>bD8yz4eOVWW1%} za&QMiljkHob~s{Z;tm$ZrQ$FCS^D47kN=rJ@~Pkymdv~*{F=#3WIZAslx1fqnI7pZ z(*x;}80{~_tH|2f%lbFLNrC#bwae#_57ZL}g=6X8GJHF;ZR_MzV@vU??*r5SwZ)h&h))Id#k;C{8sC z8zXTRFzL1IgdrQs z%C*qw7U_caDde9hc8|e0AE8Ea9-;^a#I`+cc9qK7*x)RF#$8p=vbS^Q@Mv?pwP~v* z&)ed(#0sqy$i-s%gyM*L&WxOx0%y?T3>HMJ$1(D{f&an&=UIjG3!-16Lp+yKzX zkf6?`H3OuP!4@{dm|@HCX4Ge_%Akcs7AF=qHJP@3acPAY z)Y5VCfo01cIN8xMR53Ye?RO6xJv!j-x55|oy4{V#-`#xw_;5qH+yANEae8FrjKfY+ z5EM8J3S0mb2aq}3q*VAtATgGM3yB8GNY#y{K%PJ*102d`gqLl|F3k31*Jb;&G1v{+ z1KA4Bm;&-jQPw312T96-;>!h-pv!4pj6+67X~qm=k+Iy^UsLX%2N4hdW+8PGOEGr!L1&NlhDa29QaDtAo~v(HW&A z8IdR}Gb@nE_fYi9SU#J6zA@jH@6E5zUzJbO&)=C3vJlky^l+r5z_cb3noGL65X*9| z5b>4Mu0$*r63e2O3w&r6Biu($i5H%IAwu(10yge3NaNpQIvHW30m9OWMZCAJ~52V-Q4lo;FgI;?x`Oh z-@4=C{-$5+PWJRXrQ`Q^?^{}Sq@$)`IJ9+hcz@$PN8Ubgp=0aT4wC7FiJgLHk;&~1 z3k)$u_C9j>fp(c9PEVB0!w6k53Zinsn7CE;Rzk`dNq+XDbL&o%C;Il0058zSm6!!}E7FiH6K#IHh7dSRbP?P9MaD(8MczgA zi&ib7&0n;05$IZ*vWVy!NjwWkKp-of35W$53yKz$FKAd0SO5W$o3#KJK?E=$7jbhC zu=_Rwce_~X3Ui}m`mP!L_PXDm>p6V>{{72#&Zl&U$^q}dozjr;Ri429_x;3%@sLTWp4DwM=h zKjhVma$BNGJ)%}`)&teSjH6Xh52@KIs58_>>T-31I-tfXBykk&VgQ|-szDeXQxb-B zaC2Kr|KpRBd1v+#vo2`@4h>V6S!@>GP`3P*$xHRZQUiC`9;<)U7N;1PTttD~Pap9wPjVbW{3=E&36cPXIL>Arl*)y`D{2f31t`IIHtekERR%X?xZ_IhBWdPLfP?g_>u<@ zCAOo)SQP6kLu2;jEWMKQN`-_-CDzaTGUA1I6f)#7KsTFxMU(LyJ+s6!gOTMoAdPx5 ztDxFEnQf`co4jK1H&lKl*>ZPF_eNn~&C-JhB%Sgto*KEQwQ*Tp?V-a8uVOX+&v{kZ z{{IGErTqBlNxI~@eF3kEr+&>?HKJXgW8=30$CmTEky{8fi%A-C29Vr6zFEH;$=t|y z(wp>ly-(k$UyU4Z;#7dxuugIfxrMo&+`3#pjL-26xdX6Co$D9Woz2B zyr!?gW^3rHS-z>s#$VYQ8g5{k`n&t<>-T?m^U@uyPG{?mr8QgHii_K}kTfZU4@#8& zKVau8oBw$`Ujd2#XYBk)uBBYZgt|0~Z1F@KsV}qh#Z&F`&3wr%Y_k_f41Ka_u~uXc z&{{no@rhs$kT(R^NT#LFJ4B$IEJIddmM5z&%MVXzd_&d%93+`?qMXbqGGY=!Sty03 z$Qy#$mut+m<$81Lb5{{1_U7&cB}RKg3${JO!-4utt*E z=0dx-!{JK)F-pgPg&%Ai{_Ey_)1CeYzSp_;!ThG7j)vi$ihK4x)$+h(OIyp)fVFi+ z@&2d%U+?wt#;-nDm(^5xcA4AlH0GL2+CuH1q!qX+wCXLdL<#{usRx$V4b}NezMfkH$F61X|HTa65f8@_1hX{*wr<76b zdW4{%(~)-1vO8D>qgOnyd-ch-N4ni_zdgy1Al0!U;E(0)NB@_nd!&^=dYN#z%hJ}4 zKyL%hgdyp`rslLAOj730Gfqzjr^}cU8K)cteB|jdhE--1g(}aIHtBb!3PI;&nPM(# zquQqSs_WIOV3Lmas&~Rt4JGMhm>ZadT!e}F$PQ?syA+1$gGVBUDXI!y+yc{-e`dP# zgI$kYei7rBZI@HG;p)o3*y<_=3fvuys{_qGC7rn`oq6wfH{}%1nWX|M%5R~ZPJ9U~ z6OF1XH)E!kau79t^yn?FXZEn+Moz&V0yk|K3HR^f`VIHG!9iA5mE-T7g>^am&J%WYiE)q>vf} zAV2^R60wa1I)pbux$%Uc&RaABwbNO_3m%J%J1iGNJW^mCyW#Mr5cGli8~~^(sMg9A z@nvwiMC-|_jg9uMHEX);jT@^@o^;##8?Ci2v(0@{I%se1t>(|Rl}9KmSV~8c3{l>z^yulwToP`5(T7MMZmgh_?Utd7`NsS=C%)*{0D4qwc!FS zq5S|ia+8sUqGHe{!o|>Z0GKgXm>3F*!h)|fJ-r6moGfxn(=(DAPqU&rVwxo+A*EQ- zw9?ruk$h*_hY6WowbrHwF`<)Hy-oJ6&dx4-Q*YJD=NxYSd~r*KMWY?);?H_)6F6Nh z`P-cnrEO9hrVF%+zctPMPCO$7!EwnPb&E)0K>#CVdjkkVjV>)S6$znWmIfefb(iX1 z(KuRm+}+ku>9EWlb>3CXhaWtk?Kru;rlq@O$ARR)H+L+*_r7~?-IDWUHIE8~!1g)B zNFK$b`%zcI@@F*%Q9w+UQWx%=m%J+m+8;!&D@#! zaOSbh)0r1CDWy8|DhlXAMvi4b!|2ba68`*m0Tv=nJKvOV&-djw=C97*ls}X|ntvky z+5AiSiEBa`@dPA>O!G7W1G&hQneWeq)oKg;$P5iquK~g-up5;LT3AwVVPP6XpDgd0 z|Mp2ib(_=KR%LNH_=DHvWZ#1h*HWbVcDijgH~py3(gl{PHm7fG?(emf0<8KZckT3E zA(MYbzQj#3QaZ%4U|rlJs23!ER>k7fc@+PLeF5|eW~#&BD0Fxnbq+rgJjORT29Wmw zH#F#uz^}}3Q51Mo)R>8T5ad{V46^)>M5U;S%!@RvOjDXO0jzKg$>6dr@jrYGG4$)8>Z&J40 zz;kcjIU<4eVJJIW_qutzar;?$H{`Rl8}haCZpde8H{`QyHzHUd?ef*R`+n{$yDxVb z){0S0_m!_@_vKFFEV4;w&&v0e^POpz?`8LucbUfU9GgY!+|$_H=AWIL#dGXw^0jlb zc#b_yJ}c9dd|!H+e3m^el2<}=^Upo)b7$qb$vG%AH~Ct5ZjsEC*|T^WG~d&_jAAB$ zE9BCA8#)@qxQ#Yfj8}~RDDj;3qmQ)b5OlPK{vT)ZI zSL-uzKd)N9SHDyLu>P3-wElvg#J&D1RqhkGLvlX%T?#Oo;^vh*P|$HS_eAcqxtDSi z*KlEz8g)ss6klA*YzJ1p0F?@D7oCZw6)HB2v^0;duc%l*+T1d-q2iFWy4~q)ud-UJ z=)2mg>S`X{P*Jgg{=B}ja{Wm2{J-LA!mU6R!@xK*fj11_7K0_zMCgIRa)A@gQCa$*mal0>m zCYVrRf4pTy?3ti>`o)L7mMyq*MkAifD~KO0;`-4=0J&3$bs(S<%HUao7@(Df5mz!Q z8KVG*X#oZtPSsF@9H6uC)?jxgkswMMVs#6#Nf}8+N##imNdc-`C}1Ju;DV{3mAR-6 z0Pra;C50@81=WEbSkj@MDSH%CRas!EvY5MN!qd5@cF$Sk<=l0?hRc^-_H!$`o4h$^ zYozJZlC8?(%uAdQKKNDh{!aJ)q2g`L9lx5GsOd4L*z3zXzJ74RWGgj(M3k&Y4#Y`V zG8J4C_h-Sooxx^j@NPDG#Ey~Q)2s_FxGrNGuyM!Sggv--yGgLdxlL}n+vjd{uXbZT zvsO+e+xALBWnrbKvaZr!Ny5Bxpc14Gx`3gKV3k`JTrtIkmuT#u=LD+kCwpXm^BK8n znLY>odY5i}ysh=gJ#C3E>h^7G8eDt$%;B|n zIh}Xa?0B-x|MdRu^vgMi53~)@`R=#swvN>1;-{J2%*jeld9OyLn z2U=Td+m}@Z4s7ZkzN=`Uz4NhNw<9px?d%)s4zzSsdjkhYs@f__^D=APE82Yy(_Q2z zaPR`*%cS8ymf533f}yqM8(cEOPJrczL&1773kuHpNBAq450Xl*rcOfseI~aHu>iCr ziNpfbNg7Zaur1i;U_Kpb(NsffVX7y!F4a$It{YMZD9sfa+~7&2rl zy@K>J^b`>E#^(WU+|NJxM&m#%e@JEVt{~Y<5}D$(KJHw&Ac?F}R}%UHd}-w+Cg(D^ z3SAyooy+f{$+-qxn4F7zFQgmFg2WD1v@0`H_>#>`nI>h(d=buN|FUckSd0u3k2t$T zcvKM>=|_OPnE4`^C|5k?zHj*Mb%$#P+<_%`*H!p8`74&U);L$JubVW1PMZh6;#l6g zyduyWsN@r??!Tv`-2F_cWvRnn>2|N^SlSe*Szc;gcKq;kNNjFCd$_B(xv#pdXL(sc zmc!|5-NyO{@&l?a_-~|(yy!voop5dfRk<(H7UQ!_TTZK*01g{}UH>ix7fkbm3!C&q z`ceG}{j>T@P)YDk=0z9?)O|SjSnlcE3(!8}ujF1OjJGIK2VcIsoJoOlQ@Op|SKe5@ zx*SqqkuF#X#WLN z_O32_v3P3R8z(wjkG{FD|3}9I?Zjvw) z#r89$jPE9}t|oYR#oTi4rEqz|0!%}%MU*w1nNY$yNX^sjM2@Tz&-m*l?^3C_DXzp+ zVlVNPG?uI`q4M$3k`pD*mRu@f%Uo_KFD&~SaIM$WnDsq*(8e9QapKF)v5!Z3o z8P`QuBGO0rdASx4t}JH@IJ;L4z|Uo2d@jn<-Th|kNSC{`>wy2w?nA}>?OmPz{$l>% zAKVH-f7HG9KFlGpyx!yIKCQAj;AtVO+2kS7Y}_Lif6#&Jd8#02%^BhS(Hl8BN-a`C=_zVCsIL> zD3L-mIKL(akO=;Bn^oNp>~9&~_Vm!uU(f6a?g;W%(DrFm3h^z{Akq*o@(nwr8vgkm zkYLXvJMdK{J1~;*$g6F<@T%0hntwv|+Rag1jmZ(Nc<8D01JdG`d@|Gn}Yl+1?sLr4pIuhOp;RuA`&e z6lJnr6vKI41Q5oc<}e1ie{Q~|Lkb8&$GMK*Nx=^O?2JUe^218ENaR2YEQ^_P@RC_y zr6gt%;htDbm_jKLQ-}#xMdU^SoC=VRyb<(Vg8~|hfl7gG2*U`8!W2A4KsCjJg5ue7 z$aJ)<;SZj@`zpUh7?dvXCh2{?X{K+VTw5#`M^2!?SOrqK^$zsN+brK_0VsdO<|qnqO?y(F_iJm3wKkEeA4_Hc}Th9sbKM)8fnc2&N0yfGW`mM zSRby~f{cQqg7Siff&eOdLviW?OdM7s#Z;h)tVXNN>b2HeSCQk}YuyRQH)Ke)lIfe9 z$|CH=>}xJ1)0-X>v4{$7F>ZiuWdF`@uvIwQVe7y|<$ajI^p>nh;+cc?)6@-Ev zvwgNSs<}p6eH{n>sp@!$dTp(3|JpxQwS>By9mRrBhr%Pd;g-F{E(uGUvG$*G*ToCM zD_kBr*txjlRNUjnGG7mtktssauvo^cp$zslW@Y}+JTISS`mptw^|bYZl_a0_DtY|a z9w+%j&UabCf1K0gv^#yyM(1khCg+fI)Oo`Btn(5I{<-iXHL00&bpfL-Vs3;+U<*JC z6*07O$*i&|oNaL^=Nih1nCdw>$P$nU^b#*vmIho618(=WmQw$6t97a0)w0d)9%!JW znK#|t#Wht+dVbR9jDi19GRw_40*DO!RBp#{`&|TQSgj$; zlcgO)lv0BY@UPot6V6CO)MX=||8U0eeZSIbBY$Edz+{(f%Vu!ws6l3 zL>K^}Az)ceBnifJ5<##!-2B#d>HSyEyz{dg@0@*E`k;;9Bz@y8>8RjTT|lI6=BnU8 zwC;jR?l;J+Sr(N)1&wu*%E?f|4myM&kCaTpk3t4%^7Sz-!t_)jp`tcUvMykG>^f7fm*gJEq7i}+%`#a_ zV3gBwi_-(LU7i$ibzhw%GEw2Znj+<)*q-?Q=Cd)iHX zkNC#jqu>AZJHwMlT3+I})mIx&4R`ju2+BoBh1EbObG6|ZEyb3RR|@h%gc-mGeou)Q zYj@U#&<7Mp#`NKPu)HsxN7@%G4loX@(zr+^E@H!FX&av>{fvM7@&tc{fBUjjFGS1{iqw36=xuL`Y7-P`^U?-NzO6G==kH*TqBBqdd zDmZz1G6-v|>-W#dKdgR*gT{RWK5j1eaHOXpauO0T3ZV3I@&Tw^9z|4gsS@jCu9&i~ zQ6A@)Bov1(lFsl8CY807l?(Bd-7*04O{OBMU4anLMNlQz?k%QGKYJX%+IFkpV28 zs&pRR`me9$)uQ*;kq170Ew{#^zNYEy{p{@*o>QqVYC1Qli=TfXM#XgNt3VhXtfr(4 z-RPiLJy5U806YjfUZ=vKVD?lfM~)XIC{-mTTEg8*3?+pno|3u}KlO&&P%;3gguIGU z%s@v?x0ggL7$s*jT&5|-R4r=i6r@&1%1Yv=s16)C>RRgfti7gXeug$fTcj=5HfRId zKJ6~;BiiHIGun%2W*y4Ozhe=}5@2?BE+Z+l&Q_6tRS}Cd$F3YWa!;N$FF&iRx#2|3 z(yCBDQbc?c&V!pq4)M$FfreuD3hVnmK{I0%J`fYp&LLB!QdN{LHd}|`ELC*Y%zV1F z?Cz07V?l|bCRW&L@kz!Btm=o{tHQLp7`}2IV%txk8!DAcz+wR^B~KI_s@Fn@ePJG6 zCR^NjF+5t_%mKvhWSVD=2Xs}~qM>!nAq$1l@Qk#4#%ok7VTzqsE751%WqibV+<3-# z(a7Ai&n4Y4dSXHhxw&Rx+PCp>zyC;|&)0Xv?|*!wFF4q}cGu2zJp+Hmmg5=!kzSv- z_py$^(TzUe#-o7;|Kcwm?BBb0<~Xc@NWC2O`xp%ylgOjxl1Z9j-pDBj*%%GRLZio6 zXY`|tV|;^g03#;kFFQHH)QUICSa(*Mkebc`@{&WMB~nZZ=k$vkV3B{4Hx8zL;t9Uj)ZRDXt~=b{(9nOl&OOlAZjw$;6#MzKCwE+Zrl;o_gg&V6{Rd(Q zaVa-fi4M%u!6ty8&S2&BF`f2ih^u6#NfYySP(Z^pSSVLMTd51$VB+e6Rip#PYT4S= z8fpt`J+*bU{#shQ+JRbyDxxHz8S7+@((;OMF2!F;aS%?@P&srdoDk+9EHo~(E%Yv| zU$}}Axq27wgi{jYN*6{%qMlq006CzogjjuszDQrLZ_uM(WI)eTroEo7gV*MnA|V1V z*vG1?mrVtiIfDyz!8&Zh?WH&@{2ODFlh$NoIo-^tP$}DB-i9V-e$Jkof7!ONwW@Pj zzANzHGDDuRytu$`+3P)7)v(=USzp(6zgH{mtt&Pc$DgUO!{%_RCX%v^ zrOkG;w{rjT)g^at@V25#Oi))gEwxq*`tSBNtf*T5t=Bj0?Xo)V+OjFxQo;XXu&rZT zNDx+5yPQ2W*v${Hn-kd0EJRWlbN@Q$3o=VAh~&7`>s0wPzBzk0DxF}WWSg?>*}m+? z?A0iM3MHjx(?Y>w{NfUdP?pMui$b}oRQj^BuX%=xvaL}yQ$}p7QQ2cg3OESm8p)&y z8kwsI8?L}uU@Pzz)EBIxu1~!MJK;Kp?D9qExW9-tdC?FGERc}6C}UC4qVh!zivp;- zSX@dDpb|MC&v4E)gb9RB%M>)Q>fs+!ZIvy@j546DJ*StA+H&$&4u`g_$FIVNX;PCV z;9kC|!8Y@wG=99Ux2CVjHg0zBYuJq3-75EkubaL58YrK)(!GQKm!;*>(aapA@YdA0 z`1^gx>7{tW73=|ZDWGn81L0(bRp%sSgP3#R`@>4eA$EeCNj4-GCVP_WlKtqZH@+cx z0Il}qbz}|n6l&3UF5oznI|dwQ7R3=N(GM|I$<9FsN44Dh$4X8J3WYAuz-CB7D|7l6GBVbM z_qrJ5byCc_aIDf65vAbXG-Pm`l0NzDpPm~Zy22wEfpoR2rIJIWDqUvTz>+s}d%}9! z8!`n%28=0KPSm`jY;pEHWs*wXY&chwf!h#v1-lGniW+3Hjc{K$bb1*55pbR|JhG>P z*_5G!C5f(yg6yAfFY%jiD~^($oVA)z3o=(Bb$KR6v7F$iyvl77-xKdb*KO+N7+$2w zf_k&Xk{V8qg_1+65{fkNd^t;#We3TUjf#uX?s!&wuj1T5)mQIscGd*!C+PQ%=DFYR za9;TNp3!2jv!y<;^HH=ZY-^C*%89{)PVeHj28>kczb7K{Y?gPEk&r_53JFoWrp2Yy zXTWL}D_EPo>6`qtM8*9V#a7USmR})Oh*v>J36u$iLTDgeKqF&lovFWO463m4$-g!z zJ;$#Yd_zFHP5iR+b^f_sd_CVZbY(K~jk|5e-Hy-Q4f$fwdn$A#r@PtUOy3@-cFYk^T*X zC!bjW`35vw^yJs&`>D=zL;e6#P~@3Mbw`ToOK`_EiC`GeMPC9D3MzsK$^OWSfpW+i zVnxrfSs7VHS>;&`SplT_hZ17Rb7DTH#*&|+Lkk}xTqCMagqY#y8C;|#AUkaCzmTr; z3zl_e@zAGveYh=vyDV=ZNr(aH^$#pA5&M%mYQqq*bu)LZKXjNoUR4R~C zrpky)$$|?P{Nb9_P+~k&>3a4Bhi)v7G;ZEd9@Dsa8F@u{<#`QxfjpoY2-zcr!9L&n zguiEtEU*#oUapW%VJl=H#^@{sDLU5@!B^(C7sp@7{#xgFspAY#ZPTe@M{xZPZ}Ozo zTW(cNc64@j@Wb7ET@~&K9d$%$^wz-PO_i-q{UqWw^1;1}ad3u@uNz)pc`mDTg+n_%|9~`WWG#}QH+rC> z;K~H~>&hx*v-mpNmM3E^kesYwl#Fo|ktfP#XA2$aPk8*fx*D!%oY0eu|E8Y+W-GpIlQ6bTyJ~w^xUtY1b#p`1Dt^3 zGXZ%I=XOu#ls|IMW;f&Z^}l_=g%6}hF~YtIEb&{>t4frKuFuFiHX)na66TX57Df!{ zCkB2td_-l<et~GQEjqnr|m)T(~+toi%*|)|7DT<6FNGFNhb}J#*xhx?@?w;?lSn@q&~iW%0k{ z&C(6&C%lz^Tgu^o!T%EHEYf?@dzAOca^_h+8_Lk3)g$?A(190OPUc-q&)_Wbhj~2x z9dUxaGYs9Z*_*d8YP6`1yvHi?Mk>bXkfPK(*2f)|M;T?GEresSko?8$m>kSMErwo^ z0hI)l3ZDpvpno59Q!)v%L8F{(dg6ldLw>`l=sV7*fwlMVVS$E%xgKPTh_h5y=`CjGW`Wp zptCigzwnwMymmn!XzlRlT+lD;-q+T?zk8YP+;KrTE*=b=>|a{7?Wu0-qa!2h&g*UI z23z|1^#?{qt<+a`*^Uz(=hJP5bekTO_bR_a7-qK1yftOEk1#w)F_FPHW=$UA91E_0 zPq`kJj!Lm{&?y||O|A6(!CA8g6odWakPqMl#bk5eApwCXA>M01{mQU93_W6CY&??| z&}1-v(Yy?5B0C~Jna!-o3l^+U4x(ZjQG!)LO=YYWO)Fqt3(UM$GaCt^O*|UFBsLpn zH~KE5;|e48$BNFONYjyfcim=i3pb>1VamUMCKwEU_z!t23M$Zrpj?jvZ}e;b^^D>6 zMg()SPv&yCZ`0KAIvZH@7z*wKiwNLvB486N2DAr!Y=~-^UZY%ys9*=n-c~e&Vg#`X z0xd`R9Z7zGt4M8vTk*y3xuF#X7@UPGnTJ7dMJ$yCfb3*o4U}p;X7aE(uRXIoC=F+n z8ED?0e8P9jtrxUOzdt>p+NKhy{{pH%Kvz#Ar;BRc)3}FdKe6m;5DUUP*MkUusji1w zRRCFjLmxW&*iIi)^by1d(;=|p__&+6e2j+%!M}xNi+_u~!|&KQd7{)!mRXZHgu27; z>DM6^Y(|S0IjJd;ywr3wuTyeUm;J_cD`F^6*@t) z;0fT??EO=U4c(1edZ7f7tM9-{PvVx(m)95)Lzgj>!hn?MGcCZ zFU^ILS#dsJWr33L#8d2vS=^t8lauLvdGj=d@?@rG$r>;L^?lcSrUEe+?re|2L zI0gu`W!!Hst8>-%%6Ko65Xjxfocx*HoSArC4ct3#1eIl=pJ$`1Ytb zLDo_C{qW+rR(y8Ed5}T$-}6?;O8KpjmCmsR6gU5aZT-hz_q^+YE-=M;Odh+(=V|n; z_H6PDc}6`aJkNSAc@T?#z4hHzQWtTprdE5aueGstb*l!)n_7ojM_W&{KHGW;$H5L= za051mrN6Lsk7D<`p`PxhO(4yG9}ey#UA0_|#55$Cj@i`Itbbky@{P7Z+lcKOw!gJ~ z&xSGl(Dq|AEeX1iY{4MQ<+|XXg1P_Tiy|5BBL^Fhqeulw%n(=4*1O2*m)6^kg$pyU z91|*Meh3`W?QSkLD&NO)P`H|FH01DAIYvWXp23*IpT@boJe-?(#jxaV4=y(t@XtJV z;}s64mEV-Vs6PAbMvZ!b^vUgSnDmyGdc8}QO#elBX=ynfM7}F;d*fu(J1y}BO0qa) zpZC|ZzAZA{=hcnSdAXh>a{hBZa&(;u)i}x5GaF^L{$#E$CE`=dH3h6*Wg)X^l>4x% z0u4P^KCg_2)fF%sNItLJpLH*pcOS)PXB~gpdD%CQ+&@zHLid-?v-?9YL!zkqzl~pLPS$m>ZRX$I%md`7zdi(Y4KG0TdRUu#R)RW|M zx|UuZ7Kzosf{3LaMvLe7Bw@Y4(fuXT_=V>Vi&v>~1ZY#D!t`neG}&Tcyc%0S`CTi& zLRHoK=Hz<58lx#yX~oTI3uIzDvvXmN(&i{JGIlWE^NXb*S?sk~5>BzP8L>sN<*^O1 zf!My-U9peE9*;c}dodO-`aou~UJYRE&On~H**Vf#T31!Mplqdi$T_m6bY*pg)m3L! zz1O|f>aZ>?uj^vpEMr@x7d}wE%rs~+mhdac1+0k(ElA~aZnX2W~nt;Qy^?m z{&CK54CP?b0O0g{A!58@)*~;zG&0n+V@H?j@W{wuR~OU2svMz};l^|Co@5Rg3_twq zh$bdTSl~WER@S)s4Hlc+MXw4(qD4M4<)OIEurTFL*MD?P35pHJU(bA(-pFT~|3*G~ ztK(?qiOgp+FQMj;3mYRfC2$}emW7aXAKKl)L9u=p$07EAS4 z7Auv2g&q&OPl054?i0NG6s^U90os6cBbYARg;5O3>_V#D)5Ks~)w9mAOK6b`uY&eS zb(I|}^%Mf+1E4}eXpWK` z5c$`VB?6kmVP&jw% zC{|rB?;u00Y13c>V$(#t`sv(@FKpT>eagqe!+x3DE8b9@N6>UYnPoIs>+Wz5Qjj@gQ)}KAXc~8ywm>aQ5uL;I5rEd+W|! zgM(+<4_EFS`t9v)Zp5<{kF~cSt{5B|Y;DCy#o_i-LqkJ@ZFCE1^Rn&K^Je?9m6Xi% z)O5#P|B`O6B8gxU-p9Cd5c#+-oEt}J?C>O6V$JyLDeux7LQQe=-VnMeWhiAd3XG#+?M8+Et&}_KwCGIkL%wF2|bbXA0e`!bH z4gEJ_tMxe!XKS%B@5!pWIs?5+o5Z8Fn_khjXBi9gddl(cxjs*6psvY+N@i@|2mI6E zC>>W6PA2(5E@)E3-&Hz{gmo$sOFHtAv2c{ifB=*7>RA41>3oN-wJyt7YJR#y_+a0! z(~3q?&Ba*~$}Cm$@F6|;r+^y?r^QhQd|omI+bG+NJnk_AoJu&}aDCI6>x(3${Hc&R zBM<8mDqvsq_XQAG3}j;b9)&_MiXfvrUuDGo^+=;($?}>hw3-$vxB%Wl*v?2*TbKqg zs?SZuf>bMX34w2IbH_vwEb0FF^W!f(^~0-&Iy#Ek=Tf#kQBhll(6 z5I0b;F%yu663!nkjx%FSP=F4sFklyID-IjN0e8Zo;3rBNN;o|h0Cu=UMJ45A*{E(t zsGMGFgS9EhqSqgN2_dK5VTNMRn)~RRMBLi!wEVo2*Q`wymU#BY`P=4s)KQ;v00ghg z(x>SizW4R^YSF>oE*~}Hc{^-IrJ)lN@_CsP!i$n2uKtKJoLQE+oga|e9N^KcKPWDBArHWR?k?hq8y>vd0Z9BFLe=Nz$e44 z7tp@2_54GO7DXnEkiLlZ_@fHB@NI0Bzlay7EpwD3{wG^!Fy}3J4D5YUI#AG`&tX*v zDZoz!Kg6=0!N36!I7=aQbjLT55fFjEUr=dyq1bI~eHfP$-|!k#Wf&B3&eWS|K$d&JlWpUpjDFe&3Y*?y1w_0Ny)w@glu>>UV;L-a19^ zpAstCe*SOljZpOdsTMAPCRFR>XfL!SENZYe8R2mPz)r9y0<>a4`h?dGp?l#cgM6ZN zbCB2aiNc4{C(^$U^2zLj*A7bm&L_ho`H*4M0(UvH5U^%+FsvV8zj)m;zq8I;d8hPRE3 zZ#M5n|6!mTW|P@&_L&>atI?KN2653Hg5`Zd;#j~s$otZb6|&%Np`oy_&{J4f=tmQY z@ePFo=quN-K1%IV9L&|KC11V1vH#VlTVASFjT zZdj82_|Su8yPr7U$MTpjvfSoC%@fi~vkA?!5eurSmm?O~ciMGA=dkPl1HJeZVI2hm zvqWG8!DD_QsDhBv|FNFi{|CMJZtuB`W_(+fuG_N+j0Y=Nz=I8kKaQXiO%}qI|L0n0Y!y(?SUx zz5DNG%)JKE7FafY1MOkR2eQ}aC@+L0S4g-jWYXNG z$^SxTKnYjL3*id(##M6?Dk@1y>!v~rOX&TiNWb_auuP`w5X1t9(!VaF)UpagMPY@f z0_C<9#HSSl74YA{&ed28dZ9Vif+;%%4`KP3M0WI-Vraf%DhbkeYsSiD*XLxm{?B{4H;E-^DeEj`Pje^Cby!Tlwfmq;Q= zVJn>;S^c?OX`B{LMY`+Xsq;SEQ0$DUMS5qp^S<0;zy40`_i1~cU>o+#ycYbRT9T_5 zH8(+>3mA=)b{LGDA6DGH_H8c_{8#lWe)+O%Es(Ps-yp8*Z|NEZs9LpS61ivEN z7JzydC(OJ?dTftHGI{^cv-XpI zWOjD;Uh7%UdhQp^HJG<%YSosdcKgyTRa4jG4XE9NW9zc&T3a!U)pBk=eC-C6Oor4GI2GjNr&H(!gPd@1eBA zJ%e~49NKHQ@aCvb2~!z&$Y5lVOrBNgDTObb6fZcXPyq^Iwdv+`Te>5?EPWwy?Z)&? z;Mz{3A60;Y?EH15f}+ByR1iDjE|Bk=ysDHTa}}te{^Z&7qVq&Nv>tV8OgwRQE&l$& z6RvG(?h2-cx35^epuO|tu3fHVS;o|DfhYbVEc24T(D^ve{6$m%V*aAnk)ksu?w0(8 z?`HlY?#6ZZvq!A{o@ehopFMFmu0!g~1;wUbMrP%E$lD`LH0nAz67e9Y>!6%y{6wMW zmJx>J6%yygkYpY$;^5&PBsrbJN}QDPDaOlJ$5C)WQ)^5PcL3rtObL znF6DNJi91d`FFj$f_-B#V3Q-7DiF7}7RMPpdn$071^W~efy9^!7DdqA#5pIiOezRK_MUV}alvcjc82fw6SDPe&GeL@E_JNx&QF;s(y zG(`$dg!w5AKQvKaLXfS|>eaEy7It0|C#+xyRw-zBg}-@4zcN{qluW7;eW8?lMg|Nt zCj=!MZys+O?-*Y;ej&ON_BW2-gl2`#i0JV|q+kuopeUb=_6$;N{4-)RGBOG?$}?&+ z5CfW$n1P!>y-*BP)ZSpP#WyxwP(x1~s#Z5#XV(RU79#%c%M;hpe8CHoP|y)pP#rgP zIz|{)F>)QJ6{dS5EZdNX&B}htB}EHF#9+W~i0}$(c!@~!0J0#T^2Z0*=@B~uFF$r}C$G$-cD{z*lV{GH8G0M#77!V>4QNUISK|<6 zBjOPC>fYc#cq97gQBR6M4r9O?@nVdqPZjOaqQc9)Hfod&FWF6(Lj9;V1JqoU1HMM1 z3W}|P%@HYvk$9Iv>B}T^P=QY>>PbwIc_0=~5%nX@D^8pk?CncNm7aPC5j^M)+q|r zKqQZz``Ne-E_V?8po_WOc5pdL`@CK*2cEz=R)Wp3d+6&mF3I4Cr%?|M(Ho-|HYwmM za1{IM$>unmi94_9Y_5y6E?0=?)C`qN*S4s61X^WC4(DD`G<*OLi9Q{D5!cV>C?1+v zcQjBA;#v&S*x_T*DVtaEP1)*$5zCAFxpURMSBf?AV%>@*&I!q^FpV(_BR`bEy-N6? zX^|IE3Pq@u!XwS=^f4j>K*tM`XT(l3HvrZ6Jva?@JPgB$TBV;T)Xt_%B%CPWXc{B) zmAwQKjw+WFL9PPT6R4aFBGi%D*ozo(GW$WKwOr_pV6H*oy*_XVqbL-m+M_U^jSS|r zG_v`rHKn)DsL72OeD#gf9cqW{wY|O4vE;64#)DrreBt`ENwwIN6&8W_eEd z`M=to<=497pH4OSExLANKgMBp%y0FphxzJkd6lF~oW{e5SqM@puhHRKGEgR2@`IN~ zB}w*3YwvGpF zRk~YVvmGfdt)YbFSyN+@(3m>j&0R~896KN!TQIxGf~}tX6TcN&lbDZOSto16I}g>LySaIaivo@=CG@{ zPItR8fbMqhHC;6fV2{MTkTKm)CV56YS(ljgohFG{+|3d*AV;{^qhAGHxbCHW#v4gu zCh6x^cdsf^r$9uJn4tI8g@`Id8!rjKOSEx2F8s;x?hFngR_+YvFEB+h!J>ec0*6Xs z3<8J^Ew8@ubVq0D#@hNQ*9Os}y_3k)!OErOhBw{K+Vwd?pGs5?>hUY+d`XfSe263S zgn=(Sl-pp!QicrhL}DqBl)bDaUM-BIwS;ez3*ZmTgGjZ~d=b7v(a)%|(cc`oatYdQufZa}iNpB$bHRG*3C=i!Ybc#IE*HyMv_=9!G(F|u{>47yw5F-7R2dkU_K zdq?p2Ddsog$r6vnlW88}Zh^;fuu*K~d7u&F$UHm?Ofp6Q_i~}7zL{Qrn%zxJ^jWb4HlBm`S$jl!MUK(e7Y$b;LR{9EFZ@N38?sIzHRM z=t}yUXQk@Dr|o#of{oKf098lTb@m>g)3vNPI8KkYii=(M_jDm2{wsEd`qfNSe$i*= z>JnmSln~VUhPG^vv8US$?4|Y^RE+IkX>Ua#S<bA&7+*NPe0(hw zY)Gb8LEfY6r{>Y^{i^mh_S%+70_LsnR9{z0Up@eb#Xv-(l`VceB)jui#m9 zKWk3kLKYgGMee=X7ZFO;kVQfgG)Pv@DSQR{4Q3t9LNgl#aR&K3$zvzQITX7jV=gp& zj#WicAbFfgnn6Sg^kJMc6jUO`o|SL%tP5!y5;yTL9`m#hxM_WFFSV_Iy0=#=c6Fh; z*_M+Ky3o4bm5R(RV)&q-qJvPfvbQhJqk|B%6-X9wOhqupAQFYhhF2(!7yt6I2D-gS z!G2`Vfr*c57=a@K0MMx*otasUhY|r<=-TbIfRVb9pH0rtkRXX6lNYs9P$im~wnv{K zz0=Uei(b8kvQ7?&WW4q3*kJoh7JkEJ0b7-O!3CG%$%YVeB(vs;SJJc0JaDo3ql5N3GAU#N#yl% zSV*2h8BCx*HSq$9E{a$zLVp~y{<6bZm)U5Drl1FbOuap<}NsatflH@6>33tace zs@%cQtm+xlt8WY)+;UI49%^bY?Rsj1q4dh>+~&naMYU^k4dqu(_kWhfhHjF}V7-Ta zm8d*}n&y;mGlp#VPJ%3EIuB=Mfj2k7>qIXCXbl&y$*nv*~!Zw z;LgmU6U3Ap0vwbL5=2Rz29To6QMM>YR9VzQcuM;lQ8nKUqyiK!r9*&9Umlh0JZ%5- z*w`c*RE^mFxiOVCWu#LTg9eh@IZ&>58HWlP_kSZWPV|{#9I9p9$91w$|dJ%bdKGt{U2z#D)xuGY0$xik>L&szZl045`2bS-?&+Bfk z3B-3lHgY#4$R3g)0VR?*b-5SPOAkpexGMPO2#35bzDe2G#(Hfvs_DyoI~DGIcD$~> z`LJ&f`%m#R+_PZo!HSLT?0I${4G9G^^S+^w0Q-rozHJ>U9*GNBj@{awz6T)kJ3Z z1&Xe=@ZTCas+v+1acW1k9>@;2Fd`G97Z!3bdf2B!u?|+rr4@|ULdhlH(vn_#ZRq`* z59Qugs~%#=xW(8Hq2vH>c}e z?_3nefNwlzKHmBh9+C+k=PV;TqKTzR<$?|s1pRQuU;5FCWhno zDVTDy7AZn2ClnYCfA)@RsoK5ZP-oT3#?Fq*Su?7$1_r=4v$DH8E?(^DRvVrDK9;!3 zZL3!tNwwXp{-UVd7VLUB*jDZeTwd?$x{c%oK!GCRe3To2XOKe0lo`kp;!;edC`bsX z2LU!dba*|4*y^h&hoJ2=#PuHnFed3G&f_=@pkH5^rE`^r>6}^U4Kwt zhdTph)b;%kYhS8YKh-^Bke^}f^vOA8gh+zJtB$ZXFG4k{ZIRE4+{V5DQGW}LEt(gE zYnm3h?Z|0I&N>vweOt4_bIev5t_EO6)Jv}(^>PCo#;|XqZV-sxTcozcvX?kECN@2` zAhtBN1`TlgSH`xYFD@W?DurTEQ#Nyr@PHIcN@hw?N=3>d)PECTWP7(nHfdu(%rO-s z1<@MI($ZM-Sld{~*s`$;$C9)(cGFlq98m^nH`w27Yexz#R9joDEyGr5E4S6!NVO$A zy*mHZyMK`Op8C2g({;IU({tOmKX+FF)erA}uFXCeH+5re?Z&BbaZ_7RL0tRmnFZ9| zY~#S^Td8RH#%KS1Yi(~&O-)a4ZSBc>Q8ir3ALuQm<1M6au{^Kskys-62;nQ}um>yg zW+Kc$UeWG&?KPcw=r{te1Kx98o#7>9<*U7rL0ZH8+5U}pTRl3%ANtI7yargYPYrYx zX-gYjzK9hC`y6@~HhDVluO&u? z4;lTx{DKO8d7Ob@^vVP;2A|W#jCwsS}bjkIu9wKW6}QjUDR{t zFM<4p)*g=hGCC5Gh#+Vg-1_*I!M`3q{)M5%m8HIRWhah>lal;KC{zII=ztSb!slB= zr1)5{0|2KV-ZwEjFZSg%Rj)0PoB^}rV)%Ztae#HiNd2j+Q`n{rPPa*#WG$VF`$3+G zRPNPn=P;aezR@WabPKsNsN-S8cY^H$<6vR{^M{O#7y^(J=>90wAOqRGJClb+(KODXLB*2V@^02v$)}w^{Cuk^t4Q4&c-mqE#J&n4_ zLqW5cEjEk8Qf66*HuC+AmQCm`Pn;Soy1&`lZe@~VjkRW23$5kWS}Tzp!&T|_SCO0K zZz421zk$q*;GUl{i&6lo<%8&q4)cwhLx{zVN_o7FzrKfz`^=;SBQQ*(QrI}$9vKpW zz^n!@uMBfYc6|_2BtQpk4q~Y&$P$zpR1{PZv?vHcz`(FDoqKz6OevWHt3WJ?Z=w^E z5PsOK^_A=h_2lax4{oLGh^>Y_zkF`!Qyl$z-vvfZGkFH%#U?Z&}nEQSj zIl=-33?(=4ipP=Xinydln)=lYfx!aCwTAAq^O`T%VnXwqO|16zbJS zgr+cxmViy;8KX-g^!5at^vC)V*>2^_5ts_ut;j3`>f}q7$^O-`n;};~^p3T}X2ur9 zR>UrXxIsTeYvTAIVhW%Ki7|=ki3N$Ji8Ux>*S|8c74_}tF)0_ER=!7^5HH)N+zn@( zFSWsQ#)~g0;)|8P5PFiQ0?qiinWh85PYDLU{B-KmmnORN8Je`okU$HmrtbMum z{zk_u%W7(t4gJ&NnwrJhfn_MdA2u+MtSZmdKmM)i@W&5@&+j^1-*_Nl=og6(HLrRo zQ7cL~fSvpRz@ey)IHgU@)(dxJnk%1YFGeC`gbAgbM($ZalmW*TL?7D-WFvDjAWB^t z#Lp2U0`oF#UkLL6BST~$#dwf9YcQ~ZgG#(gO)%O@{kBiLYAUN!_QrxPo^@+WI=mwJxuQ3tRip%jg&c4H}er)1a}gvE@mKj?iO z8t!puxG5^xWi(36$5Tk}-NJhB_i@!%Tt%EN{OWx52P0R}*W?4TRJe8IktYbv*~#|` z&6%Q8kHaq&30eIxEMO>;hLeEQ8Zt|l!l+CqL1|SepNnXLSJ6T?=Sss@68um}GEg%O zAJT{`!sY?4=wtS=`8a&ad=~l;SM=HBgOg?Xy7Ftz_%u>-oe36p!>8~kNawl**l{D; zSmR7F=R}%Vo*~kzx3L*8=T_RYD~mEsrp%(sYP0mu(k7|{!N5k}+=zHB zl$8vR(aejs77tFl{ovxI2bv07*L`nq@w&a8w|8vWw!CiR^61NmHT-Q{e z$lATl#gkTamNfq$E%Wh?1>2Vwo>_fc{q1LNuNgbdVU4rTa}3?No}^>)wrzzaK2(|9 z$LHG_)2x(&Oj&jI1PLJWZ#WknL9otolnAOy&{~x%8dkA z-yDkngRW0zu>RHQo4KQQK)NM8GrcIiB7G6kDkzptcIfs}GGuC%(~!&tBJ5HGm8y+s zM^{Ryr4g|a84-mM-izWvbhrH3{YYul3@mA1}1 z+Lo_vQTMHVyDn?ZJje3NtmMo`lH$;Bs;a8?&I66h9%-38x#f{%MfH`F;%4l>t!evq z+C`#Lpe9+$LG(}n1bfqUeF8*f)cy%@Rzf@o&2eU?o88;ZLY~}i2`IgREJTbTlBI*% zS#0zViVeyLDhw(QswJ@za6)b|D9#x37~2@fn6fbo#}J&*O&-w&nUNH?2`ZwK4L=Ta zfqxKgLIM~&3e7TIh*Ca{3#XB*2=7SS3I!JSIFnydbBQZwzyrre4Qpyyy$BXtg0(ne6qIy2H zK0t{JEzRX}yx-(o*=ruhCJ zJX!DhI681oYu<{gT+JDfo0SXEo4TKKT$qxiY^9<;08BFT^Y9!hnCMi(nU(@les59i zx>zCWyb?ROB)LX2FlI|>CLh3L}X9NZqvCo4EMI3u_)xIDNv81z~(uvp4YauJ|S z#85^+@i(H^14?<+n|IgVzin_@UQNSbwl!*Oct+CVY+Jd*YVfUU95{QW!tm2OX753& zl6E{R%hz};G&ClQ%<@Vm&P5j}OeCb$Ol6mD6NCN_vlxUcm;l0+Q*(vc3FIZZ#;)7mY+o?!LBvkQ`6fF4!z&9nYj06&7Pha)Kd}7;N&5218fw zs_$=Xd8|1nr}?p#mM5BXT-B4R^J6vF3@tW)!KC5^_+CA&#TG2kdiH+dT(QFW#ohAz+HOT@FL&oCU4-_o`j_nK4j55H-+4;T=k%*GA#UOeeI%$vM z^>I=UNrX6o@O*+Qo6IJg$zdupEi@5THf=J2Dl43sEfcgY7o2f^R40J8nD$t2%|@Po z62N)4QCA8-x>3{G!s}{g&o>VaMx_-bOk0XmX-$fYD$GlqWVb$E)jZAa%7O*%v>lys zwyxG9hiYc)jhjKmB1f-l74<`>^wc%043-A|6C>0F|G%gZ|}w>>zq#t}E8WzW2-BPHebjnive)^)u5?mc_e&M6g{;lAE{ z!|0n;)4gKt!L-n6HOq6Vx@vQ+))QmnR?S&-$C*1}0VKcnY1U|L;I$b!y_sxj&G4YK zF#ml`A1j#uusI&xo{9e^w8D4iL5L+{NJ30R78bz%W=lIPevscRv6c)=p{3kX3qv3g zXjlMo0<2~u_J9FApDsUo5wf(E3H%HS#0-`O^nbAej714{Lu@LyIk(*2f#fXA2kCmWc5+RXI z!sYAoxcz;S2*(hq2AQp&s_!x6u1eq*S$XL;c*b=dML@?lIvVmC^<|iL=fS!v^gDk! zxB0OR&ByPWGMHFWH+gAiUH46kCnXBNkUC;0t?TWsX3%U{khAmfiw!yRC?cOvD4>#} zoFu^voEIV)EE`cdDl*Gv z5<)Vu@s!4=P%~>b&7qZP3pGLvZIdQco@zSNL`dlB9#y8oj7qw*$T@ci3UKtc4Ig% zcET_srUCjyCPkQ+AQVA(DNP?U9I^nTrN8L$o{ z0>)r#(_Xes&l@|vno>U{X(^lwQPbw%me+W!ZN`kQ zlj~MHJ4??zwr%q2s_d-F<&NgwB;pyME@&MDKJI`u0JV9n57q>B}*f93a||_2ibxgL1jS;p-1&M z25o|R1^EI@Rx(}0-2sdaLGIO8>kq7-IM}(ke0j0On)yOzmVINddHm9yOSQ>EKVQDI zWL0PJy56c;OW*FOe{TOW!Xwb0XK>0Wa^ewaht$11AOyX+`+P!R(g22xsvru(BFIhx z%($Z$CxWjaL+5^8`ydIDb4&njfHQ%=kf@zXB2{WTBd>pIY-&boVQP75Esz(8#1Rx4 z84-w!Q4LE{4b5m(8L8Lyi`E=fJJ*z4=o_rv*$KmrxMod5&22ULS%!hKj$_MT zb^S+z>mju{w7TPP{nqzNAJ5uZ({LbB%WYnJ<#O`jwmWytCjI9N^h`kV6Q4u^5~gfGmv9vgt`Nkco&ED4KT(&uUVQ4WAAIaOq}q|p^)@`Q zTeX^6SD5<7(CVRI5FQgJFxDgcap`qhRU^do*sv-|{#RoeLEW5aGECr(;xB@^5j4Ni zma4uBTWV!6^^%YK(rrt9`AVL!r2<~mh3F~6Q_2M8MBg~Vnm#oInGJ~DL>^WDYTwPi zjQYM7-%Q^k-wNMFz92`IToT!UU*lrNrH?BZS30f+t>OAtj%!87IF_Mw%TaQj zobf1ao2+uu2S~{X+Q8W{m<=|A!%${eXrQxW*o0z4PD>0|3Ctnd6dt7;(L7r4>gGz; zvCW|nBv?Z0XrKxdCKr)q(}9X0#n^n7p%ROHRdv^{uUWyE{HpZ)Q6*U>EAM zL|TQ>hhqjsOA=l2xfNI0DvYbsV4G$cifzz8hL9|6(0ni3m4yYF?aE?L`07(^R~FW0 z(ziHfQys)r-Rg}UY{UB~R>i9Plip(#d^Gt2w1299N){0aBSCLDjcgTz36qRt6f5FE zXQgz@nupvXciu3`B}tyPXtyB%2cNwgqV;+teH(7;}s*#t~B%vk*<0`x|36 zp;t3BASy}G-yGl0Z4v$BW8*X83**bxK-IfGv zw>Eu%BXD!(t(jD9iwm{Jui;#(0g5cDqoi-wYx7%5lPykv|J&89b=3n$T=h7j?wHok zuuCs9G$~%T70@K>J@r7zRqpDG4JCgFxFP&7Nchjwk=n~!C8e^ybnc@0^+jG{M3EPW zu22C0ploxtE!&Y@mc0L)PD9upsqdq1S zGqdp6zPoSDkI9~vb-*p-Ab22NeY_`!Ygd zq3^Ycd?!Rf!8vNvMLPQC2DC>uu?7VhrC0})4LDJE)rr(S0q%J_5!HxHa z!yBN4AZtdPey>CrX=xMyL?zlbeMQv0@bg=!II36w&~!p$vL>#~}J+VM*pBTaqKG zENLM%&TCBC1XTbF17QKeAf%Ja^-}1kRitU^tF^=BpVwHEmsivHN$xWjFFrG@9L*}P z&&!<{lN6K?vRs>?Zf#uYTDwyH;Oz51dmcg4PZ9A63p{Q#-fr|EZ4rMM4iS(#clSlG zU&K$3cqJ=QgozTVjU?vxua4Y|d=0=P(h`{&Srl0jxd>?-WI=)ekK!1zNeP=+PHP-9A<8fc&9se@IJHX>FgLfSC?Z9=)0`jBU3B*%i6FkSz2vTl_r3x7l$XEkj z;v6DHOQEJlgtRQB%B}PAIe6`(j2~r(gXp0EJVo%R2q1O+YS8rpMUcAAsU<#^FP|{p zhVv(*g8$D(b9>iuZPM$w!Wqj3`BM?tc@;Zg>h*n#vdFJd$5mj0muFA1i#`M6E*yKL z$HKskV~vB0#Y>D$Hn>l5%h1kCuYLUS>#hZcX@^9(lCj=(oUj$O=2!DcB~Jp|u|b>u zI|7}gNQyvb>=fJJ6-_D)>L4Dp0StMHg94-nJ!91r;5&Kd!jL!7)E5#83J<)G0o4I1 z_qpH$2m+kR2x}FZQLA)Yz9#J-M&d2t6{M&Ek>B z<`|XXae_U3-kGS?YGb2A5q}Y|$$?avBf%jB$v(3$AsfVOG$RDR4>O0^!W>~`VGF7K zcVpNlv>@osF`Y^#W|7>^)tUX1W0NzI3zN%}Yf+uqc|%Szp(y&L7iom(tbxGe?|@E2 z!Z$S};QIP9jDsQrMUO(Nt&9@OhKEaA_gB{+>8$eqd0=H_>x!EuKDK}Q>dFku`0|{| z^-~d!6UemL@AaC{eHzsYFRhge(vu6F7IQv|CYRQdb zvSv5lq@FpDH7z?PZ^?J(Ph2%;ywUfj+S@%ab|elOr$|9$aSm5!fvf=QqVK3Ymht3j z_%YJ3odieCsrfL}{rC$kq`(f6j8tpxpt?ad4!SxK0D7gt2i11rQ4 zm@k|mTpx{$tk?F@0jHQyd8xJ(_WStwxundF34=0Ak@!-KWF3~I$Po(l|NhAQAmtyQ zKl9%a?4u>hj9}4!N3eTEu)8flH^85lg~I-vU?oCI#!+0+sb~l-9G^=mRWO34#H6IB z6r_}<)F79te`QK5Qmh1b@(KiQ8ZV*Nik6>EVUK{vm8d`&V?IZMWOoPH&TzqG=5? zYHyzr7dP#W+OF=*5epHeKM4C!#H6;mn`-VoSxbplhr2<2@P{)t|B=!4tZ6}N60sjp zp1dfv7o^?#QjkAEa5SfkGu%il4uIsE7rMIda6k%*G#qrT&py$XS)Z4M2183y(p(2$ zSCv0Ov--hZOTr_b3lFYdjKIed?Hs`J-!b(6zlouTPS177gOqB-`G}ll$`9B4Irdb8 z=ta5>R2lSvAw9;+GUFx1OIe+jT0cq%N1)D#P9JVeJagq`Qt1asTM;__mrr=e0g+1m zS8~lD&mh+f)hDThYw!i9C|f7UlGkDJnu@ft^!bpY?F?bN3d?-#UM0V!HJoFJ?75=s z#ULBtVG8=$T3FZB!f5)U`59S(I36FTG)RFZj`K)Vws`rH^@B1D2s{KEuL*gn zoL+f)tO$|zM@c%M$U)=?5+*Cs`|{M)gS~@S@?Yr{FuMFceWiI|uj*MJT_>`uy>={A z>=;$H!;XbxN_ypiYa7!Z)T`sz8?zN6Y}O*MxP*EEr#PgpdE(uCPWP&&$rp?oy6(vApzIs*#l3`JAU z1KAdRVZ|Ih84b88YcY8p47Th^iCZ2F#u4c-?DOX`?IHjU`_G0-z}X{B4LD)d+Q~lq z%7kYw4mQ?6lWJ5;kV3nSY(H4c3%m@&WhA;@m0P#WE4R)FV{8tYC$JPUHeNfuP9U<^ zTIBSvW5$LfWTzU0y=qWcs;-(TpC-3w>i*sdIn+$c_LgW9iHxEgsxSwkBsS-i8CX09 zA%C$p@H8>4By!$KsE)&jafB1WT=5$%ypa72&WNULHlxE>W?X0_*}}NV2rW6uL|&PG zYKzC>NqB5{MtEU(d3Y_HGtRgq^2&fduvRQ0n<BGrFqQ z%t-NZsjAB_ZANqD%oWMW3A!p=yK`OD1am>#bKT1iw9JcD2k%)hf5yf=bI;7$v8JRb zJ8MO%`V1?;`M2J^@7O|00iU@3;8KpL`M_`vHiuA(ID!Y8EKXr;WA&r>K!i)unM8sx zj!Q6*(z2OD$^tAFOQxmBQejy{A!RVFQ~SEFP$aKi9SKDN;gaX;>tcl=yj{D$5cllL zi%3oiHzg+_9?Pn-z(#=~LV$~U<)~SWRVTP!as58>$Sc}Z|7csnSX)d$K#Xl{f-M@o zJ5eQ|XsB+eURyBqyw3cUCIZ9^9jN?FkQ<3x=;|r zn4C%>x|Gt+^(_2TVpB3w3RB8cYN3OjiZOmpT9wn5uhSR4!O%Hj5qff>>a~>9j z8lVLd+hb4xt#!kF+uOQ2-z;f4v@~aOZdPJuQD%KwXW96ooNQ~(yh&Eu&g$jII!a3s zn)GiUtIu@p-`}<6;fJgCec^0~utdZscV|zFjE&4$`RK;FrNyl$TbG~cELY2=zX7J^ z|4aS`8O`D5MqjCTgA$_ProdClO|PnWgNOsY;thR=iZ^FY4t=4%JEf~(a&6rm8!lTi z?PFXYsOB;DOiT8HO4kc&QRMDppA5@}yLyY%)rQ;Rw=AuZbXj9*lm>qu_y3lntd zmE!(Jt9c_QEtNOoy$I?Ar@<7$t)k|Q;mFCMK$e}z-+(7wx4!|wFYq@oX&Bw#Am1;| zd{_A!XeRc_20Jn(uE*VwIIp9(lHed1xjwgk6-VuPoQ7Dg%}a@jysZ)D2wQ|B zqAX$|G8Fq8BQ_y%kz#JH?Wo`*>n8$8-C-H*ozSyP5i}(Eh@rC?38m$o#~U6WEIAzi z!19)zP0bHJ(A>0b!`aynO?q+vvLCdUYDZ?YnIhWCr?08Bt!P+RFukN8ecC`l%7o&! z=7t7aS+mqTvEP4(zd-_k_f&phxe64YH~8=IHy|OTOWT6lB}a$ceS)Z#wfY&1Q@-SP z*Jt?;tMm^nVm||)itF<;NT~b+{0!8{8{v;x?pQhPehI-Atl;nTGsuN7vda%%CtE7= ze`f_Ct3Y2lU%MxuuVe%IYP}p3Gcw~P zdX)i@my@jgawI>Pbp-Z`A|WM^do#o52dxmn1mLc5WN3-ojJoNFyNa{KWyTf7Rm3eq zIdu=UP)?1>m;At*gG@w`%!+iWYwLdStWr~XaseRx3S2$b9BYep#FoV_q{?lLv71m~ z#TgMsathhtqCG`aO5zh7T~`)z2aDUQ79UtYWy<;ki>um;2M5zy?5%tDwAx$J3`eT% z_KGb}u3iJBu+WayvKun9k8a<7EDPdzfR* z8RkNBxw#fK)19UeN?j+h6s!-BNj4|jk{!uq$qV6}?{7@r1fRX0&8R1*AVEh)b)u+( z^m=Sr{KB2B&uuF!Yd=!AbXU^TPj6qFb=%zh3G+7;uiRU(ZSl0yuKo?HpWIS0Z_ajC zRmUD{J^kd9=OG6nWMZ;&xydhA$z9;TN##nUn&h zOie)44r=N5m9ae~JEVkjO8jH|)BOwlOZ{v7Y1{o<{YeERGo&+O33VF+PX z$fgiFbI~DK2RhkNzJW7Me6jPz-kUA}EqiB>=~+Z%OJoaY!}tg~LIl0)z=o3qE=@bW ze(GwIEykP~A08f`iAZ^qsWQ`1U!Iv+Uhl}PG!2GVWEP5#g_#xM;hwjKYvLjdpa8ipj_|6Elgo1bS@BQxr4BkG^38V$Hg7j$*b zc2#b__(G?8WZK4-O7&R#3m3Ny{Nfj=X_Tm%&YbD*M@6GgU6)AKBX0~=^Y?jU|tG)DVyD8@r7{!e*hMxBaVTeyZdh6vth-WUiZ9qX#keE(lj&h!Ykz7w>J zbmZ&v#mMQf5F|gagf2fwTK6@+n1h2?>INSX5V}%FUx}uYF9!1nQ#O3n7ej@0g282A zWDJG57BmH9!P6Tf-|oeFy|zyx>sP%o?&xOr$ymb&9~nG|7Kw5PX&2cUBkEEUtp00! zF>=n*R(!p_m}qG0YU`Vi_xB%m)xsB3KIzRjCzX@1x%0kVyCJUU=aC^r_d1`(eE*Al zF>=CQmI!$)n8;qIFNRmZz8Eaw#aGrm-alAAY0a8RXv~O%S-YfSUeRD0$pD@hgF24hRTT7gt}Gug+ycGIDm-MM?D?L z$K*8`J%1fulO#{Ci3GaW86Dkg@-!UZzCsDmtU}}@L zYv;}fK=+$m4{O`=a(|Ueb@70$+-F<;gzY2934&zVrgwR>q5G?->44NN70QsixOFD- zP*6rm<$7^u{z9TZ<&IccX-d=A#)09|j_;-Rr$QV{C8PcrU-*O(RzThPd?-5A>7S~R zun3Zmtek5kZYaH><_5y<8(MFWx*mf-;Ra$nG&cT7_b-4vk=l1V2+K{d$We;Y4fgJIZORm(QDQ?_R8h= zMT=Q?ZA5yWUg&wq{x1%Fs6V##Bb(|-hg;Zd}e%6 zd`0{s%IF2LklB0OjYp!2R3w-L%5wAkLFVH4CAUtd;6mUgk)S-bnXv)W7he|0sdsrvDrSgS|xV zA*2DzHxhog35>AR-8$2Y{)b8Wk3wtx%~9=WyaYo~RBTj6RAE$kR4w{3(Fqze3jO!W z+H(_qJ#Ei})VuTc+!X#WQ+RNB_z6JaDQk}`EbKiP;;Xv%fO7VL1J{wWCwJA09C+=j zn>G+p_=cQ4p^xbLbPLf=`@HJv;nL#5GD~$UuJ=81x!3g`WZd2d0TuPDaRxCi+)smz0B*nyPkq_qt|tOph!H-6HNwy zB_lns#4Pc99#5xwZ{qIx9(RjwiL_Q25=ZXVyCu@It3B?r-Or+^uHAKTOul!fGA5;W>isBMbx4wA~fAm`=fpo^>kG5 z5;)DNx&s2DAlt`rnTJGOnPDO=4;2gS@&l{C@)&p>bg5`EEte_jeSvBOMF#8rBqAu% ziYlFis-O4282Sbky0Z9(#)f8u7KWCG)`m8P-W7UJ=)MRv*gUF7TO!vEGODPNaHMZ~TSc0uJU{i&!YCh|xQRuTQ(siz{>4q*cS$Z@bVt%hbD)ui!PentJaf zDUp?Zn2_!0u}ONrZcWa!yT7FvrRY3&^akB!1?NxDDDfHPxkw725-EC<&NMtp|A~yY z6GeILMoaQUSczvBCEuIG-%LzOnm9XaRz=oq@m-h0(0bSXL0)rdFX*&t*(9=-q?;s@D0PNC4(keogPw{C^w0TH{<&3y@&pe#Q4 zAIT^RG3Zq_d#IbnqY_&+%gK``UHjcA3k+72H1yS@=O^OneI`FDQX!s>=i=#j$5{R8 z6enedBErRvp{GDmv0Ck5dArm*uFRcBvz+Xg8J2f`WZq0qLth}|4?*a5(qLNS`k5dhx+>~ zCF=4yci%myvlBm_*U5ANv#D3tK?W+-yI`qr^#(H(5EbnYQ3US|kZrhRc6eWq$6f@{ zUZC`Xm|mI{9dpUXk8Ls5Um9w-r0!H_s5{S{J9pyTIY574*kxP}sVh;*P#&W)lQ$rF z;w|(}7WI2iSy4h&1oDC^MhAc1|5EgC$!uovtf@$*wC?Er(LaiQIy!iXGb5Ffdjt>x z@>6M&ax;M^SBA;(`4o$1CDm1?Hq&;~L#7{^erf_m_?7852z_;?_@oi#PD3)555ZbL zp;UlMx^?J#A3qhb&+uaymsfP1STXOu)|!|*!lu@)DX#2VYEPX}SCmrOQEPV{Tkkr# zOFi?P`s(r%UFEs8owJh*>ZaT5OS>wI*3?Xmyd!2o>wU}DsSBQ0pW6uy{@vlT#%jZE z;6*~85(Ma?eiCuCCelQj6>Lqm8a7)Y}>l zt7-FgHcxVG(bBZfTh8yTIl4++qAqQIVp8+Yd5_ZGmjfN^u=jq-RCj+Hl00<<0eg=f zKqoc?iF6vqHh2KB53n$+>t1@vx91CzGU#{ssXj`) zXD>Y#SMdvdsz1&Ykq3$-RM%;L9(v;??X&Y&sCx}+xS?X?XW(-5yO29P&Yt*PIY|i9 zn&TzR^UM8)gY;Hf3ufx0M2yU|&!D?yxpguoso93Ye0#2}IxkkwYop)r3E^{Y$ieK~ zZ$P3o{lFFsjrcoAM2fCjX+q=caV z3?PmjzS02DNj%{B#9j>vu}1z~xNXq9k08P@At1^b;CF*iJ(8hF+!&$Rz&@&<0OK{S zh7a*&aj`sMKc6fP}jk0b%MFhSPzs3Dd{u%i?gRIT0nFa z|EY5m{WqLAf8N#e(o6IdC$Q@?%$0c86#Z1Wj}+>nlDU|=gOOT?qA*79-Qb0=6&VWw z{#wI}HSBKZ`SZu=75)m)U&nsTGzh(q7=vN2A)70dK_!g4j)5f0yeqcBNOH&whG3-l zqfHV)$L9iBT>@Bt+i-(HQ<4$fe?a9Qg2ZnmB)dW3uk7E7kguhuRjzHGVi0u8m2+Y^H_~>r1QMt1SX^7-Qo0)dH|gCRe^&o7KX2;fm&0brZ)f-?{u{lGl}b0{OvKr34|Sb z5wBF&`6PUK0tc9vhI2do1-KV+ShzamX z#soZJYOv=q%3>?+{{F-_?)`=4IDTGx=SmGAOcVnW08_*uCBH8yjDQuu)Cx`^Iypck zBP(vi=CF+bDf35w6!=P{o50B+4R->bz)5141kRyw7YrIqx%mwQ&xw6L9`67G&^tiq zbVi}WlF0$V($^p5xd@#YC&jy{YgMwH-i6a}iI;NRSbZ4?iJG1)c>s>|t`hw;KxqK! z(_f;e0!v_hJ;A|?bb`Zj1DMh!9T|z{(%P8bGC%R!IU%AEKf%5UenL!HMu-sLU?cAiKrBZi>XuU*Y~*~7ydAalb*%AYr5=Po zRLns~8ZY+4BBUft>@KDW1@c)1AvH1;hGN4w?WV+hh~(UAu7VFsbMF0cO9!9~z+ZoX zQY0P79rq?lS8qQ_3DLv`>_BA*LUQ{BJp!ib+@1QY7xgJ&RN*avyd>CtrW1t3kg$+6 z<|$=? ziHFcFgrp&*L?J|xr1?P613lIC8QVV?_oKeIGz$lb{VdGO|ZtP7W{Q|#_mHh zIbcOV0!k8lRe5!c@8J-r(EpV9`)4HDlay*)r9)nqF$m-9^tXnDgo+&|TEe2Ic(<3k z-)kan+!hl7qeMFr`qe<54=1$?XbVvi--|hsKuPm*Fv!7|ffz#g5Ohx04g}`b8er0`4KTkJ~LQB19G@%|K3<)Fv5cZ(d(S*~) z`Bf(FLh)#js0o4c=6ZpzWl2GM&aRdaNq^m&80trurH4Z_tNVdnLtYS)pOC%rfjGDk ztee#dOcCWEIiVCGxR^Ckg?UFu3-Xh}%?wj1s`3Z+dS6YdXs_{PR71c#V2_2-IMTiE zW?o<#ac=>3h(qW5frH>|yFkbUC+CB8+>48-!ygZSj0)+efup+S=f%GHXv2s!J~zN% zc*-@_6{o%jb2yFfk%Z$vJZP*jL_j78P)Jx(VKfiW9FeM#{OwP5{|;>_4h-2kK z1_zZkj2tFIzu`D)<%TIsbiQhMi&(3GBt;wreC`Y|P*WpNuu~!U6lA1`WkGtpXf00` z^TYkz?k0%8Q1COz9@(jgtVbda7oaip|C`J7zIy4s_ujwjP4xwC>bFLH*Jc0XA6?I@ z#a?p@meBBG;?f4le2gEh`rsAv!RjT~5!dG;;f@|WHc<_BeNLwzwyh|`7JTQ2PAUa` zK>@@!v5zs3-@{aw7A8R(B3xB7704z^9k_8CGEJ4j)> zeX1Y0P+x!_f*?iaE~RB8+Z=EjIg-h@5r~d=TP8Q{oTsK8UPVoxRvmS{e#iNJHHO`f zl6~@tX4m7c@2@&qv-f-p)=`PK)Vr}{e4l>+cMG96`OuqueDvrt;0Fj#7;_)c1JG@O zAJNIkqOqpQDUiOWeW13wdd>_C;0(s~Hqs;-dtEhZ)TE6M$-z z8>)IoX~1RTt?YUA?%Hae-p~#+j&FYA#iSI5jf>MsVMmF*DO= z7R)T2Su?Y7=BAn7o4If1(V0)pB)8bi*Jg6emp~tuSb;H&J{&1b=rh-dz3$8KnF1uw zpavto2|2w}Oua=HdW&-4YduxzL#FmhbEU1)QCU{GuyR#pTjlo3hbn(q`O``=wO9V8 z63(}3I?hqPei3?UGs@8Sbb*n*J#T^;T|^Qz#Dq~#5%PZd`PuMA=Ks(w)Z=WjX2{#q zs%gccMe`a86K*P+n2=ahU>`GM>#9k%s`l#C(#b_*lO~r;vF=&-fF);U_tc5jtk?y9 zIhmcCmxMa1&>*z3+G?`pPPC>>v1dibWM^7^O7xd0S)r@vwf5UfI-Y84>+dMh-rMc^bV>Gr+Gwe6YPFZ%*HT{Ia$l*vwW-?TIxvu3 zqekxC_}by+%MZUM>;bnccYz1Y2hPJffIopG?rSqK(C0$^@6XhFZHd8R$Ti$<_=(}N z@kV1Q%GRtke%mL-XRXicz8${L`%U+I-+!F{-vSN>{3_tjfdPSOfs+G|1f350D0oBg zaL6qo_l7(hS{?dG=wMiA*!-|N!=5*Vm>xEL6#hW?7ZFcHyc;<&a&=^X)Yzy^QO`zQ ziuxRJ*~QVbqHl`{ih0~T&iwP(wAh`NV#_0z|B1$^w~pBn7aq4UZa97~%Jj+A{Vhf_|bJe~5(l);qWro5N(skPPm zZEKHppY;jr3F}X-KexVY{h!u%tsh(emTF85OC6J%mO4JQ82xl!PMewbY$}g3FRQ^SUp(3neOhtM{ZpFlk z%ay*B5tZ92U9$pbMbAo}HEventm(5(%ub%2J$vWu1GA6L{$Td!vxn!D%$YT3;hg1j z*3D_3vu)1qIgifyplWK>oT}QY6;1@?y0%Y z%za_*KhOPNb3d5-mwC#(;CbeGf0+Ns{2$JD&VP3Pujl{E{NF8@vEaD{=NJ5D!S5IR zX~ExaHr{NyIqqiL%@c0^30i$tR99CotzJ{zR{fpoUDf-me^A|fOW-Xrw_0VuL-D$uK8BYJvDo3URYSUaKpj}7oM+;s9jY1>7vv{ zs}?=D=)J|+iyyw#dh4yX{^Zs_*X7mSyCinWmL->#{AtPG(C;LyeoTE@{rLKy-FD|~ z&ZP^N{$bgMW$!Luv;4^NKdi`EadO3_hW#sTE1iu~8-KmZxN7C9PnyOxZEsF%9^YKt zT-rRpxvsfswPAJG>Ic>oui3DsW6i+Y$!neKlGkOgD_XaC-O2U->wDIp+F;sHwxRd- z=G#x*{_I9&U?lX7)dsp|jqrbiI+q<@G z-SXjg#(k&bJI`$m-`c$OmG7o}ciXnGZSC8>`@P`rnZMVuJ!1RZ?TfeXzbE{j@7^=i z?cW{QUEO_8_cPtU?*5nV-*tb~{lyOB4%3df9kv}4c1+$;vE!B<%XX~Wao3LT?znHq zBRh`naPD|^$6!x)&m%og-uuqZu$@&q_wIaUSKY2XyPn_mn_ZvY7kXdTeKYQ>yKl>V zNAG*_zW47RbN{6KH{Ac@`#;=0Zujcl-{1X*2jU-?`#|>tzk1+5_GIr_x##Mt`d(AU>;1MVI!b+sD1{3heR0Fn{t590SI zE{*?Cf4SlJ)f(j)$fKdSbP`bFghTxnE}4gV2+ z0&>BTa_KLBJvi(VpYZt|@t=P`cli0?bLeS=d*OfyRywJ}fb#C}75Y6y=zXM!--PoF zzmKMO;(2(QGW=J*rof;5(eP#bbO2B2LQSXV@t5DtZ@Pjj^6y8ulm8-?@1Sy@a)93= zukmcfTk!h|^oIfQ28@bw7I!O{>+4vtf}ilua9F)qBITIsrSNUhdx#82L1C<2oBD`tCe_#He8 zb%^S#i)j=pFR8N2wyX;B9~w=0lJY|J`uW zp+ood(2j}wJ-^~7*p-q0G!t}=+NRI)AYx&A7`g|C;ZLG{(&tLM=kb4dD}R{WbIiT?wLIK>mm6Gx-?Pj~Sjc(N2H{_-F3J)c3k z(|uk1)N{m{@*n<;tRQ%HCFDPPlYl;Gqi+wnb?KFZhT*2&<$&pn6~U55r312lxeG&MwR~0AmowA^bEDV~7%jF%-0S2-chsj3(^N z5Nv0m*xLvt3}d8X!WgB5V~kcJFvei~5|la;W2_Q|(V|3S9HYcwj8n`Q<1t=_4JH<2 zf?~m#sEomwgcEXENyhj$-)09Mv=}Hnt8^$jXXO)aGQ%S*igJQ*) zrKDmUhw(q4m84<3QAx*`qu4NxS28f>qW}7Tpl4tva3xQ<0b{V=M;7{RQ0_Ct#d}@pEOel83QG$;UWFv16R76kwc&@!yr{iUZ>e zr4Zvxr3hoGaudcfr5Iy5#?R0%Y9hu;WfI0&%4CeQl@g3|F#Z{F+*2^lRiUS77{;(x5EBxKg8B& zl-0^YjBAuyjBAxe7}qI_F|Nn>Z^{PcR*bhRbr?4)OEBJ{)MIQ>Zo_yd#t)TNWhur@ z$})^?%5sc%DJw9xWBdR;wi+;YC@V33OKHT|sjR|yx6*{M3*)~k-&UG2ZUOiESLHj( z8jM?&wHUvP@qJ~RvJT_-l=T?5D;qH0quh?MTiJ+l2gW~wkKBRrUZn-&PUTLFyOdUp z_hEcbxnJ3YaktWj@d4#7jC+)Jj1MZCG493q2W6kqf$<^bTNodPZ1D$Wzj8Om0~p^` z9)Yy*F6h~}F+Qqn!FWjd4#vlntr#E2_B^HWdl8`FUw3$ho2hXNWT53ZR zl9V=pz$BR_Lz9^>Nm`1J53i_Dxm@((<9fYb@Nor24X9871w=s+5d;yCrp2P-gSR3m zrT72OntkR>NE+Z`+wXpzeA#E8v-e)Fz4qFBtuuR%a}Cm;J6}b5pYt`O_alA8`Gs>W z(g&QcBYn{M2GUmx}m9xe94$^Vw z2Bce^8ix=>7Sh+AbkqygU-{=9Y~*Xeu(s0=SN7NbM8d?Jkkf87o5A0{>Aw*(!V-C zLHeR|H`2d3KSlZy(qA|)JNF>{yYn-o|8VX_`ik>&q&tw_k8i8rhjgcNKT=FCm~KW2 z^Y(rANnm$Mz;TK~`#$?5usbE-IK}z-F$?LhxmwnDCfC;OvwtiO8waAsgg;Y?}In>@;)CU1m$*BY{nUO9NL0 zt`1xixHWKF;NDiIaLEhdw}lT2mxRm0bHi2P zW5Z41YfBF)Ei0W{X39ckv&s%EJFKjv>=>L_eok4uJWxKnd~W&s%P%g!_sH@Jr@~Ye zSL|PLFpkDJyyD1;c@;Gk$5#wg+*xt=I}h5H|Kc4lBT9iC)%?ta$6xMTiJ(M8qS7v% zpm`%`e#Oi-cbbO-7X>Z`&6fqf2%5hNnr{zEaKGTG!Lx#wmza{ml9G}|C8w2~Q*v&} zg(c624+_r?A07_7G&j74<^y~*_qsG6IStKi8Je9J?|5nFKLj)jynY8>mb3GPonJzn z=S;*_8+Sgl^T3_MJI^3PJ6_oF{Ep{#JiFtWSMS{M^ed0-cxuPZJ8s(X-5r~ET>QlB zCk}kV*}iT2J==e{{g&-lZ$F+b_}TWMZCBub{kB<;&)M3)b;I}-<5!Mf;yB}%jHky_ zO zKl;?K+soD#9)TFr_gqbJ-~l@D{3iLx>2l^Ik9YA%>g9M@Bu$f75$fTa|GeZj4Z#1} z25*B|8)htuZ!T3UjpCxEAWbc3$OiQ`1l`(C-!^z>z{;2e>*(7C*f6J4PWe! z@WHNxAAA@5&1(_Sh{1#JhL70;&-2IdDes1lc@I3aUigvs!ms=~;u=rEzkd)OrA(_aZWJ1N`^*BP#I$ z#37!8XSW$%=vMfhkHX&^hcCJX^1seh!O#8<{Nn53b>D$;dmADWpEgnFK9ghz&08^6 z(6;6}k;}R^%gzsvHNE4yg235lRgTHLaJV_qG$!X%j+uF5a&&3sSYTdw=~$p*Y5SV; zuJEStrschx!b`*bvEH#@g?mLod{ftg@R-xFCV{kbP3hR8t~p*d-qm$%-!V4mD>DyW1*uf$7U#mjx}S8=8QRAn>G<%$C~oeu?sihofbH-_qXNVZx(0b zgGK%akU;Zhxv&kOa49dH!w2Q1<)xsotEqCVVBU(3HO(Ngw5t-zHHPru_1Hmoj9g!k zkMzcZ#V5`$d%H8^m>UZ_PCQ<7MSY#eFL0j~x7gB|b&-P`l<9k*rNDhjlp?{~ly7n=|VXlP+ zf6RUIUg+;lg6*!(p|AccCWtRMhvps3w=am`eu^_iumJh>_}9E33cEg&H;DdTp2-Ig z>HJJ4A4IhEzDzz3_4y4q!U;KL_!^ex^PMxLDw8j84wFkW`68zZM_X&1Vqbn{{qN)< z#6nXTLmM%I5*S_m7)N15aC;EH4I|bW!}E2>b)Zzo+ps(8!kFEv@YjHNE^`t5&quvR zjLZRCv(Oj;Ph&I><39~P;~3-fQ7`Gj+2}$YMQIpu)HI$g#{U57L{N(usuA5?g$V3w z#9WV?q@A{^^x91gIqcOr&81}+Jkf%LeYjrR`i;O(xO~I_aRj`?z(pMVSsA8a$95&t z`MZ!e`(*_EbSz@#3t-{+Hy^NvA^%~Ni~<+AnU9`J;rXt5)%M)HT~b3Wc%xVe(ek^< z%TdmL-LW(tg*O6W@R0!h{m8XLT7E4FBP!4Sp+>HR6bDgG4Vy}H=40hD6H)hmK%_op zTXz7?TEN-h_64D6jR9PH05$32?Zxv^Vyq|z9Dw3Qp(=d}HG$n6RK zDqZQe!6G%Ir%u7V(c*GK+rr-LLtkirhmoUIx3*$>8$r9OJ;)iB{1W1bt2wmfw3VZ- z?u=wKhyBhOkvc@%6n0b2q}0VB*Dk7+R9dLBoQ0`F z=PvS}#B<7mGlGAtDTPY=dX%d?IHuORG?7O;E-4$e*DTZdV}na0S2V=Wamm@D2WeI| zq@S}G^^hYz3>x}zPo8N7EPVEqr9?{<=8#)=1n@bJur0^3-v*>IGG%FY)*>d=4B}u9 z($bI`+XJ~ainQ21(OR@VN-xL8W9 zqhw+(Wu%e)Xz!I$Eobd8O35v$&~+UtWVzPl3WgA=os@-IWVXw4Mjj~H9@Nuyj>VXC zA?bXbaIG$NMm62`wCWG_ko~RFAy=H|X`59>T&JDsIPGeeO4d@M@+I|@EpV6MwE!! zKD9o6y&+VN2)5vO*3s#wgmRy3B}fUR(2BCQoW(%j5V%s^)p_3PUkbW8>h_M(lC_VP zd(PpiwW{~IbgC9<3Hh3;2h>(HVJ=#VId&!fJMqtXw*zg;cCq3u%gA9ZxT4juva!^# zpQwLow`mvHf2{Y~zVwgZ@T9BSlL3b_7ID1`P&m`QKDk@l%CS!U;mk*gTdzXpskUbr zFlo81c4$vp%k8%qYQs~gpGFI{E|x=D7uo~fQ}=UMU;Z(X+situ()wwyl)WzhWvYI# zW5Pemhusm;1Iqk%ntft9Cv~(fl(Sk9@}_InT#ue}04e53&=I5kVrg#$1p5D!8t0yg ztG21=w)$h&9J-pYezj`TQfPyYiw;-6{C=3u_*`pnwqz~xr~S(rigZt$hu)0-Sw2qz zrreqDG*@~y7BCf`wtptGjH;b1vG$j19%8X0KIK|U)}U5%j$#Ql&(0sC&_P`X(U-S1 zboFc3Dt29ATM>$`U^v={ooi*)ShcVImFeV?)*iCGIGq;gSRrhVJIX{ghV#GLUyeSz z0;EoAU)i-}RwBBN-j!yk?dHmkny~>_>Ic_+T(>4YJ+?jD=*o@rQyP{~?bbwV=kG=K zc%KVf=P^Q8Zn(zLXF5~&;f`}JM~*({IHCl&O6B~=@v;GBT(jy})PD8Pa9oSh@{)Gj zYdTh`^%Hemxwri?wVafD`e5zwQ3Jm3D}FV0D2#Y%P|Zf2QY~ny8p` z?ZbP!&fS<`isn!kSv!bT!0r zZAX&o0HM%s6EpFtXGU+HGMdctP@1ewk7we{qhn_}OReisJKO8JGrJB~?Nz$iS8Fq~ zG`?T_f5Q3t`)r~Q`C6Z2Dovw?siwUd|ALa;m50Gq700Z9)TyS}k;$I4x}Y%x^{7;L zbJrERI@TzvrCM97HJNH1&-ErLAfKEict?G(KAx`ga`n@$`ba1BtP)rCKiQfV>U^Y} ziTrE3evBJxNfPxban8-zxE!sWMksVuth%R~nUw)o{+xA~CQzTaw0|i{){ajKopy)R z5+kol8}+f*9WT~fwD>FsN=3H|nQLIqxLK|!XZF!#zIO^Gq)k_h7Ei96$uX_IuBr-fZw}NkA;$<9O2DzR-MN?sPSVR4NRe z`x%3?^Dr&7jj^cDY3GaFRe@?Fb=ztPTasJrMOaN?O_imc$th*_qvgu>w2epAxP47p zsZAE1m3Ho`aXPNEt^8h!f4!Ei;a{=tY97*voX)}4Lsu)JoY00UhdOdO6SMDW9jO8I z?>XYhosKq+QjKb`C$xlCgJW+xZC9w+7Xf&T+FRVTwCezaF%xQMue(ahN}altyZTcd zm|PyOSI%l3vsfmVH2cEZA6r*r4{vVt=t^{9j^0e&gOnKigkvY`-D*!vwsK;9wUX0$ zK?<2#zp*TPp07qdzF!Kv?fC77 zc9fikJI42#@VpE)Ix^*DuH{;dQbKISHzGPwqA=P~k8j?(@Px4Wj(nwiw*vL){ZV6^ zvF}XZXwgSxP0~k7+uS#H#L0SWK`vI|p7~{Xwm5@tC0Y?L-|*4fWM7fePCUL@-^rgB*V9+c)rz~GIGqTwUyllmGlpHB-#D5#oc9in{;wrS_9iOhkwGH+3 zeIp^0DpJcB=}N$8cdyF;l@#cEN|hBo}2dqvJ7JG;CXmO>`0r@qfM+ixuusyYh`n@D0L4~Q> zO{vVd)Z>roC-b60Q7xq!2PFCtFXHrN#Ax0Ym$@VdEl4eT}b(XqhM?zLA z9A%`0nAq36BLy6M@jJ?IUF6Yf#@-Nnw6yr;uqUFAq+@T3Ka!@sCk9Ds_QohA>6$K5 zv}fXwr0k7HBH3zhibj&2iE}1rOui4_J@H6VFx_0mS)6gae`Z9IbWEpdHj-)AGuFEM z*VDF+&cbglCP`W*i|K1@hNXK$WRi4bBZhk>Hc1*LTXk~w-+j?ZQo(fy-(Kjd%#WK| zGTHmXxAuE^q=C^};-{x+b#uB1CEHCNrPPwCXlH-#&NwBhu~BJ%q>|4ki&iT2dq=#I zwCoKLOVY9T#4JfoHlnrXqn4y+?}=NI8pggRMz8l&@-e`}-fnDRB>BM?O!5;&us44kd-bVsk(-OjuO3aV~DU>3d!1k&X%S_o%X5r)wNA{Nk zx1DZzPeFUt`UmQpE`aye2eWG;SD;azf+94*Jl zJgJoV&foF#<~+kAD%DaW3#C@-aOy&X94p7+?1d9>F5PxHQBIOY(kP2%34VdNS(eH& zIa!wD4Bi#eBB#hoX_Ypd0@99iKssfWoQ8AbUcosEzm?UpM!InB!x?fWelzzhIa|(= zm~=~z^h#XTN}u#gLe78-iKdU`~XfF zxlleR{~{lfi{!)d5&5WGESJb8`IuaaUr4@8{!K2IkKMZPEBms{mFxm|uBcgPRrM{=j!B|ny*$ldZ&xkr8`_sY-ZKDl3hArHud z@=JM0ekBjfBl4*HS{{=vGA>(Xn>;SRk?ryXe)#5h@_Ttw{vdypKgplvDS29+k!R&O zd0t+SzsO(ZMfsb&BrnU~m{>bC5aMyv-b9-j35v4mF42T$aPlJ4}f=!h}t!DKq8fNc^JlT>PrwyUbDMXmgC2 zXDZEnv%plDh>4nNQ{y~i7Mfc8%5S}CFvptX%<<*~bD}xPEHaH|u~}l8OtV>PmYI{y za`SGp!nBxE%u3U0+RUk@-E^2vv&x)iR+}}Z%bae`FlU4ENXHxjU8)_9F=`A4v@K#zP7BlD|B|Ng~6^a^)nU zqFbJ!IiXjx{M{yTZqd85aEs2(=8ISO2q|8dbJLfO$CCrGWN)G;)Dr6%9f^kq+)Htb zzutiFCe)$=8gMVc7H}UNKoVN1?UUMmrLReG(svVDsqK?0;ACtlH9V3|4fV$Z&B?w% zJlU7unqfYbVZK$FPq~+wt^K3PzF2y6a3D51GBf4B3$-f^X{DjvhqgHFy9u=`4Qah} zXscoOQq++ZUD0qhU)<>fP(0$h33V!%5%&`8WS5SxOIK-^j%t^#%5XKB;cAs~HR@jS zR;3fkzPwSUGgtX}nmOvf%U_l0`cb_Wta$)OWyiY3~kU;eu z40$ew;Ntj5EN@v1M#?3px}hdNgD-eGiUPow*V&I;kO=cu#D<1q7!rfsy)kpjs98B` z)+C^qE(NA75oqsE<#iBQRCsL@o?05II?o7@o?05IBGl`H6D&ykE&X)MXlGO z)@xDgwW#x`s`F^6^JuB_XsPoc*LjfZJjit(y$8A8E(^utzzE6cZUn!#sADElWpPBR zERIN(#Sy8pI3iURN2JQ)h*ViVB2^xah=(If^FsTqs-d1HBhp+I&0MQ9SJ%4Z`C`3~ zG-s|$^;%PvxkmK5ur_n8(`#*}yf#x_n}JumIJCMi9m8sIgI-p<6HjP^dns6L%}&7v zn+tVm#f|R8l@bg~hSSault`m`x3hBvQ$B@r|?M>DX|5Bn7LP zPW1J=E7@puT`y^kR@Y}*^u*o!nrQWmj-}`ue3)@_$W(cm>P!*H&^lE$HdAji4K`D2 zGj%qzFq5gVaH6*PLW^Rdg5^r5YS z@Q?TLd+mmu>-PN9fn$#d!uw-_!1ixAus=`#kF19UMvV%UoAzwpxp(>AgdlwIZ9&lg zYV*2%djzMDC9up1yti!Lap|V}6F03uU5g;RXWO!I-T1`4e~AdfU&ryjehVICe!=h= z^!FBi7i`(N|6pSEs_)?ay%=!gj@=v9Jw5*49zpnXt00KQJJ%iDBU%g};CBwn=j~dz zb7NVs?FNjeS`f_J_Uzub{|U!t7rH}zY4x7H8}~eF_@qx@!V4%r02ox@`6>B?P$<+1 zO+uTHOnBQ`Tbi318|ve=rNssLpvCP#j#cG41$8FPPvPe<1T~`;6M)GZ9 zB)`ZNuUFsUSCoYv;RgJD=x>@cRN1k4UP-W`zB;0F9J1&F6%EyS^O{N;i*w9=%ZB!9 zZ*i`}kz4GoZcjca{rg01t+Zj{KHbIMXs#oYSkc%p+)@@T^liO3KUP*;*<2iJb$XrN ziBnYxN3g`_D-Jq3bdP+vxn3?8MBzuL|IEIR6|)Lq;fjP!5P~^wCw^HCdRbegY`_jE zS)gN#0s11A3ecA%r}K%hF$WB$*)x`S-K(~U$Jyah1mMx z5AfFQ#@p-)Dpi45-YuOFufi-d1ds6Pgwt#WK6}g_M<$+R=ym$kOx+d}(*fawG!>e& zEa@c7TEIjGp8YNGtSD84zv87LN-0z*Kt1{|tjkVR@RFEd5CD*JC!fxXMDjk(@~6IG350sk_6X+M zE_AV`1n|DAGtq%x?Tz(yvFfVQ;-Y9_Brlj9@Mk&gnbr)G#2niED{K}~XSYgN6dlGJ zH8F$19Lh9{vP{&MVHEXxTZmv|5%Oep?aNR~Z-~=NDyh@Uf*76A5LL+(IJyuJ8? zSaoMsWLN_sLQT*p3iyENTUei+SSuJzhPYtTo8p9TAlOXfVqtC+{1`%}&1L%azUgrfXR*7_hMIv{P50-z+o= z-NFL4IALo9t0~CO3HZE5J;!wu)}SwoF|ofmFBd?V*Ir@;JUT3rq!R#FSto-j1G*AH z7oZ1I7Dap(2s)iJB*-$57Z76(InMwzAYT5l+w+{+9x?Quk2pRi$PALAaB83)T^7g!b;RtF=LFa(*;ppWENibYaT z0_ztufmmgX#py}A#N1TFCb7R<`i;IiL%`;$?p-&hu=j@TolQF**peXzyj`}fcej?g z1GbXp!J2U2&3k%U_dT}VB4&HK*xiMRB{lh-8+#&?Kge$#t_pUpX$xA+>joB@ZPA)a zqv-O~Exvl)yqk9P=x%idziwUF+!geP!-iyzH@@)j%H<~y4(OkC<%-wU_Qj+2q)lJZ zyGs0S_1yYmJ9}MU+&Ul#ve0+>UHNVKF~KDi2{l5Gu#Bxtc$X|1?C(l6*4I>(mlos) zvg|fhlILKxs)2Wcfw){$FbGDI!ARdkk?@3Aog)MZPGHnCS+>Ynn1N^WQ7?Y}dMHno z^|S_hy;GmUxW-xQ>U3O2X$VTlHKV>!Wn4|bZ0H*z^bRN-_=*wFHVawKOdEiQ29W4U z)s?}DWc~TtKoJvRl{OEWPS^-sB0YftO9*2KiwL6(z!g#xJiwJ$ZM(=3OTnV^loVf& zFWuiUXWx?Q>LvT;bYHx<=BAvQ&cedZ>g?=l`mD(jud?Q5U3Kbr89A;aa$S7szNzB- zmsH<4v$(Ef(RC}Tt5;mNXvy^}tE*RDzoctrOCZp)va54Nli%O8f?eWpeR#xbXA2h{ zp@K&iExCaT-ms)=RdXQFysE2nITc(EiduO3J^7&gxX>XCutdVmgx)z-6~)o~JV&O< zAat+}BT1ql@S+<;C^j;%roOVmY*{Z!LGXG=PN^1Hg#{}xfLjBrz_IW{W;z{KS+7t1 z&_SV77*pp*YYH5Wx1`X#?38&!#F0AA-VhB2_@kf@9}$`X*68(WGah1;iQWrqL9dg6 z9uXj;4w?m_rPdBLr?DVLyoXp#w5Sr&Nj^TSQ z?XMc$JEyI=Zv2+yx2qS7$M-xpC%J6fcKPwxqTQ`tW^)D_D}#AW^D82W&Yoy;RrekJ zF7LjdtV@2^=Dlsjw))L?uIjyf+oIt7+ZW8cYE8qbcRDxBi7cGMo@~0GR3T_;EXFmp zkwgXrJJ-)7O+WFPNI{3epeSeHE{bZF$WvbszdL7Yxska4N5@c9P*)1Vhwc-I!a&SoAO*xDHkc5WRQGTSn??i4Tn zVRGje&32>BX{g@!i(mfc(51h9=NJ2H3{G37>kG*p=%qjTHhV+s#pI%1;$ji$8y!p$ z8ipcTtonv}CoA2#HDh`wI{lVi=!M<+1y?3IsoDRFcYb^6q2K)S7yGKwiP3KUBD({< ztd-V?ugJd;s)a2ameoRamXE{I4{Xk_C@C(;3uU|PP@D`pC_kk268s2if|Zf(UN%c1 zfRqZs&O{%i@e-f~DDlL}Xw1-miW=&HZB?wn=k-;xHWq`9)Xq8}8iAKV7GgBNB5y8Z z>t%yG{8af<1%>X2^Xc-ZBVLnX%x2DZ;F%-rbcP*x=*%(Or8RH3^6h^2hJkU9B$_Q7 z2gcob&O-Os-zW)Xdd+xjwuqwHjOS*rJzVs4jA~qXMwhQUE|`Uj6HbiRESNJ)Mwm7_ za1sMy6=|b|kV(*aFeT6$w0&YPLX-rRNU#v;gDdo@a;ox3Y9xR#Yk670xUeVeh&aM^ zVTX7VyDPc%_T+ZZYk zCNpNCHBrpn8E-QAYGo_M`GWA};nirlR1>Qq&8{*KzBRN<4a6Q+J3{4wU{%N-sGeI9 zwAwO4dD(hvpfuz->?;X5y+yHL#kw`iqq!El)n+cNZVo%cF!ljq(IPGs9|o%`Oz6q5 z!PpbN87P8sgdq}{!~n=R`%}^>K71F|AA|ilg1Nhd(S)8fiqzbpuhYnB-cFV$s`E~J z>Y=A?rD=}MG#+=&v=!Ou|2h4r_;>kL_zfx&dXqsX@(~>ap1{k( z;Miacw1J*8Xj*Y}TPD(4`?!`zD&T{*hTH*hnYB7R;ECkR|CyH$;UKi0{ripO+E7$;BdZ16 zA{Pe?s)mzmugp19+0YG+-29cDyZ-s+;o+PAdDqUb+&uDP!>U7FU58dSG_0i0RSn{| zUrGM=3u9w1FxM-uF!$%j#y+3?<13H+^k_@V(Vsr@$WQ3=Cj_i-!FUMC_hJ(Nny@$> z_Dq}A1W}ptEJQ4D_=w==pdsK6iFR`cg9m+yWNKJ+DJwHiD~bwnG|l2^0tlbw7R>XxOa7Z{mQvD8OFSTY&NX24IjQ=ejNJ2>fxi8U)+|w!fegY z-qGeNcCdeI-o9gZN5`7>P+rr5s$3Y!_Vssdsv~&rIQ^ck67cLNUn3K`J6oD+s;era z1=)U=L+EGyCXK$jd*P~yBoW#qq=4Qa1Lbs*PJ~t|3p&`nin2wph5@7Kms3ng zGaNe4-4xZ-8w99u(X>|KR3VCG415c!VE@NzgFz!E#ZYaFKFEq7$*Zjk=_-mj0U->3 z1hf@j5RQp<&^#8XZq|j`vErWH?UBxvO*bDKxaR2%dmq}<=O6TV+##c=6K%zFHVzD2 zG!PAq+_GoI)e8%Y=B%QntF{>P{8LL8Uwd?P&i0W;N8vNqZaBHSrD^;V!+9o$Q)iNM z=OxN(7ObsmUfWxIHH&twY;0fI3N3M{a%wR}p%}EW7P_BZ@Cx5d*t{NSCM2z~C@IIUX#wQeV=;-yB`n?WpDy=v_f1~s&eb`^7azS(k|+NG zl9xBxy~!Kcr9Q_B>AvL4f!4gq76s3xBw$l1{48OwtSBi8m?rWhzDN7@Sc@nBBCM%ID%axUT&xk*i2r0Hx;pc>PoA#jpZW2pu_ z#D)@GAE_>PCq+_&ps|o)LzwK=N5WE?cN~rr!eqr3R=AAbP~-|rZ&o)Y+q?Fx+4JQ7 zmf@RT+1aswd`Y<88Fa<^)^!gYTwGZ+bYQ4{fBT;O;$!kav?h5pt84$sReQg5ZLhzy zJ~$W%MMKrgE}P%IW3bfe4vQyAP7_C|1*8Lj_5H-7%Syr_pT}$x0xXci!-6cPgThQK zRtJ$mfFaqHqD<0RGzY0#7Hy01^a>gk6Gs4oRVYoKS!_00_`%{!UQj9r%eVe$OkbNlv>R+JC#>F(PCA+TPiZx75C+i%+$#hg?l?~Auy}|j$bcZsgnt-X6>K{wS>%nOdXU+Q4+$hj zyiSc2fT9eFKLpk;$f}L$S~HE4pR-mLT`4ZNW;-U`j%@kFaDI8_snI~8?xeremF>6` z!hJ1PHwt+Xf&`u`d@T{Ei-+@=(9ss3TQ|3?Brg_@Au14Jp_JUH%rc4)!9gPyTmo6q zV5j__Ap-`85yP*=bv5#95h0bUweSi;g=jCWetI3~Z&>^K^ArbSg72r*qdrxMEOYao z>@CfIMBq`xK#|7wRri2v#&5BE`*TNUZA&=d^FIH*LFX^^MO*OCQ@mbmOMx=1n&a?SHH^ z`uvTn@7mUMylC!**8Z(sp-|V>{?-k1i^ONk=B})%9qWolyT)p3R?aOWO1l%dQ?IVY zeMD*1klTJAC=KwRqO@Gj@!<*qs(|JI{uJRrQRYgJMrrwKS@3ZkNlM6usam24-G|~b zY9Wv#l=-QW7!Ao*=!#fQRHIK#=}|o>#Dqw?P9dL-J9ahi3rShAaOAdKoxN8)vt{#V z4|e*>+lrD8TdPBluot{hN5hTGUpBb4qig5<(xQ1=JNtGI7K?-RTTg6Q{m7x-IftIu z+`fC;*2bjK&=||j_xO;{zQ2^`< z07NQtw-M2SbPDhfcoIoI^44de6~v-6`IUOF(dMl0!Kb*bkyaHg6VS9Ss3#&);^Q-o zFGrg3Net_%na0@6-!qLf$u!ei10-NO6C{E#9zL7MsH!N8kOj^84?!ZxP2yRh0c)D@ zhMlMb!1e}K70zs8Hpn2#Hxn|`%mg{E%>l}8vI587$ z47B%q=^ouu@N4+Fm;)Xt7x}mhFl#7+AqN?JGj~dQyF1z8uJHRS-0W4ied0s$>+H5G z9sZ18nltsXJ>#8>fc+|VJK^M~*cYWgOUHm!1|gQnP@OCSRw5Brk&XLH02lCe!Why- z2z`JtKo{~1kSX;kX~o26=ud3Ff&CEK2g08)*1u|FwF?+)1DPC!;QeqS6_S66dH!Ul z5tjM=Wi(>DB>(;@djR9J%ZN(;GQ;nkb(@b!ePsiCT(s4zc| z@)A-!Cq^2b8*&#G7zhbulFCg`xIKms-lHS#g1`_ti75<5jKAjWRna?0j&migBHY5z zoSHAFj!f1G@h7EI`cO5d8F>Z}14uMbj4_^RphOikvmie-uxxYd&<*PwD|!~rjp>|+ zEEPRNJr()QLltdHTMI3I+b3sYm+a4t7yBv~9UK_kHQH8RA3pJ@xwNyXsb{RUthXi* zEC~8eJunl?L}AHkhdxIh5=Mk|h(+g(E@Z-rWeeAhuAAG_(u8O<_Pl9Con`aSTRUMgxQAKS*(0K@U^S2ouey=vqRCBxV4V784f7EDCzEk0F>1h?oLM zvJ5u^GDPSjOlI3R(C$*TUDG++H7V^flO*tn&3T(QWhcfyTFV%!31k34W`=2Vj*%;A zB!%$sPkHglq?7boXh>UUkJ}kUG!hQuSZ#>ub&>pnD8-X>5Lr4}`9g@M1{cph@wmOZ zTNbRhHXmKkI@XfgdDT}g@7`Fk%H<4|_-e+win-lu5J5mNio#XQsWpbsvNj{d93TDfdwPICG*Cc z7e9T|n8%&GYoMl}Dm$Zb(=AJH{O(OXn_l?)ZBHamKQq=9Gi7!4E!_1TR{rIk-}>Bb zo12Ok?EB;wx9|Ak^@9i9wM#l#k*Q8}j|165HNL z-Y)un?nR19M!<~>fJdD<@`;JV;@tX?lAZv(I>Iy1RvrLM+|Xo8g%=ZEk4F$ni}Uk5 zAx|*Ni{~zh@n{;!w{i=4kpLe9SemB7VsZr-Zz@`I+v=qme@GOZXY~%_Cnq+!F5IIOo0x zy03ouVDcNRe)N+01^3;b{8uI{JUA4+`+?*K@`?D`o0itCU)1FZJ#zhuPwi+Ck0q_q zo;6LoufDM$v7-Kp10;5qBMNDP1gI4LE#YJW+0t2F&V?#jWy+e4y8tto%>u~)9a(v` z(D4Zt)j$PIh#YVb0x4Sn+La~*YR^#@c?DPl&a4m(L@V4Q1bk|_uu41|fjFE}nLaeb z8I(We-mNbnPQjgVm0$-`(d34D-2-;(;Ml2u`t-ze>$iTHnI1U#t7RPqr^A|CT;IPw zvF|H4&YyqX7q%ugEggtDSh00<)86f`GTTEBG23g~*DqR@VRhx?<+z4!fAgB_-@I)w zGp{BenKy)!@=@TVMevh{+v|2YOz_^MY{4`SH@B2k1Vk#4MxwKNxM3H5Bo8;39~6mN zomX*f)Ax2!KDz0pfg?0i0!sieOgJVcB5n=z40iB_x# zs*_YVtqeE-4PJ9b6ToH+KB5eLaPo!MY24Z3ypkaqc9dR-^uDL4T>D zdEJu1=ucce_NDrZue*EMy~&AJwr>6k%lz!(+b`c%+2F{wyZr6TE*-t}Yd7}Kzxk`j z%-)cjwR-KlCVy1aT;$@^{Rp$Yy3JqJT{@O+wiOo!hVJ;@HAjDN=K=+1f&n0YW zA=D|qY?dZbg(#97r-ZL&PX?yH2g(!>E^yjbe6c_=ATvj9Rg5c5sYUTZpdf4+XTe+^ zL*jyuk{X5Ol{oRqL{$Zx1UY7rwH1cv72a1!8b?fSe0^f#_17ic>*CFm`;j_&wRk1w z_a@NzPRvgdMp98s#WJ)2S%LT5Z#5Nz1S0WnRG$^4K-2#Tvy~V05msW5=sw2oeC;)b z`dUxFCw>!OeZtd;3?HP9&7yM10Qg7%xIpO*3INd zRZw$<1l59wA0b>OB2bwsrMR4m&MW`}MUm4=bDEDyamrFmp@=7!K(6p`f+Hq=vt{3B zcdpwiBJ}I=I9qGGHqR}5mA!lL%h&ei+uak1_Qz8xbx+;bOlclY0O&E{CN5!Z%qMPZ)Xnf{@CJabamWj$)>yPQYoQksV&a>5QqXuarE29Q7&3 zRsxLjmOfMuYat1d7~3Q6n0WKGhaX1A${6%l<7-6tYQmBi%+2w-NE1(K;W;D$v3?4B ztR>o{Xf7X+wtB%c%b-{RmEwLBW$lX3CZbq{m;8 zQ{hi$NYWFx1ahqGT~VJ^mz@&}NEi7sKHRL!^;G*OuBxbzt_{?BPQ4?a$nZ@ZS0Tsw zr&qW=VL^tl%Yrl%D3coIX99N>U~yE}7>$EJCal9G3AgD5#jSGa1?U+pC%p)fZ#M{}QP2N&on8v)!d@@K?JhB*G3+Sb6%-^3Nfm|9{SJNSVG|R%%LMn))mM9Gc*% zlP8lCFKycN64RYL$z(+z+`sRY>-zexdu88#RVV!GYumTK#;gxM$gHpL*ztPuuMZx1 z^R@*GZhP~{k?-9$fBtRXqj`g`>8=C_Y|whSM&!YY zJFOr|TD!nYleD|=w#oHYFl{6NHsbozz^%sF&Q^>O;JKa8SBDmf^9xP>@r24EnC|J? z*sK^?=aQFF9ZQ~d2yQ(U=&+TVUr~5o8r(oQ#fN@zE>`%!miG;KL z_~mms2>oCv|St#wJ@2uO00OQ8Wm03y-}$Y#Z!r6 zW2yqr#U%iuFIYfiJ_CZtHc{J#`xBDA7HbR#>r_9pR#W{YJZ`Re2*9VHgMe4fz~@gM z{rc7I)hn(YEy!UHJyqvV-s~tYzT;mPU%j;a@yFg0mrOn(pJ>=}$BMxtTl-y};>mB6 zh(eaQq-T5u+4qttET}$Hd^Lual)kve!XY>KUbF;LvH z7O&Q}wCwrJ_Jd#V*S(mTnO~A0X&tF*9cnBoZ&-9_+3L?6>fN|xr8%>rz9QPQwxx5l zv8bee$<=EHkMHUl?8AJqw@`Nlu-72mNBhn2sfG$t($GWr2GI?Tj;puRH5xp`dtkJp zlR<0Hq+$rIvpT%zwILZ{U!fJ0rcW{+usH-@#Zs*xc!VIP3i4{4eR7J21_TaTr@JCq z^IEb>KJoCW4Bg)!M%4$fJHmq*_-O`AaJy_4gI@46|I`dfpCQc^ou%+W)5$z|iS)I! zmsoRpNs^uPCFLbo*D*G&2`=0*2N)R=w0V#cH8E=`Rj`u{Nm5-+2jX9YqWJc*o7cr& z9lGPKBS+r4bLiFBx?}gW?)cPlY4gO1%ij9**x0Avx(wg%S^lXVZA2SJ=05nZ+aT&SBhaoF&M5yW7ET>+Hw4;c$7j2G?R4wII8B`Vzp7F$PhSK;-Rm#*r zBJHvAK`lvXY%F5@H2kIPlQsm4JvMd+yr%a~e(7`aiGX{;nm=4tHk>d0)sg$*W{e*= zX7~-pUo6~_uoM@O-QmC-QfuXlc#UL;Bl(%@V1zbsa%l6I_F57Eb4lX<4Q0JN>9y6@ zG@md%2TgOasLe-pQqE|g`BRc@M z=Q@)o^TlK#`@>hgeq-_~gE@Jl$>(`N{F(To%{uv-$1hrJj>+LkpU);P^SCCzVpW31Y`d3KA9&9R|hIEh&9~t?<0avUk3Ut?UkTwA zOHIRil6=Zs(=cEB;j5E>eIgJvvp#pW*^J=8TvN#Zl-NA^b+K7m6L3v_Khhoywdac! z_FSUgC72I+Hmu6-UVOr2BZiy8|7WXnpw- zDveNEQ#m^Z2CEV|=g1h<-RYV5fmD0yyDq7G0@T@;A3SyJ7 zFkEdFmks1LTIE;s^FA!f2Zt7xV+P;iGe9gHAkQ$!I#G*-gKhKCgAbr6$9RG{VV5#^ zU%b8r>#unK!poJRvpvaM-*)HdW7+QB_kV$kCncBkW2~)1SdlO~GD(9-;i@YGJ#b7_ zCXu#-*`d6mbwr2@6C(DT!5KM-lbAKnux5mal#UnU)07Zu*Bf};O4RLRo33_b8NX(A z8En4Sj6OHq{*#B?Hn!GR<|!{rK45dBbs_nVH~i_B=E*6Xg^jSgJ$h)RdZ~6(v|5<_#FoBAM|ueU)6b z-jFi-?}YPgpWNgL*nTfR?(zM_nu+<6&HA2nNM{gAgeF#-@RpUbecq$(LIAy3OjP8fG9V;>M4X%ui&wLs*|GQA$dD4?l9!`3#)wq0-o z0ELCOf)>b3g#DzY9>c$V<|vSgibPLN4^XC*@jzowZvv(dl8*aktBpiu43`q1&u9fR z5g1(F5t@=R82aEF7rAGZGFr(yt!^+&9dCfg%H~)PqquXO4Lf0jqI75|kSDu~2N$hr zZrMCo(RIh4p4zyfb6IDV&zWt^TlCt2#YdJ`CTpt}^mGIdKeeMKP~K_}tS)FOa)-M% z_O$L^(x4kUaA~+C?6NhD3^$G+Up)CMSEM%Y`?^r=oYLavLI+{+-KYPe^Ma6s4G2k$C3e?8PM!=nT$;@~SY_`l4nOvzWL;4Em+I(yEPt9f>SoZ*cH*1WHf1 z`}vNCw~iejuW!BR;Z5s55i=R1Y-H)R4b>O-9ltx$wN`$0@}YUlx~_foiaoC$8yTFl zGAdm%JTK|(s{hu@8;-9aWxfCOU!*H_vQWyzgsnIl%*pbS?^w0ZXdPpvFv9}m07_A-$`Fy(wGPg5pckI|l)8L6M&*uQsvQR(2$Ih~6d3!FZ4ZP(X#t$FxhPsgRt?c4T9 zhtz4d_=Ens@#AAFZ&?>ZLbRiEWT5xD*Dky0t2coRiJtlZ{Wny4Y9V@JDm{7JJZkP` zUQSQ6pS#ip7kYL8CcR8?bIF>9q;5`LoHOd7YJ)Wr&XS)8@$z%jqSRVTI%#rdrlea{ zPpb*F9-BB6c1%PGzWnQrTLsSKr0gZV~-v=A8%#f25o zikyI(=Vn7N6>zCWbQ8x`0m__#;tpb|MXD9UJTM0%wm;HRLAVKLA)Jp~H;r;?r}v9q z&>`}?XzfyCNTI(@A)S^Bt8^~f;jSd?FHm;GaJor}FCW-e7z|5{thi@S2a?`bi`9$v z_jRx9t#WuRwc(Xp_cUz%r>pxq4?Vm0>N}lcQGVANo!qwX@g1c(Ymcv~3Kf8Oid&+t zxu5vfwcEaQ!~APMd8B>wKnW=~NZJwal%ElTtdQps1O>!TvI8C``3|_pt`@6N2DJnl z5s(-G4N{Uw`g6Au_%)0xL9hX6A=Wq4!vL#N)M-7kF*8f)*GonyP?tL5~JM zkET_n;+ZlJw~<34HdP#NbTYZ0rz)jytRp@}os-9}X{r_`P9g-!Gt+BB+n6Plfq0xE zSFk}C`-T;MMrkYv&)7ulHiKK{r9GbP2WnPaH9V(T$MSMRl>_y;tT6d=X_Zy>xaX~3 zdc&$}_cFIJtA4C=)zuRZKm)B!-XZ-&rx%)p`NAr;Hjy*5fC)<%FIY9Ss=qJMPF`)h z4dZEIO=hwHXoqxW3u$r)^hIcP-#_6de-bw5&!_8o4gX znIij5*S;#|D&3dgwDG3VxgB}o=Cy~eJhZkMgt&Y6W4jvGjF!dh;p)7B#Z8-zv0F>~ zR&Uu+(=<2Ix3j-*?@(#-YxSdzIT!8Neo=1YLY+Q0rz>o-cMkVox}?(KuJjfZ+I1#x z?O1Q;p*2nA{p;!mwuao@jozxtQhVu5tNJfpTzTsCXry6n9>hoL5{DJB&aY3+t zpkmdoU8^bv>M395cF2n#LrQvtzwx{pkKl3ItrpTYQ(ok-8@eR1ThiemSyT#lhd}Yu zHZp{?f-vd8m7q=4$t7YeCX zqA*jkF9YddJ zhN|~e&uGKO<4YzFi`VVDa;s6l?V!+5k;gGu%1zX;zQiip|qeBz`O`fYG{K1nneN|z!5+xsqO$rn8*rr$*?5Z+zey8UWzZysql52R8QHk310^SymBoyCW4ix-8<6{x)Hj z{>Iu<&#LHM6(Dl@Uy^rnh`5Df#t5HiUjw{SZU-=m;}gLI2XukOlb)rhiO6X}5Ksg^ z!nkOr0!$vR^AHO&Wo8Wlk-f=2Sz${h^D^4Qr98xSWDu?tY1lG`x%o`^GU89u8Q*0hpNSic= zw2By#+7Eq_c&cp=gDu6rl6{Uqh9%@qS{zPxzsH))0m!lF zkK&&(e3gXV)4WCsky}YW0+c!BYk3k=4?)WGkl>h!GC(SXe^7xQpTq5>8dfxcvFGGh zKkPvNoTJO{a;q~t0XBs^>r(6#L1d8fwoC?zrF=u-5;ODzI1%*lAD|{W1uwOQ;Iou? zG(qE0g<3&0N2;9SZJ;5-ZKM@Wp^a7;?@?6E3sB4wr7!{!)H0z#rB)a^AdpRnoUIZ7 z%ej1lDj3M|AsZxgO}S(-82kpRj6aBTh<9j`$Qmc}lOzxwy9s@PK2wKR!2T^ChJe=FS5 zGq!hK!*Dz+w*HotBq1(29BN(BO5YA0oZB{Or4{9J7OUbD{>tU7Pw>I6vC(>PzDT~h zT(7LiS?*vh0675KnvB)fBCHjnmzX?Ck-B}RFisVmO=wO_IZL$&jaPvp*dfssV0VU; zMd36li`+-G#`&bI3T^B}oDN-E*TdVVL@mI%Yu@r1qL$n8Ivb$p!WuuBaC(qSo9%Z; zJQ3`=bTL;-vg80D7!a5fX|yCJRPewTsR8h;WngDh8IrjHYCv@%rL}?*5UITNsh6Bh zMW#wom)d4R?RW#tdUinsC}*jX&M21ee*W_A?#rLwz5Dqq=FGX``Q4wo^UhBV?ina7 z9N43i`;WeQ$-%E4oj333R}WtD>e2p*gWr7N^WTcEzh(LI zhR2Y5n$*1%By%gX12Q(&d%$f)Bv~r-u3*@dKhDWLbau)K9(a~AJ1?k~C%qO)?Ar9c zILnxFEdWuc`b*W+oXzp{n&+%Ut4vKxDX$j1l~Xem(mjvx1`_)yOzW7WT%u`O4V3|< z*M$2~BF7;S0ve#?5YC4v3d-$0SBi@$J8UVk;+XD7Bo30<`PfeG8`<;lrq$QQn1j1U z`i_wwG5NSWSa@(~ZTGe09yvDB-jqz}{(YJ!5%`~cTzW%Y=>s!XdZur9x-Tou8LT+6 zG=fOWS>h`_%};c;S~&DFmFdJ+8nqmuyN% zf~b?cV5wd~2Vjw8($ebC@(6`#m;;hkye1-9}m*=X11LVGAU+M-NL!q|{Vm+nTrlY2*AMjoHx_ zDy<-pnfCD1Vp=mKhf;@#p1?b6opd3h19)IZf%gz>>t^j@N-(5EiCQgXekp!&wL*k7A+y*f+$#OBgDxjsXdtvSBx@>1z<-t3dxE^#@o^SgFzo;*xawH=YLOvnYk zC$_nfcEo1;jd~SQWDmqz8IyC7Y@6<3hpbA^fC5WOB{HRFK%Kqnl$$(NQO$t5pgQNs zfZ}JcUSI;0_(O|7Gukj1ujq?qSM;ymu)4pZcKz{H+n#DIHF}-S;--(aK~OP1F5)X%Zna`JPsD_iqR8;WxCO4?U+ zHg6xP?r0!LmtzOOOLDsqW<#`-B{v(f3_2Riir8kDg}Eo4e1S1+5tTy743nKJTK;Yd~5Z-d=-NL~b*kx2skW|k(jV^n3F*sKK28~EwW zd?%Ef?^RF&BZ*8TvYW=kO8G;%xHWh zJfjc{MG^(XoUx)fQeD&jBk2VdOH4$_FI5y9j;JU>zf>&>C6lZEGyr_%p50Uh>Vj`| zpu$l5c{CB+8eB}Ng;~y8hs$V61aJ^65v`y+@l+(k!OFL7UvOjdbCAxqu1B^Zp}0)? z+vK5rSM+y@f0!^A?wq%*Vf^?K@p`oH#OVJUP&`jA8Sr{qmeK#Wxn$1UJvj(@*z5+Q z(+1SbcHflT@F19E=H&i@zDT66K)l)RnJ{Dg@Jz|?O8>yl(a$F=mF4+)q1@@YWJSKT zTr%%ZHPh|RoZJ(c6At%<6bR;vpYv7u zeAT|mh4~mNGC`#`feqQh6SL%<`P?=*twB&c^UQ|C$Z0s?pY~cKw6rY4NP2;@W}lVv zQXe`0%!PyD$p@n3pMeGN#29vE^2sN?ZsYqV$B#1HnU7$9>4qnfeRkSl`(uXBeLpfY z{$#TzkL2XAgw2u6nS2+AMjp%cB_HFtXEx}j?*SfO;c&u;W{`ZwGhIkOblZ@dq^6#M zJh<*is6mohdq>g*$uK}=mddqsPSxY6AyBrDmmZ!q?~Fn%t}`;v*vqEuoFgwLSKs3c z=vk)8DpMY!L7(e5p8SD3i`_20j>z_f3lGS5<( zg|r`dN|I4|@W5%ig|dL^V*LM64dGdd}Xr=1~VFkBaw z7Te5||0R}8%2tb5H2G8UJ?U{*#5Nhdsoxs0i$A>?b<2}Kg+4neB!s#A?ELC1c=Bn_ z6*zsOrT{cXzH#tV@<&IhGZ?w_O*h*S9eScWn5uPTu_~e876dwIyAh9WP=Le`uaN(u|kunFrFx^UB6*V(|#NhPRK;f~8@*@*Eb zDg>x-NC6ggb#SezJ|b992rgpccm$%vjEOeY8AII0)Ib91^AR*Vj)4I;M=Y>`~8w!Xr z09c&r%9FNJreRh46X~OXf1B0)sHeY^X{oqGx zL`3QaC|6QqHN9;GsR~R>+?f z+F4b?-QHFo=chx#=kIo!O*%1kDj+2|NDXBo(k;n6BVwivuTx1ZDStB3H*o0+L4n^_ zrKOHF%+dh*SN+A)no3p2EmfMqmG}tN4F)U%#p#t%&DB@i4ZeZtiv{5%xcRvc zUFWX~Rfu#3z!NQibHZsxO+mKO2a@{~7&a6&VD|?FQyP5y5J$biXMjRZ4pBo9(j^-B z^$nCCQHecWHu0z7+!HJAD&NxFw5jaGvb#e0;oQ4d++Dt^1E_`N{>`lEo_fO+81J~<)DjEGsMNpkf;q633H|6mWiDrKrADL7?Eq>6Q)ZWUpX~s z#;#h0Ai)pzp0y&XfC4n5w?XMese-g;0}c(H)*bd51Zli z(~dzU;%OkNN}VB$y^mT7644sJm8l&EsPZ%Zo$bf_U=5=USA!I_YN&8?yA@QncRf_ z(#BAwBi0g^?V8MSHZOD^^+_>s^&taCs!Ub)b3saCLjb{$I({2;U10L7`6Tq0;( zy@=2Y;$bLA|IxVtVJsGZM~WPYA^=+{gep`<*%2}`wMAAnR3%q0D8B2=EAe@YLr!O? z*y}6FbF$5Jw4ARb=ycKzgt$;bHsKyZ{3`bON~v5a-AkDM8{ATubNVmx2av^;INg0c zTb}T)Sv5M+)7?-uEMX zBBO#t+C@xy$Y)#wNw^5IRPK``CiZ{PoJVPnl(C+(j}F&Mih3l*@KF01<4lbWjp2&Q z1s}T|TvJIzqqRp;g%Fvw*QKVnR$ zH=6Z0lBuof(f#Wm+}F`_=&|)X?ry4-?G{_8cCZBpN0;F!+xF_N>cWYI@io^!^wP$S zFF$nsnmB!bdE>^H==*s2!o4>?GY}mp_KD4U07y;6T-Cd<%h3Z8;`HO?%|g=j=%hn@*SNld*l`zaXtR@ z@2+3==q(3ED>r`b4@5;Pr4DhC`~>#@)CvDX`+t!0S65bd#{QprtRVLPNOA=UG2}+z zWGSH3^esS;Fd!DvfJr^jxSJ9JCX7m)r2(kOs6>=d2l?bMU-d7^JMVw4q=Tfd*f}f51D=D#b)`vHK&}_41+;6jGTJM+T zoaU+-zeT-|U6*6=N78gr~U?7FkOAjWqmYmwd)-vRSjIPL5m;ySsI zwjx7{H$03aP-zxmB}y(OT(daQL!@1Vv%co?ma7PNN-OW0Y!Tl{jxjJ{;eU6ljxNPH zvvJVEJYfkto(RO_bbnubUc7HkS5rfMU3FzaKKU5A)&tNi$*jYpS!4Tcx ze94FeU>z|G+UADgk=_fosp+rU{xm}J|3xbZFl)QqT4#<0;sCgYcE9Ctuz2Z>QS9A*f=070i35SV>LdIe5UOCdgI==j8L6*WI~F6*ppR3@#F z-y}+BG2`k{a>{FGUR1*WHRq$T&R^fl@}7Eh`!GQo8K&L#vPYGlK5qbADE7we9s3H%AMxy9lV^)_q4@D9?fPzVQ2?++zFW zYx10niFSIWBJoXdWI9D?bcS9-_~k{-k#IKQq)`3KvmMxE5(`CRB!Fr zB|SZtjMZwNR|f0nm6rC^2ZQx}rKR)ggSsu<2bR{>EgjKZDJ{~ z+li&XMiB%G;MK#TN;})?0xRmdpywe`Zjw02E1q^IS#rDd<%urcbIGGelee-xN7=!N z!W)SDEtHOkBl?ZF+xsdyqn~bTtO_8UKXA8y8 zU0TUCi$L>KSSfuVdxWHwdJs$|6c)u%PInK%kA%C2c)mF|lWFTITOMEB8m3D=9`aRr zUibKtEW`3+e|es(wW6}gW^_4lE6v=@8}%E5_4BKWd)k|WpV1@cGQZ54V|m*judBC-nmG>F*i1+_^Jxmg7$_*O}YM>zN##}&x+Gx-JxPnuq?;6l(oid<5k6W9GGvZ z8>-6&biby%NnEV$@&;>#xsAkG%`d~#K6zlv!6*oUUEZ)p=u|spFFxbJH?r@<#lN#< zd$!$a3+Ks?CzF}hzxX_a!-pvA3vsAiwv10&cH_`l%Rjzd&h0DNi&~u9k;sMf*S0^+xcYX8=sEqvc~% zrq|KY_TT)es+l3)1$B%z5c$-6gSF|k(39eJqQWq~Ni0QqMYM(;Thu6Vl}4&WI7^cU z7lPvkxRk05AZm5tP*JMVM|xV<8R-GhB7U46rDd@49b2_5f$n2V`}Y(X^vj|p$Q0PM z^PrX~&^ISmS-Lcu{9SPYdPkR~ryFE1yiP9RA---d!8zmpMuKcE7$W7I)dJ&z0{}iL z-;^c~!f08pHdwh_lr7%BLmF{-67 zC;Cv2Y-OGZ$!+{;J3M9Y+xI2^aNm|kFYf5L_|Yx$i4z|-$lv_1L0Z+e_4vq=V;dVW z?#tLev&Y2WVvdlQ>J5l$oQ@r_TeK6EmoRwAF7z);x_{5R) zUwBK9Jd%8ny$kPFuJAgYS%fp(aMvQ}Avd+ZCTzC?@v}JsK!gcmG3;r=Q<3-*Tu1~- zI>Ie)dOQrVcv*7)VgLyNJBLZ8$s{u6ks3n#^|O=WzCJfXCVZ=xbU;y%+=E3B8` z;JVd?C2FT64ej_-0@zxbHX_|#c17<+!{z0}7xm8FJ5pXgvUl#H(a}XqM@Qwy%ZB&i z4yuu|vXT9LbN3CGO-^ndAK$WNe0(d-;8U;)t*{E6Fsxw}7JBRgtilF0%aGpMH zGVNe49IqTRm_Xs$k5b9Yq`+Op&y0WY!TBvx#Dc(DEV;#TEg5a76xLq(@3vlNH=m4q! z6oOjP^GxtA!^aF~H24-k558={_9D2(l~hRRQ?!Xl3mCPfw}XOu15yHIef%soOn%G+{Y1H_-tK64-@rNO=yfQZrgiiRh3iwn3t#U5=bt1@w zxjkKpw$_&BrpCHhRb{%aox-PqhMH>1IaD=nx*kQrDab2^1WyIGB#v7aP_U|mn-$ao zra_$Gv>!q(&D`#r*(3^U=ymQ^0cWi}U>UVXST^#%Xph?pT=`eVN$rPC8p18+E#tau z#oQqE+6<(F(@{gZv%>(Wk!D(?wVsikSfAc*20OD|#6k)GR1hQ1B;t-5?jxB2Y3e0| z6x108ObY!j*oK*jm#!2>>NZ`Nbu)4AG)(=&6pD&JzYx18mWI5O2UNU;cL{iVx%>e5 z-~wThuv%P~h&mmsS1wz+XmoB*X9r<#b!ACWIOJI1TrkBE9VAWZexEh{%wmSKHlq;d z@Zd@yJyI`lLYCQ*Q7afsMiVyOgPcu<48{2bm#Ps_=cqNsC;?-$nRL8Ny9gyuW0<(l zp0GLtSV)X_!~a1ynVD!^>B~;~|ranZDh=kEO9_NBva2h#10vjR5NCuhs%?8Idk-k*S>GMiXC`y9{c7s*HxvuZrs zHVey$k8BT5tehq%MC2ph zi?EOkpLm<_M#9z%>Z1J_sT<2k*^a?-BlQ~FSde6f=mUjZkyi#!rDm?_kkmzau+TvH zws6u3h)$}{UX{!MR47bqL%Fc*>{XB~qUP~YWnzO`pVX3SD#@uc!*m@i=7Td1cT_2{ zSssm@Vd6+)Xkcv1*{>{%;v`2y@}ilSmc2!HmX$9&Ffh1nu)ew`e9vQ+^7h)Q*5Q`& z9)4$;#jLZ>ytM2zZt(_xo2UOfxC}wcz>I9WAk6aIJni{^rOI2_fwb~(rk*>dJ^xGU zxheg*p(6F%&i0{y@$_$zMfD?C!A>EI1ru({x1bXRQ`fdAXVlSB)_EX!l;l)gT1rkt z5V;Olq~IIgkTS$iYE|x#L$Fk~P?nd%#A0e?=ucQGsshKs8O=;p#UU}8$D#GYssa;< z@uZrdq#{bl=vJ#6a1a|^$$g#?;3!448JZ9jLuhwu5)wHz=^{b;lhj+b=))lXSel%4 zwTe}fziboNO-$5GzV*DhFmNaP5&Pb1ORg<-Ne(-j{EXX=xYM6YdXNN3CpkXIZ;Kib zFH2;RhSt{FSYK0BRG1g^`(Q&4uz^$zdI09Lt{DdzwcD(?2XP+5jdc`_*6XCH?JNq1 z1z8}3qTN$x@Prr+8>G`#3J{{T8}p#@JZr_0e*7k#vo%Qu{Ks!{)=?7sS$M|8*%=du zG&eBpE{FC`vW1*h(;)y9otnQU#fLsp%annKHVV(u#Z)|g{zqzdDuE!?!PLs}xct(O z*`AEO^mIuf=+kIawMGR9G!Gu2S7JtTy2}G+RMo}#1qWxj;Y-=?lu36v@Z=2gjEL8! zxkd_Z`o;ZA&U^Ql9ruKd{_Y|B>|T@umW#i_gcIkw70f!iZjZhp-Pr;@`V9OaVa{KR zLF&X`u`zCz=jLh8iN7l4Evzf8Jn>QGxk-6``r9DeS9tr#T0?Z*_&&8x*BRWH_S8&I zPrr+&hxOF9Qr05T)4$;9K|QssJSEaZf+ys{_rQnkLRk2D!WmQ&;BZU5%|ZyxckU4v z#=SM@RWiWD!@9z=OUSO~ys3x}HC0P}Bi|nUmvFXBuVQGg3W%9csl(u0i8TFFLg4ta*3M9E%F=HB88N2h}+bV)J8X| z)xIJ6_|+NwI*rNSy`lRL+^M!7dtNS2UdtBK9U78FJjSn7PbS@a7=KpAMustcZu+|B4I!n^3JT!&C{OKDk|kI>`!UsseR?SW7>0CU*)-p zo&&a52yf$j?lDB_3<*RuaMP?wG?;J~C2KG->4W5F+4?oflgUr7VdKfi*05!4O!|BB zv&s9{vh~S(*RpZ8Y;E#UHim^?dHN3AhVmm|N`=sfoJm_OHe`PDO(s zzSG*8XkiGV(Po4L9+oF0INhUxLr$jiNxUHOowm<&*6Q$7!pBN&oU1xnEp@Z?K2;q| z4<}R*YoZ;Syl=kaGtqv*^*}I$mRfykhBQDPlj3MaNv(Xp5nWcQGBgBoTA0D>l#%_7 zb7d(1NRH!(8NQKIR&HfvgSN0s{cew2Pm(hjpyu9(JHt#vrInX2C(R$}n zy3Iv;zq57nqW$-#-RM$NeKa?~bn98(^ZZ_y=K9^)zCWx_{{G1uzCTa8wzQ1yce&!5 zeG^A|>4q0zDL?O@V`HO=jrVcvn)%$!(w`GHD&;NgvuWiC>y+mv^|=xJ@Rz*(R^Gmu zHQ{sWW*Iwnl-!$eVq=NlkBnZ06NppK;j?vnSt^PbA-;dEE>XUON4r?tuIZ za!mhBJ7~JQ+FA-Dq-P0ztdGx^sHQZV!PtQ>9<(aL&QXrwfQx{VQk3W?a{MSOh4fQ` zP-Ql3qO;Y260B7Nmqsm3AugX@i#mWOQKblM#nl3>3|S}e<~L3+4q8US7^6!=Q`N{W zBZAOs@(`^?5DNIn5aJj1o|&_XOP!}KcIJn_;I{b(H{Z3ssw^>(D61P@HC)#;e#6kZ zlWK};!$4g*Zf9;>w0==zMfZa43V-9Wjyb!B%AW7J>IM0k)>XS=txLLUt7CaZ@rtV6 zO$!zrT3j);eLYdw*c&Tt9_^|d>Zos>TbtHazTOGMiIBbSZb)x(jZbS#T?2YU)rr(tn-3BMT-$Txi+3 zI?7}gg8;X6gag)KgzzWN-xTD}Gm~4;!K(jd2WHadB7zw=p7Ku(TJ#wvyM#7tkI&vo zhKP&FYiFGW{KAAg5zGd+mt#hdtl~NQBKIQs(>I-~FGO>-?xKi>7~nspmS^eAtRuH0 zv2{(bE1pdOo=VINzP`;fID|`Xx_@PhuJ*tc zkb=>}4;$c5Xd!=s+za#h46_=FJv<<3cT&4U44Nbe2aZ02!A|C>vNvS# zjMmOH($&^rdoma$(^`daoNANY6C_#ZeT+7_AAr1yDFxL{EG{wnG1^MA%nb&juGA=L zuv&uqbmJM>VjR)b%dw|rxGVUF{fFt6GrKj-axNS_wy9Y?J-uqyL)Og>eQnDV>m0LN z&6k?7FYzMfboIo{!`Ds5&c1$QbDF^n8B3?%e}l`?K2^s450|kspC1s?pOcJL%D+AB zImuGx`8MVG=?`G~T+iG87qqVzy1!47{Vu4W#c59u(9_dz;%U81Z7XHpev_X598XJR zYFT-@?fay^4xauicEn$gl#f2zb6j7SXs_$5@2e~?$mf|ABn(QMt08PzFdp-}oSDd* zqbm@h+(J!?(t(#GS}-W(%G&t33!_gUz*H@&jEoUtGPvFn83H)jLivKM+6LOWhGpg( z@3nLVaz3Mw!39o)P379w2lk*&_HC}%*yQxf?zJzBJQgu}*R^iwEowjf#e?ggxV*1@ z|7W(0|5K;?;?-YTGk4!erDTr}Y-k_2Xt1bqc&o0&VAXpw``r09IU9L5?e^B{Lrqq* z$KG9Y*{5IJb;~awSkiU)xjm~NyP|)|(xYEa+%R!-{m#$qE*t46tX+D^oRKS+RA4=B zhkEm4nKUG9HixG53wUX1op3t8&c@eip^6=+W_^A@NPkW%sFZ(u+H-1OdH#!O&uMLy z=iBHxG_7&rpONEw6~6g|GNDtsmw}&=idCRJ{$)S`N!t+4*$H=t@Nk6Y1San-7D=YG z7C08z49CB=om9)#9j6>sw%!#^-y0rw&HOFCa|3&HhGTznbjAakL*n!cx(eMqA&eQ+ zv9g4-qP)DWqK@{p1+wfoQ!=$@yfp`$I36pc9c!c(z)(lx2+IYoo?&jg`5Emh=E7Vj z{!6^_W48h9r#6UQn$JIulz8X4Z7KSJpMB0ptE^b>|F60;fseAt7JYrarPJB>J?W&g z09goONq_($ge^oi0mC9B5M+^USVB~WaX~=Fab?s|#|2Tr1zSW#T*g5}#zDuCxjrxB zb#l2QD*DC|9q-eD^!uOsx;vc^6yLqS_j^w~sjt7U>QvP^r%vtXbYjud_rOAXr+(BE zc)uNQX+V1ZZX~7{oF|RO8n9dsV)kymWmv6PXl%G{P-XJatWmetjuAtRleSdVF>{}F z=66GledAX)tew=$sGP87Qm+9Wlg3!r*8QecEH~!4>$B1hjXt@>{_Vn=e` zrtWqm!&1*aSReFAGkQcv|E_imqP`$aOoD=*lvL6DBLqe3$iO%y0-* zMG7kY>2O8Gu8M_|yI~bQBVYvBnOxW@ifF+1Cucqa_CRG@T%OLu{Cphg5he_5R5y}m2JrA*)h9{U}$jxA;AA#*d+@A$!8b+>FyJNJsz?jVJOZzu2 zoK&6Wc5XiV)6Mvxyu&i=b<41V#6Ee+{raS2Cq|taVM+P-DipVMIn_gJVsTa$~ma&7T^d2paLe!j&$E=^|Rg8;`k809K*G;Ie zyLj})ovRl~_#6%A=o9M}B1aR4a=U$ej>Q>{Yj>+Nj-dhb1Z;Na&;~1e$lR>|QR_!?_Uu6sO)eUklj`c(?OJ+x&u-T`1=BCMSylZ@ z6T;j-${8Daa+dG!*iewO6cB(pX@v1KgK|Gun-;=?xtxJ?n7eIs7b4Ug)nYe{XB^9-NW)!S6lq{eTmyn| z1II4PBEJ6QK;I8xQsLOTBnz#O1JmGP=f@MS$Uy{GySq8JXr0F}hjvH8S#YsKAq_WJ ztRTA1+M!`Zv&#nI=nFx?HBUMW=)roCR3DiP)JaMzN_K*Yhb2&p#o4EmJUx{NpE%!# zO<#JHNmy46>)%L}&BUZm1#5EzrFK&F*;&>#XD3@q&mOaQXLkyAh$;=9+UOKl3R92v z6c1R{YP9iEP4@6%2Gf&aqlb?kT*+zed^d(&v?Ns<)sX=WI=Ylq7Ah@0F~)ANJ6geF zn#~c;nqOf=r>^WeS_KN=GwIPBUA_8vRsz&+Wn5@TA8 zGIyCm)(gdKL0C|GS_3}3J`D;|?SMs3Zp68dcSVnGy((^>npl*ZXm;2y2mE>kglyoY z1(tE!j$9+|yt;Y%sva91k%M0#-F@4pcl!Ez1Vz@!Z8NKyS;JW}LRrudNt3~sc2=QH zIN|^=;K3q>6T|eus1>~n_XExgYn1&6N5ihijh?;%T{dDo{$&9EF5G+b7) zOkfrjtM1XXi&fMmSd&zW5QaY`O0JzS2ONO}oG|zJ-S3B4W+Uk#>2;}9z7QVwAXq=i z5BVquxG9bHqT%O@1Y!V1uP4P-a)}^Dm|)h<_|@LXm^=4Aopu*4jt*XQS!`0+sIzv< z3k^%MBI+zZlX)qpUO4L@J)wElA;Ne^_k_10ApfR&LUUcGmFmerWRCB&v&g<1E2-s{ ziW-K6rNy3He&Lx`tl7a}y$h`SLfIAV&#oxph` z+@`{|xs1!jY2%3ROUnJ@I6TQpCoLBTg3|j;Sk$ zs7!H}h8m`5Y{LXN(TR$k<4{y6(E1C<5^fWd4D28WhXw&$QaaPbo++ZbXVtyzKyApy zkP{Z>=E*>--*#Bw(5~>+vdxEYeYS$4^eEn;_qksZ#uSp(xmOjHf=g~`^1U2AES({O*+=;-H94C!O~Kb zUpum*A7?1XjGRzAVMtZKnu?l|K6&n-XUcM;JUXx!JG{(rIkS_^tyupSEJt$C(>kI_umWmDEwT2PgiYq0+lAo=~JhKt_N5%U#ocJX*#$ zdhe9$X_)z?B66Y4uW%&fB2Ufq9?-I&8mPN$BRXBW9d*_`1TQPbay65!Q_XIUR%pC> z8n0EeK1R`Xe857!Oxr_O`Pn}-?Z=vH{K=hLh+lWvLL4@;rZhe&vcKLzT>qQOLBGAB zW#_t@n)Q!fcHJujD_%VN=+C$2)h!-9cJb)E8>|c2GVF8imSNB_=$iGbt_(P#xnjkV zjpB%A*3I(=h%1_Xzq8tdn}qZiL$EmiXU8|xls-|wapOKi`S^{TTWw?&yQ( zQh&btI^%~W@ZO9c!}&MCZ^l0mjQgyp6?KUDlT#0V1*6! zKx#Sq%lf)5YmbQoXM;Gx?in~hHpnXzOvk8V?tn3fh;Iz1-YpN#O#9-!>e4AAN}MzA zNlN;cq}0!jXXcbmsVNOlHfpWvY~fok%pIIQWKNysofu16!uVZ>e=|QTC4I=Hbvv$+ zDl6NqmKH{kQEGOLllukChlAs;1X>(}N9tw4QWir~@O z1}{tV-n1P@BkW6o^_jo^mX`HN30KF(UgJoPyy`EH*lvy97#FvZ4o(zkpgeI>9`TP6 zS|0Xx&3g`(fs$#24B*TeaGd!`7Zoe`7F{0RiOp`Xax~I{=?LDN<>AyC2M+LDW|-z^ zt)8nQlO0z_IP78es~ss3>;LkI{Z}sgPs3eym+hyH@D6>J*l*(jfg zJR_sLu6IdQRY_@;*kst;@tE-?Eg@5Ft>G|IS_sdx6u=LM)NB_cW z=gGY*2a1ILk^L z`4;iq*IwGEr0=AvoUFX8#_~ynC8P>!E_P`?W)6mLJat`7yo=eqE5U^qb>0L#zv$LY z-dYA&uA@1}sm|7|-{_AX^CPrk(#c&`?--yggs^1osn`?N#iq1%!u`f0|SIpnUMq>U(Tfs?ArUa_o_qFXQ)+KU{ zJl&J#DtAUYZZ;zIWYX+Od%>oBtR9Jj7&MWdJkm!wSgio9G5tf zz~B3_h%P;@40{XB_@ET@IONuoB!f9oXzYNEUv830Nfg(;ZQN+=nu<4QNl!4Lh>4!NzWP2(* zYwO;QHCJ4dSDO=NamJ=6)((C-JT5)X`j2rb`Dbpju0DJ1`WqtSCWLdiZg{O_Lrp|# z0%zsay_P8JOO~4%1YEdeLGjx;*`5bM`Qk^Nhhs={iZ zKX)7w~l;PP;2MJ2g5XB`m}Gb$N67tcOSE*&`j%uEdgl zgRnKRebKu>iFCkqrMEmTX3OxzdSEmWB@u?F41)8Cssvr(pVomFD*C~bU`F~ z?ZRnRa$aIugqD_8O-o(2G)%}-w)4>Qg2`e0`oalca$eF=x{l8+t(qgDr8`eC&hz?Q zAvm{m=Vjmd3x~Y4cHC`?w;xnF#)_Kgoa~IWWW2XTx@_XTWrBAYI;fb%17&dC#;P(? zxkMm$Zty9LBDRuVl(V??v)Pi(aliEDz0XNPEE3pg#%K~rZYGefZbOfGbV(4r6c%OE zBL%_eN<%jwi;!LNLhG?4C1)YH^M4-F=^1nXobMgdB-7+6YqdDi6(!GX%G z4y3l9o0_9e^wK0^9M)rUJ@saUk}zP9EY7D`2~w=XjY{!klN*%WdsloYydU za#3opft7_R6CWI1(yOB_rLb~fuhfq9);n^_!(EY9;}fj!q=uy%+2;LxrG1cDaCm)IOJ%!9%`F7L?A}@TnY-U z&yk-Om&}8~g;`y9x0{ku|x)fG-zS8@iN0#s$;qY)k)08RpeZ<=jYn(mGma(;0$>;|s znj$uF$LQkT#tl77+Sy&zIps!LSVvk)it%w+nn<6ek*d6-+O5x9k1+bH4$g}vcvIkw zwpJljMpqb&_L#)T08rYQet?zoJJ)K~M$Q}iZ$~jpduM3NmWGSAE*v^^;ns^9wzLej zTpajy5x@9~T50rsX`i7!C+{LPRQ*~!QOU_!IhW|aL8wQb9HB8Y#MXnpy%g9|itqX* zNlIx>k+bBBS=cUd%mQa{a8t(8QWe;QL21KeqL{(ssY~^kc}fKZOaD=88?^+8VjfU(zQ)TfG7;^HS#AEWC-5UC(;?gw42>w6`*-|l*Y-N+~tVUS7!nS{59_2 zF|O`Q6k*+VIUg za&b6OJ7;Km`p`MGBWDjzOB+1f_-Rz!cblSOjj7W%NyJUlW^9p&TV~W=IwYOdzS@zq zB;u@*KkyySY@@CGtG33@Ou>>UGliZkv3EDReqJN%Xb!REXMCh>`GGSYV{TYtJI83B z@lh8ueHJ_<_GFRI@UdcT^|0<1u4-!>;p{zF0=w+oP!lIJ`ub}?Bg(Bc7SaMc?Cd3( zKd~Y!N{k%>zs0u@TRsE*R<8_|=ljyO8eKBh_(e_j*fBM@v>RMmQC{2|TRgck%EXvt zq-;%S{UL3*Asm%C5VgTE5IR&=JUCMl=H#%SxQdFBbzjk~k%j~Hf?GV@KAB(ZaR5!* ziQRRcU9NanaNDT<{5YwOfBogW*n=38T>3=0H1Lc6YZzTFbRx#2{AHCuc6k74@t>|}>UM#wt{*1$}vID5(^!t8qz`fIOYotJqWVS1R58*Lt645n+Wk zoE+!DM4o13h;4G&J2%mBq=zQP43?F4zjtO&T%|af#khS6%Pewpph#QL^$fJW=HLdQ z)44l5Hg@TX@aLm);&USRJ69~ledO2sHtw@ck4}r`f1_`d^Q_lcKB2>lOVx|Ub=+>5 z?2JlU(vfC-jO9>6cD(Ex?Yr^!bwcjX6EZjHRhWs-?MRnifk`=7{&e)J$&#m-LC26-hu0AbejdM-K^P z=Ro4KTE>kN|8PtfP4+TK=U?>9jgvK&PKPZiaTvH{cswxl;1m}naZAN0+FCbd>w?PB zSM6?T*?raM%K0};>2PM}8xJ+zvux;sr%vB|^XaD+3|)Rtld&^D+juT!`7_bx@Y0l@7+CP#@+8-y>QRgrj$J`nM^e~z4Dc@zWSP0ggY=E4&i;;hQki9w1Hu=*_8M~3#6?iG=AcY{Z>h-FTZQvnm4!4m^q_hRQloHC#EGv#{ct% z%2ki8DY>|&aQO0HUNZ8sF$Kt|Vk^f!A6;Wrk*c+e4-=99G<3Bo{N~v5oTFjE2>x9R zGlF?4EH98)e={XpM#wsj1c9aN{zh&=u3W(rYg|oFSuXzW31;9IbzB{u7#^MwE~nw| zwf-h$NM7DhnMUC#-9^s@uXNL|rJM>p0qq8D8dUiG{iR1vb1wkQ$$+z zVwz}$^TvshI5kC~C>WZFp(G)hNB(GiBY|jE>9tt?M~~7$`F*9ElL(KI{di_?V-h~n z?}&`#Zhg4nwPz--Is4u(EqCVj9-JK0vCv(Ymr<2v9~+zW?POZt5Y=IKTOZIf`bp~H zn(SfKy?cpGx#~&7CiU;vYiRGGIa%V@Ol}G3lYP4To=}>G+ibdiWDg~T&{1EPBODzk zJ+MbV+N9ia^IIOIFR2YCBj+%?RgW)`YkzWC9pZmFZ%M#NM-Hx;PH7p@u`wVTj@lQn zU=eZ`UoY_mbY8TjpzBRpF$@*xgK%nXJykXPqLGk1Y2!uHUzGr?1z?Xrd^y3>YSGOWO98?|SDbnJ}qXqSC?>p#D{?6!HOQLzn? zQ4S+x=%uyv1YTpK^?mE>SQM%>5^B=3GC2}aA*bRqE3+!KpJb?s_0Sl)(CBW9Bd0%N%&sdQ= zIX9`v6pF%3T|l?uAD!Vxh7SC{xol=z7kN%GyK*^O6ILWV$+qYoyodMJgseejdEsfE zRl^1>S~#yXyNX{~o}bhXT--9R^n1QpXGJHaMy&2zmfI^gDk&{;dH;U7y>mPEMDg|~ zI@m!n)Zt~Zh+hs|W= zSI-Z0*1}P8X1x~;laPxK2OJqNZ_5qyRN^hQGWQPS)796k{<7npdB)8h73;5A-|@9E zVP3}!>o30ia?6n|XU=Rnf;4YeldX5#ZsF8>k}9pi$v{FpD*!b)aj}S!o#PuKOOihi z(rJoPSGhLH(~zx6u7EKkv1c1utmTpWcB>;ky<==y|MZF^0N)QeS?b@1wi!a@wxyGYf62`^-_jECPc9J`iF?j*en0}sxHCR zz8j$OX{wv3%4=wVG*xJj7Z>evSVhCjwC4O|=pSx)u)m<^W#NXt-FUUJd4sXJ46#1zqnVi+d3NdW;n>v=$`wxBu%C zVIL>pt-rVbM&%mI{ihfFUWik<3mJynHFozZz*-s?D-$<_U6x(^^Ca1yW3~(j&>-yY z;c1aW=jI7`8B!F7B$60NEwKYjy_AU?+WsWc1IP&DLX*UpyNHLoB@uLXoA@m5Av4oD zr1bp*Lki|k0xcN8LEJ(T>q@~uJ$^;aO0ne-#7KWSCO@!WMy}@Z3IB~y8)s_*Sa4*= z79S$Ym2?qNMx@{fZpHMEGY=egF`80H2PK<(;_v3bs-%nuhOB*ZP2r?0hb1u~A~oje z2Q4joJEmDLjj|^tj<34(o>jwLu1llBjN7;OKa*o^I`cq)qo?ir*s0wiKGN_{qPit&6DioJ)1%7f*&1z-%C#p;ffj@yZG26M> zDz4biO(eaN76LPoV3d|)@}G6Mko2MXh!B*XnKHuI z1NYAKrr_uiV4ylO9}s0CgFJd#u^1Xs)<9;0NQ9u4E7U?ZW-!Pzjv=@d#JB=iquuc! zHi3JOf%%0-VoHH1>26|xt9MUa86#s61FjlqAsDdu-o+RHYFx|SLCbqxd!ym(=~QKGM-4xD@{u+5tBJ3scEHoiH^JYm6#~MN@Vx61k$zI-!i@oD3wU9 z3TtG;x2CXo@Ze(eJZ`$fX_?`8msyKfPOFNiCI4wv<|=wEXg0j~fA1`+u%OFPR7dAo z)W6wIHZpUYb zqobZpOg$VG&0hpX#47?zE=hbhsWj>H%FK?MV~(w&ncNw zI=1xR%5LksygasiRlk&e_g6S87F7JXzoY-p`oGoxtpPOyn+HuA^gk<~uKZiovxAF< zG!AtSy?p4-p@(n_nmcUMuv5dAkH{R+P}8gC?wYqo&Kdb;ZE@|&QFqpTHRkcL3&yS- zd)3%2V{adO|JcXJEv-+eo2udE+cKe2vheM|ky38@qECzMa9o-l60v7M)i32B&oP7I~$EQ3$<+Uk)nDXZ-C#QTl<;>Ku zse7g#n0k2XyHh`$dTQ!77dK9;oi=gWtZA1`TRm;#^mWs(nX$7myfLXUcjl;B*Ufr) zcJAz(X5T&gkxQL(ADO#%?kjWOocrF~6LbGI_q%zHdGYhI=k=NQVN+q#+NKRnA2dfa zw>1CD{KfPCu;8`@dl$UBprfTv%Z!$tEnh9Hy{vT6;zf@v9=GJ^iTgdFQ)n*DlLqgvr4^r``lGJ{7c#OzPgUvoiCuX#CIs0 zCGwxG2zm4WXIx7I+M|wJ)74$Jt!fak)RC{o**B`G#!+<_r+qd9^;WlP;#&)rnde%b z(_y3K6z8V5s%qd(U@@=^=;aUPc?BTpwj2LTT`eHbz#YKfteGm$u}sadPo_7HR(tHT z)GYf6wa2y%SjO*{`2C66W4TPdYi(22_NnS1CXM%C4QG$McT}r6w!`Y6gmx$2^3@RA zz4T4{)C1sjhJB-=*-DPKol;I)yP82gZnFH%_c`G#^1si@ttoI9TE79$Ty>ZA5miq( z&X%g`Ejv`YwL?{4^ZYi*cCB&7cZBzM@%)Hmsk%+x1LJIy2}xruRJU1M)NsowRl@r# zncTvxx_M0hra_$`*Z)Kp*^@efJf_93c|B~NYO_a@%AS-zuu_o+MVx2VfB+@|WF zeTk;K(7qdl)%rdWUT8iDFZ^J+%y$%=cN2aAoObk46#+g74?=-*ZIs`d7s3xeXkNfG z+d*|e=-v}Jns_g~fDfTyQNC}X|DA;I0{?ECsv4-T$p_&@C_oo}*8o>`0eGQ#Mkw`` z{H3lszn#=ocn^d`D^5$?l?=E+6LSK zFY5S~XMaG|*xyq#c%EZlMg1Dpa9|q0x7)5%WjqhDx_#32ynuw#7XJoZ%?-p3+gg=w z+o{sQ_b1=qv0J^v_qp$Lm8te)g(e-JX6T!+=Q`Ls4!8K~e50H%XblulC4@#e+l%qW zEi&1*x7lf5MyeTF52!ZdYp2x`!=91MvaDqJRE=t?4)>u!<3g~u zXsiZU4c|X}|KU66d&RfMcc*Ww?<(Iq-%otAed9WkIubh^XYch`IJoVv!eAxcspFZ6G;e#LE_vazU@8xEl(Br@TKd&lr zw|L!6mwCKua^u38rCx&@8rpix!#(Y8E$WtJXOt{ z>GpYMlbLh zqvto(m3nP~cdFR)w8K`=+cr0Od+mL4 zJzk?Z@JwxWdT{7(Gs$l(xr}Y{UOm6FE>A0!;HmQ(qr7VPUY32RcBwb4M7f*5^-Ki! z#%s4VJ?*d*mwKHgyo_jak0P5U!Oj0u8a?i6etNv|3o|ovb18XviPu@|b@nOsx=P&c zu~albH&1hw$GvTOWA~RCk}RTxt&?Q0tB==6Dlhd$mbeFkx6~WOd#g!!_!qz>k1Bbe z7SX!lo~oxKjU;l6E^$|bJrJu28Z=jxdSgn;QmRY6u|0gH<_m}sSMsz)B^S8M++(#c zSPI5(+cwrS*3&%SYj|q+a^oo}kqqKtOEN^~fBn^K6ffLX=5f2Lw}B<0^Q*f|e|LNB zh?Y_8_BIKpYo;_l!}h2<;~8tAEq!KfEu3_Yf@M0gXH1jVJ_`0Uxv8Hi(biE-Egr9J zRC5dbwvKAf;JIlg>?c|?`ON8jgkr?lEYvK&6UGyoo^sz2t{C6}-LmQyNcwG+}t1&X3{} zZ&EOJiTu#9OZAh)F4IpEwQq?xIT*EEe(0$E^pixb&`%Pze~C9G7p zKS|We68=<`cq>iKg-UwCshnzo8^uwFqV}xvCXS{N^=hJ%n%>wc?Ouzg?wN4B85BPg z5i5V=lKDGxudSD3^wc`u*(_WX==^WL`Z*&g`Fo>`V(bUFX{tEivKtG42W)oV>5lC> za*R44BN`ibLktuwu z=e2yvq-?+Q#_73al04wO@(KL}<*V8WM69(k5D_%+a{k4&H7Aoa#ou^qFk^hU~UZ5O# zU^7b@%In^`WsHZ)CfB6J2^Xc+xT(8vPv{^LY}Q@My9`+2r_35+n(b{BPa;v$4wvXy zW{L&8UjdF~yj`Hbt$=cFWK8J2Qva0{lCwy*v~oAki}@z`N=p?Ai8Q&fE3!_6&(iTh^lDf&0lqEpTH9Gx5 ztwqjltINo5rT!+m=5o>s2NqI`C0YZSy+WWiW{VEwExkjimR%19N!_&_c1lj5B}?ff z2eW?=+#;#c_XVW4g*RqNR`4Xb2<@Z|twcIZ+6aw=XRG;Vwi;88!{UQT`!4gN^XD~QVNOHj8qCP;c=*}NKH+xAgxxktF(hMauyj} zg?{MEzxDc`**8d=F!hnpOmxk1V*J?nT{$j2dfzU(ciuVUk-q=e#y!1$bZunh_5aUk zNqVua{8|GaMG98IbK$;dv1Np!{T9KQNsRXz7+-dmiwjG~Vyrnh_pL?y_wXNkb8MCq z%gXK?=Rf4OCA%jsxqrzjU^MO^V>wwD&u(KP=j)O=jh(8}SRu_|tu%{!OF7U#mtM%j zp`ij*sEVjzZ%)V;(~e3hbzeOyu2B6MjSWmLk~vb(vBmeG%)hlNhf}VH|cbea3XgpqJo@W2Ty=X5(|=QZ-l2Q%$Pbu&RgD zCUw1fS>2&NQJd9G%s_svcB`F+jT?-|)pe|`p2oWPFR**JRlTM@#B#-b>M^`|e67Aw zJJgfvcj^tSv(ASbx1e!;Pis7)-c)~3N7Y;EZS^U7+HH7R9n>J>aco6{YJfH#H$bFKBhZ2*G6xM#zjC3Qz$mC#Twr%3{hK8_p zE0&a(k1Y3xbzvh{E?T)_;pJh?{&2KETxf=liOmbvtzGC?VFnkQ!5TA|Wd>L3z%{F7 z<=W;23l^?e>$)=dsPm~9HP|+K-RhO{qhipY!LCKCn_Cx_Eofe|FsfzA!qp4cELo#} zMJ#V#uzKYR{p`|M^<&I}C94;#TYlNHg>B}i1(=UzG$=Vi7q7xt;f~QO(k|q^PFd>4G)z;`%bM4&pslbe zrmY?t1f9>MynNy66)M{Nt8ocF*(H}y?B9K(JC4T4jR{ku z@*_7ICnKxFODy{%H(Ec8+-SSYb}F*k(dcx9mqag)jgDAMtaqZ5qm#o=N4?|P6!nhz z%T?`q&$ZgM$@QM#jN2TyIdUWTPe+`N+Z=IP-Xu)z{3rQ@{Hu=C|DqR1ZWMfhf0B#& z&&(t6D>_-q5S1UD95qpYpXI0}>+T3fjz&Fq+N6{R|&=c>` zT0he5_7gP8DRjo?v_8>C->7fVi{ZWvD#q8K;(&ObvwVkCHjsyY&F6QiZ-^S>JD|n_ z>Hb52*16)bs;t`GK10+m1I0 zFEaEbtugJg^@)02~D0 zYovRf=Qn`2fln#p=fJmo!@Cte01JUWKm{-WsPr9GRlfJ2_q)*hUFiKT^nMq5zYD$J zh2HO~d-#4Y@N3{c;1KWL0%ix>Kx~(G&_p|EBDec=J18XV1C;uz$n`#Qy$@PBpj8>P zDuY&K_(`mzeKgTNnxI=5?V}0WmC-($)C}KT+DH>p)PNMNRkMAokfa86sc$Qi)PN*4 z(0-bbpavwT;d|TB4dlHY_$6=$a3^pVa5u1nGCc(B1Re$+0UiZ*0lO*7W5DCU6Tp+e zUf>z>-ADK=@Eq_wupc-8yvVngfR}++0BL`(f$I=?z0UVHfTO&Bi{Eea{1Ih82?W~Y z7d)Q^z5=9uUXFe(hvIE$*>bdOIZ{|d8|4lKVLb1%e7m6hE;LX%)ISRK+u-+6sDBjd zFNXR@q5e^*e0+;k(7GkPA2UXU@Gq}CY(k%op6Tl4s{89Z{&HV?;SXB z6b`%t2lk+u%i+Q;aN!oTb2<8X2pW0_9N7g&Zb4HIL06Zx z(GuEd32n&VQ8;rH&K!j^N8t=-dw{!v9hBoCU?=b}@CfiIunX7?JO(@tJOMlj>;;}7 z|9ynd0?z@@1N(skz>9o)33wTJ1vp6lukrp6dA&~f25^-3Z}IzWoXj7iTeLF(9wHa=;!>!G5YX@A)gF`#u%-wKg7aVDa zBkgdc9d6tQ7uw+fCpKtlCY9Tva=V|(2$64k)$@YPCbHcBs@2mD-_FdkB>_hfrxVRBDGx?NF)RPo*8KM92CLBC98m(-X+) z31svHGI|1PboL|T;X|M=xdfS;>3aoDa0D5A1=%|YRSrUlgUHxHaydyZC&}d` zGPnmB+=C46K?e6AgL{y{J;>l5N^p`AoTLONDZxofaFP<7qy#4^!AVMRk`kPx1ScuM zN#tw~r8r3`PEv}K!5V+dduFe`_mP|Tk(>9CoA;5M_q(*BKnuEo_uGMA0(Ss+0(Sv- z13y;s50NGy^>6Vkk{=Ik#?hw7L6dQMo;(DtSIwMy1mU&3yAId{Tn}spwg6j!`-yXq z@EGB@gt1^c0+ru}n{R{h2pErm;RqOxfZ+%jj)36^7>Mnl6G3y$D-4e^_RWu#dRYyhq${&m16 z;Cf&)um#u(+)vtrgvSW~1djKB_koW|_X+SRd7dKt4EUVqZwS97zKeFhl(xH+w!4(J zyOg%Ol(w~$wzZVDwUoBCl(w~$bqYIuz6*!~VtrRr?zxOOH&gD#lzA@NKs3P-%Dfhg zSA+3t%Fb#WEn^*U1;4K%+`zk^@_aw(jsYL>d=mJW_n!c#fX{$0cy}833iyWKag<;` zCD>01_LEz?ct#_~c5>WLPW#DeKRN9um;L0jAB_9KxF3xB!MGnR`)QGO-%haXgeUD_ z+DScbq#o_m;YR4*4(5~etcSpS5*`TlonYSy#+_i?3C5jZ+zG~=VBE>tg`Js3xNi>B z%tmu$!{xgP!d>u6%L%OlRIG~38ulM*4L;b^OtHWrk!)U9+ zQ2jVmKMvK8L+RsC`8X8*E7W}-s=g0J4?xiaQ1AehI{sm`QEZAf+|wUV*l5o&dWS{JcHxR$ur0h@s9fz7}cU@LGxX$}$|Bm5I--vizUJ|^8K zz^CMQitsbwb6v8DNX1dsIl`GS#!${!zQhs6^IPU;`Gno)XoHcWAwV@UHG;6t_bQUJ z6Uo_$>!Va zfStg@z$3t;z%F1nc|8U^4m<%o3G4;-0nY-@0nY>bfdjxn@_UVRGH-mH-){gie|($p z7A1W50c1?1su!4u@YF#^IH1db-)$;zKU=I?|#bj4dB`i z{1UhWxD&VwxEr_!{PzOC2JQpyCyztCe+xLq^GBpV349E$Pk>XvXTTS{I}LmVe8X>9 zTXeCuzN*XGBe!LFFP>QB6tS2E>HLkQIP|_l7E)EA`FGipMa`tAcnss2c+K4mai4(#4{!&)OTlI?dhpbk&%PO}n ojk(g9PAtLVP?*9aY%s*7 - - - - \ No newline at end of file diff --git a/android-application/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android-application/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 7353dbd1..00000000 --- a/android-application/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/android-application/src/main/res/mipmap-hdpi/ic_launcher.png b/android-application/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 2bea069199df50e13b1572d2bcfb6f46fd317e99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1462 zcmV;n1xfmeP)6gXPw zL$rl!EhV+J300HE_=hplv{oY;l{PUNwbp2SR->`e#Eltemc^XFJvm!%@Ape40m2Ty z`TSW>2!9X?LzBE8;CRO zH}~E}vBUzBaiO9pi_z&g8d%K6DYj@K{ZpUl=#=SDx0r#ds;B+ngs(}ah$W$eNgl2YEQ#D?(+lme_#qud&0A2W{~D zCJ9R28sy^7axrsim#Og49v;qgi%_&wOH4rdc}|$vA;7z6C9c^J)>Jv*k0Ts(H!Bfu zmddlbScN)|3e_bV6y(JrplJXd4S@li#teFIrx11)Q3l>quENR3CHQbafOES9qjX>E z6rr(te!8|aUxPdGAeZD{AwWY9<-n!qY~U$U18%BgjRKcPIjFC6gcZbEgh2ZBM%NUO zG8F%N@!FG5NbvQL4cb=QBZfrTP0i!fb`jq83h??i5q91u8~QlISL^_x&gf@)1bC}g z09Qfa?C=z6@au>THx#?-@r*fH>|K58cP0#5&kl_7CS&lUH|JC z2iu!MXT}Q%@sp={BSQlHPEDz5WQPwS1@lFjMWyobULLB7)c{)KgaZ%fz|RP$w?z)> zk3cz@~BOp=;L8WW9Iw;HB>qbK(jS4D zL;)w838@10@YN2P`<4knvpv@4* zKv{7C^?-)Va08+_i#p_mXLxw3Q8Bco7smRqSc#6Hz5sA+hyq)U(QU^h zw%oc3)ySkWJZYM5zC=J&hL*Y2pkOZ!^7`@3Qbcu5or*fp^dLwgOJ6rFcUbFQtQv*+ z_amH6WfSQps0?T_ripkX&LP2u%(w-#4F|A4k8*ldiON1On+d4EDf`~RG5u_hz&=r& z3y`;2@X@_hYmI{e@?YbfQ-CJCS-$Qj*|-;Dfc#dcnL(aH*=Kex28jJvg8^cI7$63S z0b+m{AO?s5V$W)@XEm-|iS4mEAfD%aQ3K*QuEF1#Rp6Mh=njViGBPqAFq2_Xq!0C8 zgLbPd%kNJ+w332io;$x1imD#-Z8b z+&D9qo6&BF)jK>EQLUw>rY=rNNx3PWjbfl!D5n49Eie`_w%B5et+-f!0|W{;=XJfD QumAu607*qoM6N<$f^f;NH~;_u diff --git a/android-application/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android-application/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index f5f7227c287f56e0d6c853a88b703eac3b66450b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3045 zcmVt%|K63Z-aVidb6_ zRB&lMNU5G<>#4`u4T^0=pkO5^g_7a+`(Ezz+)QRNGg&8-ch1e^yyd?8fA{;p|G)R$ z_b$7vZMROc#04q(@eZ?fs;H>wTwGk-g}>omc0LR5_ODGDGyi4 zhauZhzEll_Q9k_E=mm`MaUaShzvAOD^<3`v1B-QU=e<<-i#kTBJ%- zsSNT1SUtvj76)omn+mYb8uWGsXur!Jm;k-rY(>^x2Pn3IZSikkt8a)h@ruqYM&tgg zHo7H&2?msM&+}|kptiOuIQZ>@hU`%qd$F}ZX`rZW*vmGyDoFZ`AdDt7;HciH=FpdB zWRy<<>L}dK+$tdH!UrEOC5@wqHKEva9?9qU78P$Dee}*Wzvv{Qywpfm34k=CMVO?3 zGp?P1Qx7DU%T?a2AnBAu#U{nA+7mc+K!QA+w_$58cZ-wE>8%KIdj!WHq|eM|bE0Zv zQvur34g@(O;f6=NuFOR>-nCHKq8I{4C~1j+4lQextLcM1RFsZ#PRT7|0wCQMxY{|$ z(J1*c*ya)pX$ z@S4-v+1V*UlSgGpFC@hFAH$yZ#k(QQrg^Ed?=!FwX0!6OzC0_BwLc93$ zkIdqHl~J5~#wbp0Gl|`I*~Gl5u9(V+a&mI6uIFZo{w()*ud7CR#c%Gnh*Li?iRYKw z#7z_2V)}TGSUlY&K6ua~jz47*E3bEH42y+m1|7P)-a|L7U+)e zd81fR5nN}AM&yZK-D{OBa!1ste3Y4B-mB0u>f0YTn#HG&nZ=(_cHe2!Kx+=yCD@b- z29{v;={7@$4+Dz?Rj9S3C@U*#puV_(s?JJ3e#D}Q@rVL%gAKTMmP35~v{9^|(=Zs?NyBxH1qx24!;W((+1|sNP}HDh-FizyF~{d;vhiaS1l+Y4qfo zpPIz7%HXV<2H@y+pKUgaDPuihyX`_q!XLnXUbpH7rj7ji7%~A&b!{(reLq`a(-^@>77joJvgSFXSbIyuI+PEFG2&f7>M*S|G?--M61c*b z0Q8M}tYTboV35d?%?lhF@Vi#p#5GrW!)iB$n>JQ0wfR1R7ks!O=j_r+gL8?=nl-i9 zXiCi#8vvcC?Fp~%ogY{=@tia!JZe{#d&J4DwX7J?fSb)Muhpvq>#PxJ%H{=j&G@~m ztr{5l3gF|RSHD%O#q=9SbWZtbuVx_ifz)nHK0~IG zrR>0u9=2$~f%?Zt+QghmOB8K3+xx(xcbzrbGOfNG=sl;6zeaj%D7d6;BsXCOd;wWC z!)qY+aKOu9%hF0`las%(U~Ktl4-uwztVI7h^wMUmCZJqj&x%-v}E6O<1*(%)P=zS;_Lo;1c2)e~lRyZv}VLV`hgPo&{9Mk6PRl3rMr zQza9w4)fqJH#c_|Z8z3p5O@*zN0l5 zlzY3QEM9;(AArqQNZZ3&{*r)vpn}2`t1R+k&yBP>?3J(S>FM3^GX&$3SEQ@O>;fui z51*zEkv50DQHv4=3>Z*|#IZV7m*7E0s{8lvUm_>zBU`5^5glwW7}iKvtBDbCG+Q{V z$jr>VpEjnXq+H&pH^_xVSq-{;#l9G}*!iZh}5w*sUy(F~Fb4&165$sn1N*}He|q?UZqH!dL|fnPqz7&K_mMBMlY zQvmtidsMxWDT}aJEJvU@Q`lzN_7;B&I!^XN8X|!k;c`FIb%jlr+IaY&zs6HUPz^gVhvf>EHB_p!jrPcrV@)_nyNxur0DpQS-4AjZHm!_T<-CGEpo8 z2M)Xez4;=9{5Z!wevz)u$4!(EoP1mK{pz`DgkqhnoA<*Y z_U2G7KcZlQ_C;`mTZauB_7DL3x!G(!1cUzq7dZy~IE`{fmebtFV?2lF@)};tIwV_I zXDaU@2b}HaBTIfS$aG_ZDZ%2}zbr0jWAsA^wlh_r(Ku%uqD>hK|K~m&bMYLWE3e_T zDXdE-t=-!7XSxD_)s?-?oCNMMkaIDd3zoo9?G^ZpH2Ya&urDqVrQi00000NkvXXu0mjfjW^xR diff --git a/android-application/src/main/res/mipmap-mdpi/ic_launcher.png b/android-application/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index b4f921ccc5e97f1603b4eac66f70756abfed10fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1028 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 Dbxwq2 diff --git a/android-application/src/main/res/mipmap-xhdpi/ic_launcher.png b/android-application/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 3ab278ceb761247a2e9ee849c2056d2d37644b61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2217 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 diff --git a/android-application/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android-application/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 2ed89a341708cd91f93c660415e844747cbbaac9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3435 zcmaKvS5Om*wuTdW5owBsUX-p72!hlop$SAldNh$9nu3%N5Qr4%AP}TTlNvf31*w9d zAP7haASG--nwZc-2M>GZ-kCdR?l})@{r{|o^|WTq_s5vP_1IW=SpWb4n}I&e>|9^{ zQ%nr!eMNVn@qDge0J~!zFh$8`^}>%`?uq0OWg*@pKo|@pFQt%=GoiRmj^rpNF4GQz zuv{9G+gQ0Up%qqUB9xzxEA~Ii_~i>zs~;b>ou0CsR^ag^k-eRA zT$Hl1GVCKHdu$d==)rBy+|xUhFMAE&DQbFiiX*8Qs#O#E`#@}+>R17=JEU5Pl`D;9?EpFU&UHaV@b`6fKO z3iG}9qiJ4rR1_B%YnW-&D<1nMNA?>_As`a%M1Gb?e9uqUh;)61hQUiP`nu>ICX+Lo zYs}EY=N~1$7+#B@QTt|n^HYRFNsGk*{lcfa(_O-He zuaHLZC5r-3Fo`kP9En^X0}(o^&q@(aPEKi3kLV<8fNnQsWa2s>AdZCDOy-B)YLlE- zba2~z`9N9*V#fmnU<6f!-kkfSNkaq!R4MOAUv`a_mzS?M03qlhVJ+a=RX`dZPvjDo zt^ug#0{m2Pi4xFDzyc-?9UKz}Q1m}~x@dqYU9>3lTsehlU^qz{7^iUT|L^k~U$R$N zj`rvgofPl7VYN+23d)3PRjs0%nlhE*L>&vZf$Pw`QqHc5vARqV>W&4nJ~YlS_{1bl zb(>UlcARh6w(a>L@PIEw$=x2tR`Ir%PT!qOARL|5Yx;S)@W1YADJM=NX52P(la45X zNr4s}*o}~Mw@HCNe-5Zehd@@}kR z>)?|d74^`T@5Ro!AlETv%+8lP)Zyxbzk{6KArflhMs^1oh6tRd746{3m809AEJJ-H z5n64%?x$_eQo(#z=+S{LwCER(dCQ~{Uu-3kaO3Z}nKC02m? zOs3vFu$AEr<5@+|KImc9l`NAim8>b$g)y7l0;)dnxBlTd|EZ8s)yFrGoj+VR^^3_! z-Ij1qLTq{7%&Ot;!yoi#ZdH1uAZ&-*>Qm0gA z(4%ACg|BU1t*p%wf0NSSjOn3`SZ*><{w_DOZg6ZjKi}GRJ(u&WiIg@Tu9{_%0uUFb z=MSA-HBBF23SIvFSQV)yQm`kxU;gJ8a5b*3FkA7q2cJsD$ltzpCUbk`AJ+XU_Ls0H zhW=$4rKejLlcxM5Q3GmfGixr3Xxw_U>?{4#eWjz(5OjT4c@>Cjma+RrhT!0;1a^Py z4EFMvs+vSk9zKKT;Hw#5AC0|z)SEe;-8(q|lT7~_ft!9V39i>ep&4q+{+wni30BM` z-PUbiw#E(p5&ptAT7zEUUm4W#zM3pzVyWQNZ)TGY0=KsIRtT2$4o9E`i=SY4 zyhlg4l14+Pdz!Hf>r)>a?o-2SqW})aH<>9QD}Cocw|c8!LR2k)MQyHlcqO7r)&Uo=ek+M8oA|m)E|0Sgs#=s3|LRd5l42V7{ZLjvk$&~zA?(BfF_W#l z?)~A|4$cEG-PsB`h_GuWA$=Ndi5trL$JKX@$lOS()?bJGMX3>Z4GMUY!Tr9EbM}fn zV0=6gYyun#KQn_W;ApSmZy8bbE@D)maZ9NVgKfFiO9Nj$y74gd{QJGM&r%MlxI*R} zg1$jwOBIi9RM^>dds^^49GP1Avc^

_6r!{K;>6k)4U1n~&*17EcfS)b2KLtMT5JHX5M)L86}j;(s8n+5bWo>9qe&S|n!_#27RCl+MBejB z27b_>J6$}+itFoEUs9Y|^akLaWt@FzWY^rSf;65)P@@ycoj;6sO(Bzko)v@d4vths z&_Exi_{f|gxTP`qH;v7YXpBx`i?4w1=T?R`9@}aj>*-?kv#SJVx>RL~D%dqQaV64e zDgp&^2R1i1-`3I5@fULS_S*;9E9|65N*VH5AxzM#j#^lIJTn=A?KB22(O7&FV`2c` z$2{M`V_C~%t1>)hdQ-rkWp7~8qM2HJ;LwU_ex(TLQLm|~Igc#gBV++Lz$@^ET?#}4 zrgz9?g@|G02NdY>Y}#~KsR+s=s2BnHYmWv3KLa5EfDlkFX>D!&NoQy0 z--sq{0#62*0IFyT!E2Z!6vLDxz#Rc}buAO{u=0p&5X|D9aqoDB`uh6I=$ZECpjHRI z-MhnMp*VhR9KaXw=dmJGa3F{LbqlBT5afBIDML|F(L9v=$vfQWa5x?XsGLscN3f~@ z8UUv&h1&3ysfSLX1{8RQ67%!wJbX^e1UtMGl+)#MeS~|%J)%;JR}0a-&sWc3fL_s@ zb{>NU9+L_I{>WE^BFK^-5iBe$oL5m%aV)HAOH0cG1h`)k z@LnRNco!?z07fVVfC+$tLP0_Jy$CVAf&Tya9KM6^Lg0CDPMn(*Z!@md)z$S9u8n)Z zz0f@!hkHX?hz@vuh5&=UTeJ3x=2Y=m%;2#R;E!-cP{FcFpXy$r-cW`vMUx0fdd%S0 zENh5>w;N~^S=}=TjH{cPnrH zpCNGnjXu8~-=%Z>oX+(ws_Id#>VVFhM`b zu=bMG5wEb*E9lBFl_^3o^JJwEHB2QMIal7w6r-KN*vY``W{d1*4(`>vR}E3^21?xg z-EKZtC!f2Wuhq)eZsdEZ(Ewk@_dK1S!34cndpY7(h5{{SPzs?uL^;!nDyA5<48{fq zW)p+7MN<+b4ny?6weokG`5cXW&U(H^HD7Zk--EL73h;{47YOL(7_KrzQwZfDrZBCT z#sDnlz_N^iS-~K!WWXv#QBuRA|DXC?C4aYq&sE0fF6L`Z<7-dREPOP;3+UxYi87c9 z5ltxy8H|%Pk5Qy4$#l(wL=*M*Y1;RuY9OD?*N6u8Xn+^c%aJjqFcm{7$3#s@3N&Sj zCi-Xe?@ovTbOE~@Ij0b@lw({BWr+sraYKMy0H4C+{{XUc-Zu>JP$vKY002ovPDHLk FV1lMo2yg%Z diff --git a/android-application/src/main/res/values-night-v23/theme.xml b/android-application/src/main/res/values-night-v23/theme.xml deleted file mode 100644 index 67bf33d2..00000000 --- a/android-application/src/main/res/values-night-v23/theme.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/android-application/src/main/res/values-v21/theme.xml b/android-application/src/main/res/values-v21/theme.xml deleted file mode 100644 index 2dddf810..00000000 --- a/android-application/src/main/res/values-v21/theme.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/android-application/src/main/res/values-v23/theme.xml b/android-application/src/main/res/values-v23/theme.xml deleted file mode 100644 index 8b39cac1..00000000 --- a/android-application/src/main/res/values-v23/theme.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - diff --git a/android-application/src/main/res/values-v31/theme.xml b/android-application/src/main/res/values-v31/theme.xml deleted file mode 100644 index 81875579..00000000 --- a/android-application/src/main/res/values-v31/theme.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/android-application/src/main/res/values/application.xml b/android-application/src/main/res/values/application.xml deleted file mode 100644 index 9ec91c2d..00000000 --- a/android-application/src/main/res/values/application.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - Ack - Ack (debug) - Ack %s-%s (%s) - Ack %s-%s - Play Services Unavailable - No Play Services - unknown - Navigate Up - Unknown Error - Selected - diff --git a/android-application/src/main/res/values/capture.xml b/android-application/src/main/res/values/capture.xml deleted file mode 100644 index aee80002..00000000 --- a/android-application/src/main/res/values/capture.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - Map - Log - Insights - Messages - Enable Recording - Disable Recording - Controls - Close - Unknown - Not Connected - Connected - Position Disabled - Position Enabled - Settings - Bluetooth Settings - Audio - Internet - Monitor Status - Status notifications when ACK is monitoring APRS - Monitoring Audio for APRS - Monitoring Internet for APRS - APRS Connected - off - No Callsign - Audio - Internet - TNC - diff --git a/android-application/src/main/res/values/colors.xml b/android-application/src/main/res/values/colors.xml deleted file mode 100644 index 11ec8270..00000000 --- a/android-application/src/main/res/values/colors.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - #FFA72B - #212121 - #70212121 - #FFFFFF - #70FFFFFF - diff --git a/android-application/src/main/res/values/connection.xml b/android-application/src/main/res/values/connection.xml deleted file mode 100644 index 9e9be1bc..00000000 --- a/android-application/src/main/res/values/connection.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - Connection - Callsign - APRS-IS Passcode - APRS-IS Server - Invalid Hostname - APRS-IS Port - Invalid Port - APRS-IS Search Radius (mi) - Invalid Distance - Invalid Callsign - Invalid Passcode - Incorrect Passcode - diff --git a/android-application/src/main/res/values/content.xml b/android-application/src/main/res/values/content.xml deleted file mode 100644 index d16250cb..00000000 --- a/android-application/src/main/res/values/content.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 60dp - diff --git a/android-application/src/main/res/values/ic_launcher_background.xml b/android-application/src/main/res/values/ic_launcher_background.xml deleted file mode 100644 index 606b9bd3..00000000 --- a/android-application/src/main/res/values/ic_launcher_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #383838 - \ No newline at end of file diff --git a/android-application/src/main/res/values/info.xml b/android-application/src/main/res/values/info.xml deleted file mode 100644 index 3c3aebd7..00000000 --- a/android-application/src/main/res/values/info.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - App Information - diff --git a/android-application/src/main/res/values/insights.xml b/android-application/src/main/res/values/insights.xml deleted file mode 100644 index 1d4050a6..00000000 --- a/android-application/src/main/res/values/insights.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - Insights - APRS Stats - Nearby Frequencies - No nearby stations with broadcast frequencies. - Reported by %s at %s - Packets Received: %d - Stations: %d - No packets collected recently. - Normal Conditions - Rain - Snow - Humid - Windy - No weather data collected yet. - No packets collected yet. - diff --git a/android-application/src/main/res/values/locale.xml b/android-application/src/main/res/values/locale.xml deleted file mode 100644 index 73812f29..00000000 --- a/android-application/src/main/res/values/locale.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - Locale - Prefer Metric Units - - %smph - %skph - %sft - %sm - diff --git a/android-application/src/main/res/values/log.xml b/android-application/src/main/res/values/log.xml deleted file mode 100644 index 7a74c146..00000000 --- a/android-application/src/main/res/values/log.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - Radio Packet - Internet Packet - TNC Packet - Local Packet - No Logs Received Yet - View Station Details - Received %s - Hide Unknown Packets - Log - diff --git a/android-application/src/main/res/values/map.xml b/android-application/src/main/res/values/map.xml deleted file mode 100644 index 2acedfcd..00000000 --- a/android-application/src/main/res/values/map.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - Map Settings - Number of Pins to display - Disable my location - Center on my location - diff --git a/android-application/src/main/res/values/messages.xml b/android-application/src/main/res/values/messages.xml deleted file mode 100644 index 53119d09..00000000 --- a/android-application/src/main/res/values/messages.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - Text Message - No messages yet. - Send - Disconnected - Connected to: %s - Compose Message - New Message - Callsign - Start Messaging %s - Radio Packet - Internet Packet - TNC Packet - Transmitted Packet - diff --git a/android-application/src/main/res/values/prompt.xml b/android-application/src/main/res/values/prompt.xml deleted file mode 100644 index 16156723..00000000 --- a/android-application/src/main/res/values/prompt.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - Save - Cancel - Enter a valid number - Number must be positive - diff --git a/android-application/src/main/res/values/settings.xml b/android-application/src/main/res/values/settings.xml deleted file mode 100644 index a895b0b7..00000000 --- a/android-application/src/main/res/values/settings.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - Settings - Cancel - Update - Authenticated - Made with ❤️ by Ink Applications - User Agreement & License - OSS Licenses - Onboarding - License Agreement Revision - License Prompt Complete - Show Advanced - Advanced - Dev - Must be one of: %s - diff --git a/android-application/src/main/res/values/station.xml b/android-application/src/main/res/values/station.xml deleted file mode 100644 index 9a59d495..00000000 --- a/android-application/src/main/res/values/station.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - %1$s at %2$s up to %3$s - %1$s at %2$s - %s - %sº - Recent Packets - Station Info - Show Station Debugging Data - Recent Packet Limit - diff --git a/android-application/src/main/res/values/theme.xml b/android-application/src/main/res/values/theme.xml deleted file mode 100644 index 9a99185d..00000000 --- a/android-application/src/main/res/values/theme.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - diff --git a/android-application/src/main/res/values/transmit.xml b/android-application/src/main/res/values/transmit.xml deleted file mode 100644 index 6467c2eb..00000000 --- a/android-application/src/main/res/values/transmit.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - Transmit Settings - Repeat Rate (minutes) - Update Rate (minutes) - Distance Threshold (miles) - AFSK Preamble (milliseconds) - Digipeater Path (Comma Separated) - Symbol - Destination - Comment - Volume (%) - Must be exactly 2 characters - Max-Length is 43 Characters - Must be between 0 and 100 - Driver - diff --git a/android-application/src/main/res/values/usage.xml b/android-application/src/main/res/values/usage.xml deleted file mode 100644 index a38b2de6..00000000 --- a/android-application/src/main/res/values/usage.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - 2 - - "Usage and Privacy Agreement" - Decline - I Understand and Agree - - Legally Restricted Services - - This software provides access and tools for the amateur radio APRS - network. Radio communications are a regulated service. - - - Some of the functionality provided by this application can be used - in ways that may require a license or be restricted in your area. - It is your responsibility to research and follow local laws when using - this software. - - - Data Privacy - - This application can be used to transmit your location and other - information to the APRS radio network. When transmitted, the - information you provide, including but not limited to your location, - will be transmitted publicly, either by radio or by an internet service, - and should not be considered private. - - - This application collects usage data using Google Firebase. - Information collected may include information unique to your device, - information about actions performed within the application, - and logging data related to using the application. - This information is used internally to improve the application - and is not shared with any 3rd parties. - - - No Warranty - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH - THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - Software Rights - - Copyright (c) 2020-2022 Ink Applications - - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - - The full license can be obtained at: - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - The full license, as well as sources can be obtained at: - https://ack.inkapplications.com - or by emailing: legal@inkapplications.com - - diff --git a/android-application/src/stub/kotlin/com/inkapplications/ack/android/maps/MapsImplementation.kt b/android-application/src/stub/kotlin/com/inkapplications/ack/android/maps/MapsImplementation.kt deleted file mode 100644 index eea6979e..00000000 --- a/android-application/src/stub/kotlin/com/inkapplications/ack/android/maps/MapsImplementation.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.inkapplications.ack.android.maps - -val MapsImplementation = DummyMapRenderer diff --git a/android-application/src/test/java/com/inkapplications/ack/android/TestData.kt b/android-application/src/test/java/com/inkapplications/ack/android/TestData.kt deleted file mode 100644 index 42feea26..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/TestData.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.inkapplications.ack.android - -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.PacketRoute -import com.inkapplications.ack.structures.station.StationAddress -import kotlinx.datetime.Instant - -val testRoute = PacketRoute( - source = StationAddress("KE0YOG"), - destination = StationAddress("KE0YOG", "1"), - digipeaters = listOf(), -) - -fun AprsPacket.toTestCapturedPacket() = CapturedPacket( - id = CaptureId(1), - received = Instant.fromEpochMilliseconds(0), - parsed = this, - origin = PacketOrigin.AprsIs, - raw = byteArrayOf(), -) - -fun PacketData.toTestPacket() = AprsPacket( - route = testRoute, - data = this, -) diff --git a/android-application/src/test/java/com/inkapplications/ack/android/TestDoubles.kt b/android-application/src/test/java/com/inkapplications/ack/android/TestDoubles.kt deleted file mode 100644 index 6542e778..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/TestDoubles.kt +++ /dev/null @@ -1,103 +0,0 @@ -package com.inkapplications.ack.android - -import com.inkapplications.ack.android.maps.MarkerViewState -import com.inkapplications.ack.android.settings.BooleanSetting -import com.inkapplications.ack.android.settings.IntSetting -import com.inkapplications.ack.android.settings.SettingsReadAccess -import com.inkapplications.ack.android.settings.StringSetting -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.data.PacketStorage -import com.inkapplications.ack.data.drivers.DriverConnectionState -import com.inkapplications.ack.data.drivers.PacketDriver -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.EncodingConfig -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.PacketRoute -import com.inkapplications.ack.structures.capabilities.Mapable -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.ack.structures.station.StationAddress -import com.inkapplications.android.extensions.StringResources -import com.inkapplications.android.extensions.ViewStateFactory -import com.inkapplications.android.extensions.format.DateTimeFormatter -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.spatial.latitude -import inkapplications.spondee.spatial.longitude -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.datetime.Instant -import kotlin.reflect.KClass -import kotlin.test.assertNotNull -import kotlin.test.assertNull - -/** - * Spits arguments back out as values for testing. - */ -object ParrotStringResources: StringResources { - override fun getString(key: Int): String = "" - override fun getString(key: Int, vararg arguments: Any): String = arguments.joinToString("|") -} - -object StubSettings: SettingsReadAccess { - override fun observeStringState(setting: StringSetting): Flow = flow {} - override fun observeIntState(setting: IntSetting): Flow = flow {} - override fun observeBooleanState(setting: BooleanSetting): Flow = flow {} -} - -object AprsAccessStub: PacketDriver { - override val connectionState: Flow = flow {} - override val incoming: Flow = flow {} - override suspend fun transmitPacket(packet: AprsPacket, encodingConfig: EncodingConfig) {} - override suspend fun connect() {} - override suspend fun disconnect() {} -} - -object PacketStorageStub: PacketStorage { - override fun findRecent(count: Long): Flow> = flow {} - override fun findLatestByConversation(callsign: Callsign): Flow> = flow {} - override fun findConversation(addressee: Callsign, callsign: Callsign): Flow> = flow {} - override fun findById(id: CaptureId): Flow = flow {} - override suspend fun save(data: ByteArray, packet: AprsPacket, origin: PacketOrigin): CapturedPacket = TODO() - override fun count(): Flow = flow {} - override fun countStations(): Flow = flow {} - override fun findByStationComments(limit: Long?): Flow> = TODO() - override fun findMostRecentByType(type: KClass): Flow = flow {} - override fun findBySource(callsign: Callsign, limit: Long?): Flow> = flow {} -} - -object EpochFormatterFake: DateTimeFormatter { - override fun formatTimestamp(instant: Instant): String = instant.toEpochMilliseconds().toString() -} - -object NullMarkerFactoryMock: ViewStateFactory { - override fun create(data: CapturedPacket): MarkerViewState? = null.also { - assertNull((data.parsed.data as? Mapable)?.coordinates) - } -} - -val DummyMarker = MarkerViewState(CaptureId(0), GeoCoordinates(0.latitude, 0.longitude), null) -val DummyPacket = CapturedPacket( - id = CaptureId(0L), - received = Instant.DISTANT_PAST, - parsed = AprsPacket( - route = PacketRoute( - source = StationAddress( - callsign = Callsign(""), - ), - destination = StationAddress( - callsign = Callsign(""), - ), - digipeaters = emptyList(), - ), - data = PacketData.Unknown(""), - ), - origin = PacketOrigin.Local, - raw = byteArrayOf(), -) - -object DummyMarkerFactoryMock: ViewStateFactory { - override fun create(data: CapturedPacket): MarkerViewState = DummyMarker.also { - assertNotNull((data.parsed.data as Mapable).coordinates) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/capture/CaptureScreenFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/capture/CaptureScreenFactoryTest.kt deleted file mode 100644 index 26f2c122..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/capture/CaptureScreenFactoryTest.kt +++ /dev/null @@ -1,286 +0,0 @@ -package com.inkapplications.ack.android.capture - -import com.inkapplications.ack.android.ParrotStringResources -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.android.settings.LicenseData -import com.inkapplications.ack.android.settings.Passcode -import com.inkapplications.ack.data.drivers.DriverConnectionState -import com.inkapplications.ack.structures.station.toStationAddress -import com.inkapplications.android.extensions.bluetooth.BluetoothDeviceData -import com.inkapplications.android.extensions.control.ControlState -import inkapplications.spondee.scalar.percent -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class CaptureScreenFactoryTest { - private val factory = CaptureScreenStateFactory( - stringResources = ParrotStringResources, - ) - - private val FakeDevice = BluetoothDeviceData("", null, "", null, null, 0) - - @Test - fun internetDefault() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Internet, - driverConnectionState = DriverConnectionState.Disconnected, - positionTransmit = false, - license = LicenseData(), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals("", result.userCallsign) - assertEquals(null, result.volumeLevel) - assertEquals("", result.connection) - assertEquals(DriverSelection.Internet, result.connectionType) - assertEquals(ControlState.Disabled, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - } - - @Test - fun internetWithCallsign() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Internet, - driverConnectionState = DriverConnectionState.Disconnected, - positionTransmit = false, - license = LicenseData( - address = "KE0YOG-7".toStationAddress() - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals("KE0YOG-7", result.userCallsign) - assertEquals(ControlState.Off, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - } - - @Test - fun internetWithPasscode() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Internet, - driverConnectionState = DriverConnectionState.Disconnected, - positionTransmit = false, - license = LicenseData( - address = "KE0YOG-7".toStationAddress(), - passcode = Passcode(12345), - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals("KE0YOG-7", result.userCallsign) - assertEquals(ControlState.Off, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - } - - @Test - fun internetConnectedWithPasscode() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Internet, - driverConnectionState = DriverConnectionState.Connected, - positionTransmit = false, - license = LicenseData( - address = "KE0YOG-7".toStationAddress(), - passcode = Passcode(12345), - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals("KE0YOG-7", result.userCallsign) - assertEquals(ControlState.On, result.connectState) - assertEquals(ControlState.Off, result.positionTransmitState) - } - - @Test - fun internetConnectedWithTransmit() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Internet, - driverConnectionState = DriverConnectionState.Connected, - positionTransmit = true, - license = LicenseData( - address = "KE0YOG-7".toStationAddress(), - passcode = Passcode(12345), - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals("KE0YOG-7", result.userCallsign) - assertEquals(ControlState.On, result.connectState) - assertEquals(ControlState.On, result.positionTransmitState) - } - - @Test - fun audioDefault() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Audio, - driverConnectionState = DriverConnectionState.Disconnected, - positionTransmit = false, - license = LicenseData(), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.Off, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - assertEquals(null, result.volumeLevel) - } - - @Test - fun audioCapturing() { - val result = factory.controlPanelState( - inputAudioLevel = 12.percent, - currentDriver = DriverSelection.Audio, - driverConnectionState = DriverConnectionState.Connected, - positionTransmit = false, - license = LicenseData(), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.On, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - assertEquals(.12f, result.volumeLevel) - } - - @Test - fun audioRegistered() { - val result = factory.controlPanelState( - inputAudioLevel = 12.percent, - currentDriver = DriverSelection.Audio, - driverConnectionState = DriverConnectionState.Disconnected, - positionTransmit = false, - license = LicenseData( - address = "KE0YOG-7".toStationAddress(), - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.Off, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - assertEquals(.12f, result.volumeLevel) - } - - @Test - fun audioRegisteredConnected() { - val result = factory.controlPanelState( - inputAudioLevel = 12.percent, - currentDriver = DriverSelection.Audio, - driverConnectionState = DriverConnectionState.Connected, - positionTransmit = false, - license = LicenseData( - address = "KE0YOG-7".toStationAddress(), - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.On, result.connectState) - assertEquals(ControlState.Off, result.positionTransmitState) - assertEquals(.12f, result.volumeLevel) - } - - @Test - fun audioTransmitting() { - val result = factory.controlPanelState( - inputAudioLevel = 12.percent, - currentDriver = DriverSelection.Audio, - driverConnectionState = DriverConnectionState.Connected, - positionTransmit = true, - license = LicenseData( - address = "KE0YOG-7".toStationAddress(), - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.On, result.connectState) - assertEquals(ControlState.On, result.positionTransmitState) - assertEquals(.12f, result.volumeLevel) - } - - @Test - fun tncDefault() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Tnc, - driverConnectionState = DriverConnectionState.Disconnected, - positionTransmit = false, - license = LicenseData(), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.Off, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - assertEquals(null, result.volumeLevel) - } - - @Test - fun tncConnectedOff() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Tnc, - driverConnectionState = DriverConnectionState.Disconnected, - positionTransmit = false, - license = LicenseData(), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.Off, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - assertEquals(null, result.volumeLevel) - } - - @Test - fun tncConnectedEnabled() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Tnc, - driverConnectionState = DriverConnectionState.Connected, - positionTransmit = false, - license = LicenseData(), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.On, result.connectState) - assertEquals(ControlState.Disabled, result.positionTransmitState) - assertEquals(null, result.volumeLevel) - } - - @Test - fun tncConnectedEnabledRegistered() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Tnc, - driverConnectionState = DriverConnectionState.Connected, - positionTransmit = false, - license = LicenseData( - address = "KE0YOG-7".toStationAddress(), - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.On, result.connectState) - assertEquals(ControlState.Off, result.positionTransmitState) - assertEquals(null, result.volumeLevel) - } - - @Test - fun tncTransmitting() { - val result = factory.controlPanelState( - inputAudioLevel = null, - currentDriver = DriverSelection.Tnc, - driverConnectionState = DriverConnectionState.Connected, - positionTransmit = true, - license = LicenseData( - address = "KE0YOG-7".toStationAddress(), - ), - ) - - assertTrue(result is ControlPanelState.Loaded) - assertEquals(ControlState.On, result.connectState) - assertEquals(ControlState.On, result.positionTransmitState) - assertEquals(null, result.volumeLevel) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/capture/insights/StatsStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/capture/insights/StatsStateFactoryTest.kt deleted file mode 100644 index b0820271..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/capture/insights/StatsStateFactoryTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class StatsStateFactoryTest { - private val factory = StatsStateFactory() - - @Test - fun completeStats() { - val result = factory.createState( - packetCount = 123, - stationCount = 456, - ) - - assertTrue(result is InsightsStatsState.LoadedData) - assertEquals(123, result.packets) - assertEquals(456, result.stations) - } - - @Test - fun noStats() { - val result = factory.createState( - packetCount = 0, - stationCount = 0, - ) - - assertTrue(result is InsightsStatsState.None) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/capture/insights/WeatherStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/capture/insights/WeatherStateFactoryTest.kt deleted file mode 100644 index 79ab84c9..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/capture/insights/WeatherStateFactoryTest.kt +++ /dev/null @@ -1,184 +0,0 @@ -package com.inkapplications.ack.android.capture.insights - -import com.inkapplications.ack.android.DummyPacket -import com.inkapplications.ack.android.EpochFormatterFake -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.Precipitation -import com.inkapplications.ack.structures.WindData -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.ack.structures.station.Ssid -import com.inkapplications.ack.structures.station.StationAddress -import inkapplications.spondee.measure.metric.celsius -import inkapplications.spondee.measure.us.fahrenheit -import inkapplications.spondee.measure.us.inches -import inkapplications.spondee.measure.us.milesPerHour -import inkapplications.spondee.scalar.percent -import kotlinx.datetime.Instant -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class WeatherStateFactoryTest { - private val factory = WeatherStateFactory(EpochFormatterFake) - - @Test - fun weatherTemperature() { - val fakePacket = DummyPacket.copy( - parsed = DummyPacket.parsed.copy( - route = DummyPacket.parsed.route.copy( - source = StationAddress(Callsign("KE0YOG"), Ssid("9")) - ), - data = PacketData.Weather( - temperature = 80.fahrenheit, - ) - ), - received = Instant.fromEpochMilliseconds(123), - ) - val result = factory.createState( - weatherPacket = fakePacket, - metric = false, - ) - assertTrue(result is InsightsWeatherState.DisplayRecent) - assertEquals("80ºF", result.temperature) - assertEquals(InsightsWeatherState.WeatherIcon.Normal, result.icon) - assertEquals("KE0YOG-9", result.weatherReporter) - assertEquals("123", result.weatherReportTime) - } - - @Test - fun noWeather() { - val result = factory.createState( - weatherPacket = null, - metric = false, - ) - - assertTrue(result is InsightsWeatherState.Unknown) - } - - @Test - fun weatherNoTemp() { - val fakePacket = DummyPacket.copy( - parsed = DummyPacket.parsed.copy( - data = PacketData.Weather() - ), - ) - val result = factory.createState( - weatherPacket = fakePacket, - metric = false, - ) - - assertTrue(result is InsightsWeatherState.DisplayRecent) - assertEquals("--", result.temperature) - } - - @Test - fun weatherSnowy() { - val fakePacket = DummyPacket.copy( - parsed = DummyPacket.parsed.copy( - data = PacketData.Weather( - precipitation = Precipitation( - snowLast24Hours = 12.inches, - ) - ) - ), - ) - val result = factory.createState( - weatherPacket = fakePacket, - metric = false, - ) - assertTrue(result is InsightsWeatherState.DisplayRecent) - assertEquals(InsightsWeatherState.WeatherIcon.Snow, result.icon) - } - - @Test - fun weatherRainy() { - val fakePacket = DummyPacket.copy( - parsed = DummyPacket.parsed.copy( - data = PacketData.Weather( - precipitation = Precipitation( - rainLastHour = 12.inches, - ) - ) - ), - ) - val result = factory.createState( - weatherPacket = fakePacket, - metric = false, - ) - assertTrue(result is InsightsWeatherState.DisplayRecent) - assertEquals(InsightsWeatherState.WeatherIcon.Rain, result.icon) - } - - @Test - fun weatherWindy() { - val fakePacket = DummyPacket.copy( - parsed = DummyPacket.parsed.copy( - data = PacketData.Weather( - windData = WindData( - speed = 25.milesPerHour, - ) - ) - ), - ) - val result = factory.createState( - weatherPacket = fakePacket, - metric = false, - ) - assertTrue(result is InsightsWeatherState.DisplayRecent) - assertEquals(InsightsWeatherState.WeatherIcon.Windy, result.icon) - } - - @Test - fun weatherGusty() { - val fakePacket = DummyPacket.copy( - parsed = DummyPacket.parsed.copy( - data = PacketData.Weather( - windData = WindData( - gust = 25.milesPerHour, - ) - ) - ), - ) - val result = factory.createState( - weatherPacket = fakePacket, - metric = false, - ) - assertTrue(result is InsightsWeatherState.DisplayRecent) - assertEquals(InsightsWeatherState.WeatherIcon.Windy, result.icon) - } - - @Test - fun weatherHumid() { - val fakePacket = DummyPacket.copy( - parsed = DummyPacket.parsed.copy( - data = PacketData.Weather( - humidity = 80.percent, - temperature = 80.fahrenheit, - ) - ), - ) - val result = factory.createState( - weatherPacket = fakePacket, - metric = false, - ) - assertTrue(result is InsightsWeatherState.DisplayRecent) - assertEquals(InsightsWeatherState.WeatherIcon.Humid, result.icon) - } - - @Test - fun metricFormat() { - val fakePacket = DummyPacket.copy( - parsed = DummyPacket.parsed.copy( - data = PacketData.Weather( - temperature = 25.celsius, - ) - ), - ) - val result = factory.createState( - weatherPacket = fakePacket, - metric = true, - ) - assertTrue(result is InsightsWeatherState.DisplayRecent) - assertEquals("25.0ºC", result.temperature) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewStateFactoryTest.kt deleted file mode 100644 index 9608ff7d..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/capture/messages/conversation/ConversationViewStateFactoryTest.kt +++ /dev/null @@ -1,118 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.conversation - -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Cloud -import androidx.compose.material.icons.filled.SettingsInputAntenna -import androidx.compose.material.icons.filled.Storage -import androidx.compose.ui.Alignment -import com.inkapplications.ack.android.* -import com.inkapplications.ack.android.capture.messages.MessageData -import com.inkapplications.ack.android.connection.DriverSelection -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.data.drivers.DriverConnectionState -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.station.toStationAddress -import kotlinx.datetime.Instant -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class ConversationViewStateFactoryTest { - private val factory = ConversationViewStateFactory(EpochFormatterFake, ParrotStringResources) - - private val me = "KE0YOG".toStationAddress() - private val addressee = "KE0YOF".toStationAddress() - - @Test - fun initial() { - val result = factory.createInitial(addressee.callsign) - - assertEquals("KE0YOF", result.title) - } - - @Test - fun emptyMessageList() { - val result = factory.createMessageList(addressee.callsign, emptyList(), DriverConnectionState.Disconnected, DriverSelection.Audio) - - assertTrue(result is ConversationViewState.Empty) - assertEquals("KE0YOF", result.title) - assertEquals(false, result.sendEnabled) - } - - @Test - fun connected() { - val result = factory.createMessageList(addressee.callsign, emptyList(), DriverConnectionState.Connected, DriverSelection.Audio) - assertEquals(true, result.sendEnabled) - } - - @Test - fun testOutgoingMessage() { - val packet = PacketData.Message( - addressee = addressee, - message = "Hello World!", - ).toTestPacket().copy( - route = testRoute.copy( - source = me, - ) - ).toTestCapturedPacket().copy( - received = Instant.fromEpochMilliseconds(12345), - ) - - val messageResult = getMessageState(packet) - assertEquals("Hello World!", messageResult.message) - assertEquals("12345", messageResult.timestamp) - assertEquals(Alignment.CenterEnd, messageResult.alignment) - } - - @Test - fun testIncomingMessageItem() { - val packet = PacketData.Message( - addressee = me, - message = "Hello World!", - ).toTestPacket().copy( - route = testRoute.copy( - source = addressee, - ) - ).toTestCapturedPacket().copy( - received = Instant.fromEpochMilliseconds(12345), - ) - - val messageResult = getMessageState(packet) - - assertEquals("Hello World!", messageResult.message) - assertEquals("12345", messageResult.timestamp) - assertEquals(Alignment.CenterStart, messageResult.alignment) - } - - private fun getMessageState(packet: CapturedPacket): MessageItemState { - val data = MessageData(me.callsign, packet) - val result = factory.createMessageList(addressee.callsign, listOf(data), DriverConnectionState.Disconnected, DriverSelection.Audio) - - assertTrue(result is ConversationViewState.MessageList) - assertEquals(1, result.messages.size) - - return result.messages.single() - } - - @Test - fun testIcons() { - val basePacket = PacketData.Message( - addressee = addressee, - message = "test", - ).toTestPacket().toTestCapturedPacket() - val local = getMessageState(basePacket.copy( - origin = PacketOrigin.Local, - )) - val radio = getMessageState(basePacket.copy( - origin = PacketOrigin.Ax25, - )) - val internet = getMessageState(basePacket.copy( - origin = PacketOrigin.AprsIs, - )) - - assertEquals(Icons.Default.Storage, local.icon) - assertEquals(Icons.Default.SettingsInputAntenna, radio.icon) - assertEquals(Icons.Default.Cloud, internet.icon) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexStateFactoryTest.kt deleted file mode 100644 index baa62596..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/capture/messages/index/MessageIndexStateFactoryTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.inkapplications.ack.android.capture.messages.index - -import com.inkapplications.ack.android.capture.messages.MessageData -import com.inkapplications.ack.android.toTestCapturedPacket -import com.inkapplications.ack.android.toTestPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.ack.structures.station.toStationAddress -import kotlinx.datetime.Instant -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class MessageIndexStateFactoryTest { - private val factory = MessageIndexStateFactory() - - @Test - fun empty() { - val result = factory.createScreenState( - latestMessages = emptyList() - ) - - assertTrue(result is MessageIndexState.Empty) - } - - @Test - fun testConversationItem() { - val station = "KE0YOF-2".toStationAddress() - val message = PacketData.Message( - addressee = station, - message = "First!", - ) - .toTestPacket() - .toTestCapturedPacket() - .copy(received = Instant.fromEpochMilliseconds(0)) - val conversation = MessageData( - selfCallsign = Callsign("KE0YOG"), - message = message, - ) - - val results = factory.createScreenState(listOf(conversation)) - assertTrue(results is MessageIndexState.ConversationList) - assertEquals(1, results.conversations.size) - - val result = results.conversations.single() - assertEquals("First!", result.messagePreview) - assertEquals("KE0YOF", result.name) - assertEquals(station.callsign, result.correspondent) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/input/IntegerValidatorTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/input/IntegerValidatorTest.kt deleted file mode 100644 index 479dac06..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/input/IntegerValidatorTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.inkapplications.ack.android.input - -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class IntegerValidatorTest { - @Test - fun positiveValid() { - val validator = IntegerValidator( - error = "error", - ) - - val result = validator.validate(1) - - assertTrue(result is ValidationResult.Valid) - } - - @Test - fun negativeInvalid() { - val validator = IntegerValidator( - error = "error", - ) - - val result = validator.validate(-5) - - assertTrue(result is ValidationResult.Error) - assertEquals("error", result.message) - } - - @Test - fun zeroValid() { - val validator = IntegerValidator( - error = "error", - ) - - val result = validator.validate(0) - - assertTrue(result is ValidationResult.Valid) - } - - @Test - fun zeroInvalid() { - val validator = IntegerValidator( - error = "error", - zeroInclusive = false, - ) - - val result = validator.validate(0) - - assertTrue(result is ValidationResult.Error) - assertEquals("error", result.message) - } - - @Test - fun sentinelValid() { - val validator = IntegerValidator( - error = "error", - allowSentinel = -1, - ) - - val result = validator.validate(-1) - - assertTrue(result is ValidationResult.Valid) - } - - @Test - fun invalidSentinel() { - val validator = IntegerValidator( - error = "error", - allowSentinel = -1, - ) - - val result = validator.validate(-4) - - assertTrue(result is ValidationResult.Error) - assertEquals("error", result.message) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/log/CombinedLogItemViewStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/log/CombinedLogItemViewStateFactoryTest.kt deleted file mode 100644 index 8147f03f..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/log/CombinedLogItemViewStateFactoryTest.kt +++ /dev/null @@ -1,242 +0,0 @@ -package com.inkapplications.ack.android.log - -import com.inkapplications.ack.android.symbol.SymbolFactoryDummy -import com.inkapplications.ack.android.toTestPacket -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.ReportState -import com.inkapplications.ack.structures.TelemetryValues -import com.inkapplications.ack.structures.station.StationAddress -import com.inkapplications.ack.structures.symbolOf -import inkapplications.spondee.measure.us.fahrenheit -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.spatial.latitude -import inkapplications.spondee.spatial.longitude -import kotlin.test.Test -import kotlin.test.assertEquals - -class CombinedLogItemViewStateFactoryTest { - val factory = CombinedLogItemViewStateFactory(SymbolFactoryDummy) - - @Test - fun unknownPacket() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.Unknown( - body = "", - ).toTestPacket(), - metric = false, - ) - - assertEquals(123L, result.id.value) - assertEquals("KE0YOG", result.origin) - assertEquals("Unknown data", result.comment) - } - - @Test - fun position() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.Position( - coordinates = GeoCoordinates(12f.latitude, 34f.longitude), - symbol = symbolOf('-', '/'), - comment = "Test Position", - ).toTestPacket(), - metric = false, - ) - - assertEquals("Position: Test Position", result.comment) - } - - @Test - fun positionGeneric() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.Position( - comment = "", - coordinates = GeoCoordinates(12f.latitude, 34f.longitude), - symbol = symbolOf('-', '/'), - ).toTestPacket(), - metric = false, - ) - - assertEquals("Position", result.comment) - } - - @Test - fun weather() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.Weather( - temperature = 72.fahrenheit, - ).toTestPacket(), - metric = false, - ) - - assertEquals("Weather: 72ºF", result.comment) - } - - @Test - fun weatherGeneric() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.Weather().toTestPacket(), - metric = false, - ) - - assertEquals("Weather", result.comment) - } - - @Test - fun objectReport() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.ObjectReport( - coordinates = GeoCoordinates(12f.latitude, 34f.longitude), - symbol = symbolOf('-', '/'), - comment = "Hello World", - name = "Test Object", - state = ReportState.Live, - ).toTestPacket(), - metric = false, - ) - - assertEquals("Object: Test Object - Hello World", result.comment) - } - - @Test - fun objectReportNoComment() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.ObjectReport( - coordinates = GeoCoordinates(12f.latitude, 34f.longitude), - symbol = symbolOf('-', '/'), - name = "Test Object", - comment = " ", - state = ReportState.Live, - ).toTestPacket(), - metric = false, - ) - - assertEquals("Object: Test Object", result.comment) - } - - @Test - fun itemReport() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.ItemReport( - coordinates = GeoCoordinates(12f.latitude, 34f.longitude), - symbol = symbolOf('-', '/'), - name = "Test Item", - comment = "Hello World", - state = ReportState.Live, - ).toTestPacket(), - metric = false, - ) - - assertEquals("Item: Test Item - Hello World", result.comment) - } - - @Test - fun itemReportNoComment() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.ItemReport( - coordinates = GeoCoordinates(12f.latitude, 34f.longitude), - symbol = symbolOf('-', '/'), - name = "Test Item", - comment = " ", - state = ReportState.Live, - ).toTestPacket(), - metric = false, - ) - - assertEquals("Item: Test Item", result.comment) - } - - @Test - fun message() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.Message( - addressee = StationAddress("KE0YOG-2"), - message = "Hello KE0YOG", - ).toTestPacket(), - metric = false, - ) - - assertEquals("[KE0YOG-2] Hello KE0YOG", result.comment) - } - - @Test - fun messageWithCount() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.Message( - addressee = StationAddress("KE0YOG-2"), - message = "Hello KE0YOG", - messageNumber = 69, - ).toTestPacket(), - metric = false, - ) - - assertEquals("[KE0YOG-2] Hello KE0YOG (69)", result.comment) - } - - @Test - fun telemetryReport() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.TelemetryReport( - sequenceId = "", - data = TelemetryValues(1f, 2f, 3f, 4f, 5f, 0u), - comment = "Hello World", - ).toTestPacket(), - metric = false, - ) - - assertEquals("Telemetry: Hello World", result.comment) - } - - @Test - fun telemetryReportGeneric() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.TelemetryReport( - sequenceId = "", - data = TelemetryValues(1f, 2f, 3f, 4f, 5f, 0u), - comment = " ", - ).toTestPacket(), - metric = false, - ) - - assertEquals("Telemetry", result.comment) - } - - @Test - fun statusReport() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.StatusReport( - status = "Testing", - ).toTestPacket(), - metric = false, - ) - - assertEquals("Status: Testing", result.comment) - } - - @Test - fun capabilityReport() { - val result = factory.create( - id = CaptureId(123L), - packet = PacketData.CapabilityReport( - capabilityData = setOf(), - ).toTestPacket(), - metric = false, - ) - - assertEquals("Capability Report", result.comment) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/log/SummaryFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/log/SummaryFactoryTest.kt deleted file mode 100644 index 10706e2d..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/log/SummaryFactoryTest.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.inkapplications.ack.android.log - -import com.inkapplications.ack.android.ParrotStringResources -import com.inkapplications.ack.structures.WindData -import inkapplications.spondee.measure.us.milesPerHour -import inkapplications.spondee.spatial.Cardinal -import inkapplications.spondee.spatial.toAngle -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNull - -class SummaryFactoryTest { - private val factory = SummaryFactory(ParrotStringResources) - - @Test - fun noData() { - val result = factory.createWindSummary(WindData(), false) - - assertNull(result) - } - - @Test - fun speedOnly() { - val result = factory.createWindSummary( - WindData(speed = 12.milesPerHour), - false, - ) - - assertEquals("12mph", result) - } - - @Test - fun directionOnly() { - val result = factory.createWindSummary( - WindData(direction = Cardinal.South.toAngle()), - false, - ) - - assertEquals("180º", result) - } - - @Test - fun speedAndDirection() { - val result = factory.createWindSummary( - WindData( - speed = 12.milesPerHour, - direction = Cardinal.East.toAngle(), - ), - false, - ) - - assertEquals("90º|12mph", result) - } - - @Test - fun full() { - val result = factory.createWindSummary( - WindData( - speed = 12.milesPerHour, - direction = Cardinal.East.toAngle(), - gust = 34.milesPerHour, - ), - false, - ) - - assertEquals("90º|12mph|34mph", result) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/log/details/LogDetailsViewStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/log/details/LogDetailsViewStateFactoryTest.kt deleted file mode 100644 index 203f927c..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/log/details/LogDetailsViewStateFactoryTest.kt +++ /dev/null @@ -1,196 +0,0 @@ -package com.inkapplications.ack.android.log.details - -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Cloud -import androidx.compose.material.icons.filled.SettingsInputAntenna -import androidx.compose.material.icons.filled.Storage -import com.inkapplications.ack.android.* -import com.inkapplications.ack.android.log.SummaryFactory -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.WindData -import com.inkapplications.ack.structures.station.StationAddress -import com.inkapplications.ack.structures.symbolOf -import inkapplications.spondee.measure.us.fahrenheit -import inkapplications.spondee.measure.us.milesPerHour -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.spatial.degrees -import inkapplications.spondee.spatial.latitude -import inkapplications.spondee.spatial.longitude -import kotlinx.datetime.Instant -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNull -import kotlin.test.assertTrue - -class LogDetailsViewStateFactoryTest { - val dummySummaryFactory = SummaryFactory(ParrotStringResources) - val factoryWithNullMarkers = LogDetailsViewStateFactory(dummySummaryFactory, NullMarkerFactoryMock, EpochFormatterFake, ParrotStringResources) - val factoryWithDummyMarkers = LogDetailsViewStateFactory(dummySummaryFactory, DummyMarkerFactoryMock, EpochFormatterFake, ParrotStringResources) - - @Test - fun nameFormatting() { - val packet = PacketData.Unknown(body = "Test").toTestPacket().copy( - route = testRoute.copy(source = StationAddress("TEST", "4")) - ).toTestCapturedPacket() - - val result = factoryWithNullMarkers.create(LogDetailData(packet = packet)) - - assertEquals("TEST-4", result.name) - } - - @Test - fun icons() { - val base = PacketData.Unknown( - body = "Test" - ).toTestPacket().toTestCapturedPacket() - - val localResult = LogDetailData(packet = base.copy(origin = PacketOrigin.Local)).let(factoryWithNullMarkers::create) - val isResult = LogDetailData(packet = base.copy(origin = PacketOrigin.AprsIs)).let(factoryWithNullMarkers::create) - val ax25Result = LogDetailData(packet = base.copy(origin = PacketOrigin.Ax25)).let(factoryWithNullMarkers::create) - - assertEquals(Icons.Default.Storage, localResult.receiveIcon) - assertEquals(Icons.Default.Cloud, isResult.receiveIcon) - assertEquals(Icons.Default.SettingsInputAntenna, ax25Result.receiveIcon) - } - - @Test - fun timestamp() { - val packet = PacketData.Unknown(body = "Test").toTestPacket().toTestCapturedPacket().copy( - received = Instant.fromEpochMilliseconds(-22073104000) - ) - - val result = factoryWithNullMarkers.create(LogDetailData(packet = packet)) - - assertEquals("-22073104000", result.timestamp) - } - - @Test - fun debugData() { - val packet = PacketData.Unknown( - body = "Test" - ).toTestPacket().toTestCapturedPacket().copy( - raw = "Test Debug".toByteArray() - ) - val data = LogDetailData( - packet = packet, - debug = true - ) - - val result = factoryWithNullMarkers.create(data) - - assertEquals("Test Debug", result.rawSource) - } - - @Test - fun unknownPacket() { - val packet = PacketData.Unknown(body = "Test").toTestPacket().copy( - route = testRoute.copy(source = StationAddress("TEST", "4")) - ).toTestCapturedPacket() - - val result = factoryWithNullMarkers.create(LogDetailData(packet = packet)) - - assertFalse(result.mapable, "Not mapable for non-map data") - assertNull(result.temperature, "No temperature for non weather packet") - assertNull(result.wind, "No wind data for non weather packet") - assertNull(result.comment, "No comment for unknown packet") - assertNull(result.altitude, "No altitude for unknown packet") - assertNull(result.telemetryValues, "No telemetry for unknown packet") - assertNull(result.telemetrySequence, "No telemetry for unknown packet") - assertNull(result.rawSource, "Debug data hidden") - } - - @Test - fun positionlessWeatherPacket() { - val packet = PacketData.Weather( - temperature = 72.fahrenheit, - windData = WindData( - direction = 12.degrees, - speed = 34.milesPerHour, - gust = 56.milesPerHour, - ) - ).toTestPacket().toTestCapturedPacket() - val data = LogDetailData( - packet = packet, - ) - - val result = factoryWithNullMarkers.create(data) - - assertFalse(result.mapable, "Not mapable for non-map data") - assertEquals("72ºF", result.temperature) - assertEquals("12º|34mph|56mph", result.wind) - assertNull(result.comment, "No comment for positionless weather") - assertNull(result.altitude, "No altitude for positionless weather") - assertNull(result.telemetryValues, "No telemetry for positionless weather") - assertNull(result.telemetrySequence, "No telemetry for positionless weather") - assertNull(result.rawSource, "Debug data hidden") - } - - @Test - fun weatherPacket() { - val packet = PacketData.Weather( - coordinates = GeoCoordinates(1.0.latitude, 2.0.longitude), - temperature = 72.fahrenheit, - windData = WindData(12.degrees, 34.milesPerHour, 56.milesPerHour), - ).toTestPacket().toTestCapturedPacket() - val data = LogDetailData( - packet = packet, - ) - - val result = factoryWithDummyMarkers.create(data) - - assertTrue(result.mapable, "Mapable weather data shows map") - assertEquals("72ºF", result.temperature) - assertEquals("12º|34mph|56mph", result.wind) - assertNull(result.comment, "No comment for weather packet") - assertNull(result.altitude, "No altitude for weather packet") - assertNull(result.telemetryValues, "No telemetry for weather packet") - assertNull(result.telemetrySequence, "No telemetry for weather packet") - assertNull(result.rawSource, "Debug data hidden") - } - - @Test - fun emptyWeatherPacket() { - val packet = PacketData.Weather( - coordinates = GeoCoordinates(1.latitude, 2.longitude), - ).toTestPacket().toTestCapturedPacket() - val data = LogDetailData( - packet = packet, - ) - - val result = factoryWithDummyMarkers.create(data) - - assertTrue(result.mapable, "Mapable weather data shows map") - assertNull(result.temperature, "No temperature for empty weather packet") - assertNull(result.wind, "No wind data for empty non weather packet") - assertNull(result.comment, "No comment for unknown packet") - assertNull(result.altitude, "No altitude for unknown packet") - assertNull(result.telemetryValues, "No telemetry for unknown packet") - assertNull(result.telemetrySequence, "No telemetry for unknown packet") - assertNull(result.rawSource, "Debug data hidden") - } - - @Test - fun positionPacket() { - val packet = PacketData.Position( - coordinates = GeoCoordinates(1.latitude, 2.longitude), - symbol = symbolOf('/', 'a'), - comment = "test", - ).toTestPacket().toTestCapturedPacket() - val data = LogDetailData( - packet = packet, - ) - - val result = factoryWithDummyMarkers.create(data) - - assertTrue(result.mapable, "Mapable position data shows map") - assertNull(result.temperature, "No temperature for non weather packet") - assertNull(result.wind, "No wind data for non weather packet") - assertEquals("test", result.comment) - assertNull(result.altitude, "No altitude for position packet") - assertNull(result.telemetryValues, "No telemetry for position packet") - assertNull(result.telemetrySequence, "No telemetry for position packet") - assertNull(result.rawSource, "Debug data hidden") - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/map/MarkerViewStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/map/MarkerViewStateFactoryTest.kt deleted file mode 100644 index 8fddafc7..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/map/MarkerViewStateFactoryTest.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.inkapplications.ack.android.map - -import android.graphics.Bitmap -import com.inkapplications.ack.android.symbol.SymbolFactory -import com.inkapplications.ack.android.symbol.SymbolFactoryDummy -import com.inkapplications.ack.android.toTestCapturedPacket -import com.inkapplications.ack.android.toTestPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.Symbol -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.spatial.latitude -import inkapplications.spondee.spatial.longitude -import kotlin.test.Test -import kotlin.test.assertNull -import kotlin.test.assertTrue - -class MarkerViewStateFactoryTest { - val symbolFactoryStub = object: SymbolFactory { - override val defaultSymbol: Bitmap? get() = TODO() - override fun createSymbol(symbol: Symbol): Bitmap? = TODO() - } - - @Test - fun unknown() { - val factory = MarkerViewStateFactory(symbolFactoryStub) - val packet = PacketData.Unknown(body = "") - val result = factory.create(packet.toTestPacket().toTestCapturedPacket()) - - assertNull(result, "Unknown packet should not produce a marker") - } - - @Test - fun noCoordinates() { - val factory = MarkerViewStateFactory(symbolFactoryStub) - val packet = PacketData.Weather() - val result = factory.create(packet.toTestPacket().toTestCapturedPacket()) - - assertNull(result, "Mappable Packet without location should not produce a marker") - } - - @Test - fun noSymbol() { - val factory = MarkerViewStateFactory(SymbolFactoryDummy) - val packet = PacketData.Weather() - val result = factory.create(packet.toTestPacket().toTestCapturedPacket()) - - assertNull(result, "Mappable Packet without location should not produce a marker") - } - - @Test - fun marker() { - val symbolFactorySpy = object: SymbolFactory by symbolFactoryStub { - var called = false - override fun createSymbol(symbol: Symbol): Bitmap? = null.also { - called = true - } - - } - val factory = MarkerViewStateFactory(symbolFactorySpy) - val packet = PacketData.Weather(coordinates = GeoCoordinates(0.latitude, 0.longitude)) - val result = factory.create(packet.toTestPacket().toTestCapturedPacket()) - - assertTrue(symbolFactorySpy.called, "Symbol is generated when coordinates specified") - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/onboard/OnboardingStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/onboard/OnboardingStateFactoryTest.kt deleted file mode 100644 index 737a1d7f..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/onboard/OnboardingStateFactoryTest.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.inkapplications.ack.android.onboard - -import com.inkapplications.ack.android.settings.Passcode -import com.inkapplications.ack.structures.station.StationAddress -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class OnboardingStateFactoryTest { - private val factory = OnboardingStateFactory() - - @Test - fun agreementMismatch() { - val data = OnboardingStateFactory.OnboardingData( - latestRevision = 2, - agreementRevision = 4, - ) - - val result = factory.screenState(data) - - assertTrue(result is OnboardingState.UserAgreement) - } - - @Test - fun licenseIncomplete() { - val data = OnboardingStateFactory.OnboardingData( - latestRevision = 2, - agreementRevision = 2, - completedLicense = false, - ) - - val result = factory.screenState(data) - - assertTrue(result is OnboardingState.LicensePrompt) - assertEquals("", result.initialValues.callsign) - assertEquals("", result.initialValues.passcode) - } - - @Test - fun licenseIncompleteWithData() { - val data = OnboardingStateFactory.OnboardingData( - latestRevision = 2, - agreementRevision = 2, - completedLicense = false, - currentAddress = StationAddress("TEST", "7"), - currentPasscode = Passcode(1234), - ) - - val result = factory.screenState(data) - - assertTrue(result is OnboardingState.LicensePrompt) - assertEquals("TEST-7", result.initialValues.callsign) - assertEquals("1234", result.initialValues.passcode) - } - - @Test - fun licenseComplete() { - val data = OnboardingStateFactory.OnboardingData( - latestRevision = 2, - agreementRevision = 2, - completedLicense = true, - ) - - val result = factory.screenState(data) - - assertTrue(result is OnboardingState.Complete) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/CompositeSettingsProviderTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/CompositeSettingsProviderTest.kt deleted file mode 100644 index f5cd89cb..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/CompositeSettingsProviderTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.inkapplications.ack.android.settings - -import org.junit.Assert.assertTrue -import org.junit.Test - -class CompositeSettingsProviderTest { - @Test - fun getSettings() { - val first = object: SettingsProvider { - override val settings: List = listOf(stringSetting) - } - val second = object: SettingsProvider { - override val settings: List = listOf(intSetting) - } - val provider = CompositeSettingsProvider(setOf(first, second)) - - val result = provider.settings - - assertTrue("Both settings are in combined result", stringSetting in result) - assertTrue("Both settings are in combined result", intSetting in result) - } - - @Test - fun emptySettings() { - val provider = CompositeSettingsProvider(setOf()) - - val result = provider.settings - - assertTrue("No settings providers results in empty set", result.isEmpty()) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/PrioritySettingValuesTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/PrioritySettingValuesTest.kt deleted file mode 100644 index 918abb59..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/PrioritySettingValuesTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.inkapplications.ack.android.settings - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.runBlocking -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull -import org.junit.Test - -class PrioritySettingValuesTest { - @Test - fun firstIsPrioritized() { - val first = object: SettingsReadAccess by SettingsReadAccessStub { - override fun observeStringState(setting: StringSetting): Flow = flowOf("first") - } - val second = object: SettingsReadAccess by SettingsReadAccessStub { - override fun observeStringState(setting: StringSetting): Flow = flowOf("second") - } - val values = PrioritySettingValues(first, second) - - runBlocking { - assertEquals("first", values.observeStringState(stringSetting).first()) - } - } - - @Test - fun secondIsUsed() { - val first = object: SettingsReadAccess by SettingsReadAccessStub { - override fun observeStringState(setting: StringSetting): Flow = flowOf(null) - } - val second = object: SettingsReadAccess by SettingsReadAccessStub { - override fun observeStringState(setting: StringSetting): Flow = flowOf("second") - } - val values = PrioritySettingValues(first, second) - - runBlocking { - assertEquals("second", values.observeStringState(stringSetting).first()) - } - } - - @Test - fun noSetting() { - val first = object: SettingsReadAccess by SettingsReadAccessStub { - override fun observeStringState(setting: StringSetting): Flow = flowOf(null) - } - val second = object: SettingsReadAccess by SettingsReadAccessStub { - override fun observeStringState(setting: StringSetting): Flow = flowOf(null) - } - val values = PrioritySettingValues(first, second) - - runBlocking { - assertNull(values.observeStringState(stringSetting).first()) - } - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsAccessTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsAccessTest.kt deleted file mode 100644 index 6d780c56..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsAccessTest.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.inkapplications.ack.android.settings - -import com.inkapplications.ack.android.ParrotStringResources -import com.inkapplications.ack.android.connection.ConnectionSettings -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.test.runTest -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class SettingsAccessTest { - @Test - fun items() = runTest { - val access = SettingsAccess( - SettingsProviderStub, - SettingsReadAccessStub, - SettingsWriteAccessStub, - ConnectionSettings(ParrotStringResources), - ) - - val result = access.settingsGroups(SettingVisibility.Advanced).first() - val list = result.settings.map { it.settings }.flatten() - - assertEquals(2, list.size, "Provider should yield a result for each Setting.") - val (first, second) = list - - assertTrue(first is SettingState.IntState) - assertEquals(intSetting.key, first.setting.key, "Settings key is preserved.") - assertEquals(intSetting.name, first.setting.name, "Settings name is preserved.") - assertEquals(1, first.value, "Setting value is provided by read access stub.") - - assertTrue(second is SettingState.StringState, "First setting should be a string item.") - assertEquals(stringSetting.key, second.setting.key, "Settings key is preserved.") - assertEquals(stringSetting.name, second.setting.name, "Settings name is preserved.") - assertEquals("foo - test.string", second.value, "Setting value is provided by read access stub.") - } - - @Test - fun advancedHidden() = runTest { - val settingsProvider = object: SettingsProvider { - override val settings: List = listOf( - stringSetting, - StringSetting(key = "advanced", visibility = SettingVisibility.Advanced, name = "advanced", categoryName = stringSetting.categoryName, defaultValue = "advanced") - ) - } - - val access = SettingsAccess( - settingsProvider, - SettingsReadAccessStub, - SettingsWriteAccessStub, - ConnectionSettings(ParrotStringResources), - ) - - val result = access.settingsGroups(SettingVisibility.Visible).first() - val list = result.settings.map { it.settings }.flatten() - - assertEquals(1, list.size, "List is filtered to only simple settings.") - assertEquals(stringSetting.key, (list.first() as SettingState.StringState).setting.key, "Advanced settings are removed from settings list.") - } - - @Test - fun advancedShown() = runTest { - val settingsProvider = object: SettingsProvider { - override val settings: List = listOf( - stringSetting, - StringSetting(key = "advanced", visibility = SettingVisibility.Advanced, name = "zz_advanced", categoryName = stringSetting.categoryName, defaultValue = "advanced") - ) - } - - val access = SettingsAccess( - settingsProvider, - SettingsReadAccessStub, - SettingsWriteAccessStub, - ConnectionSettings(ParrotStringResources), - ) - - val result = access.settingsGroups(SettingVisibility.Advanced).first() - val list = result.settings.map { it.settings }.flatten() - - assertEquals(2, list.size, "List is filtered to only simple settigns.") - assertEquals(stringSetting.key, (list[0] as SettingState.StringState).setting.key, "Standard settings are still shown.") - assertEquals("advanced", (list[1] as SettingState.StringState).setting.key, "Advanced settings are removed from settings list.") - } - - @Test - fun categorized() = runTest { - val settingsProvider = object: SettingsProvider { - override val settings: List = listOf( - StringSetting(key = "B1", categoryName = "B", name = "B1", defaultValue = "test"), - StringSetting(key = "C1", categoryName = "C", name = "C1", defaultValue = "test"), - StringSetting(key = "A1", categoryName = "A", name = "A1", defaultValue = "test"), - StringSetting(key = "B2", categoryName = "B", name = "B2", defaultValue = "test"), - ) - } - - val access = SettingsAccess( - settingsProvider, - SettingsReadAccessStub, - SettingsWriteAccessStub, - ConnectionSettings(ParrotStringResources), - ) - - val result = access.settingsGroups(SettingVisibility.Advanced).first() - - assertEquals(3, result.settings.size, "Settings are broken into categories by name") - - val (first, second, third) = result.settings - - assertEquals("A", first.name, "Categories are sorted by name") - assertEquals(1, first.settings.size, "Settings are kept in their category") - assertEquals("A1", first.settings[0].setting.key, "Settings are kept in their category") - - assertEquals("B", second.name, "Categories are sorted by name") - assertEquals(2, second.settings.size, "Settings are kept in their category") - assertEquals("B1", second.settings[0].setting.key, "Settings are kept in their category") - assertEquals("B2", second.settings[1].setting.key, "Settings are kept in their category") - - assertEquals("C", third.name, "Categories are sorted by name") - assertEquals(1, third.settings.size, "Settings are kept in their category") - assertEquals("C1", third.settings[0].setting.key, "Settings are kept in their category") - } - - @Test - fun licensePromptFieldValues() = runTest { - val fakeSettings = object: SettingsReadAccess by SettingsReadAccessStub { - override fun observeStringState(setting: StringSetting): Flow { - return flow { emit("KE0YOG") } - } - - override fun observeIntState(setting: IntSetting): Flow { - return flow { emit(12345) } - } - } - val access = SettingsAccess( - SettingsProviderStub, - fakeSettings, - SettingsWriteAccessStub, - ConnectionSettings(ParrotStringResources), - ) - - val result = access.licensePromptFieldValues.first() - - assertEquals("KE0YOG", result.callsign) - assertEquals("12345", result.passcode) - } - - @Test - fun emptyLicensePromptFieldValues() = runTest { - val fakeSettings = object: SettingsReadAccess by SettingsReadAccessStub { - override fun observeStringState(setting: StringSetting): Flow { - return flow { emit(null) } - } - - override fun observeIntState(setting: IntSetting): Flow { - return flow { emit(null) } - } - } - val access = SettingsAccess( - SettingsProviderStub, - fakeSettings, - SettingsWriteAccessStub, - ConnectionSettings(ParrotStringResources), - ) - - val result = access.licensePromptFieldValues.first() - - assertEquals("", result.callsign) - assertEquals("", result.passcode) - } - - @Test - fun sorted() = runTest { - val settingsProvider = object: SettingsProvider { - override val settings: List = listOf( - StringSetting(key = "3", name = "C", categoryName = "test", defaultValue = "test"), - StringSetting(key = "4", name = "D", categoryName = "test", defaultValue = "test"), - StringSetting(key = "1", name = "A", categoryName = "test", defaultValue = "test"), - StringSetting(key = "2", name = "B", categoryName = "test", defaultValue = "test"), - ) - } - - val access = SettingsAccess( - settingsProvider, - SettingsReadAccessStub, - SettingsWriteAccessStub, - ConnectionSettings(ParrotStringResources), - ) - - val result = access.settingsGroups(SettingVisibility.Advanced).first() - val list = result.settings.map { it.settings.map { it.setting.name } }.flatten() - - assertEquals(listOf("A", "B", "C", "D"), list, "Settings are sorted by name") - - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsDoubles.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsDoubles.kt deleted file mode 100644 index 8198b62d..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsDoubles.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.inkapplications.ack.android.settings - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf - -val stringSetting = StringSetting("test.string", "test string", "category", "default") -val intSetting = IntSetting("test.int", "test int", "category", 1234) - -object SettingsWriteAccessStub: SettingsWriteAccess { - override fun setString(setting: StringSetting, value: String) = Unit - override fun setInt(setting: IntSetting, value: Int) = Unit - override fun setBoolean(setting: BooleanSetting, value: Boolean) = Unit -} - -object SettingsReadAccessStub: SettingsReadAccess { - override fun observeStringState(setting: StringSetting): Flow = flowOf("foo - ${setting.key}") - override fun observeIntState(setting: IntSetting): Flow = flowOf(1) - override fun observeBooleanState(setting: BooleanSetting): Flow = flowOf(false) -} - -object SettingsProviderStub: SettingsProvider { - override val settings: List = listOf(stringSetting, intSetting) -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsViewStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsViewStateFactoryTest.kt deleted file mode 100644 index 7075240c..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/SettingsViewStateFactoryTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.inkapplications.ack.android.settings - -import com.inkapplications.ack.structures.station.StationAddress -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class SettingsViewStateFactoryTest { - private val factory = SettingsViewStateFactory() - - @Test - fun registered() { - val data = LicenseData( - address = StationAddress("TEST", "7"), - passcode = null, - ) - - val result = factory.licenseState(data) - - assertTrue(result is LicenseViewState.Registered) - assertEquals("TEST-7", result.callsign) - } - - @Test - fun verified() { - val data = LicenseData( - address = StationAddress("TEST", "7"), - passcode = Passcode(1234), - ) - - val result = factory.licenseState(data) - - assertTrue(result is LicenseViewState.Verified) - assertEquals("TEST-7", result.callsign) - } - - @Test - fun unconfigured() { - val data = LicenseData( - address = null, - passcode = null, - ) - - val result = factory.licenseState(data) - - assertTrue(result is LicenseViewState.Unconfigured) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoFactoryTest.kt deleted file mode 100644 index 0ab3d0f4..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/buildinfo/BuildInfoFactoryTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.inkapplications.ack.android.settings.buildinfo - -import com.inkapplications.ack.android.ParrotStringResources -import com.inkapplications.android.extensions.StringResources -import kimchi.logger.EmptyLogger -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -class BuildInfoFactoryTest { - private val factory = BuildInfoFactory( - stringResources = ParrotStringResources, - logger = EmptyLogger, - ) - private val data = BuildData( - buildType = "debug", - versionName = "1.0.0", - versionCode = 1, - commit = "ffac537e6cbbf934b08745a378932722df287a53", - usePlayServices = true, - playServicesAvailable = true, - ) - - @Test - fun release() { - val result = factory.buildInfo(data.copy(buildType = "release")) - - assertTrue(result is BuildInfoState.Release) - assertEquals(result.playServices, BuildInfoState.ServiceState.Available) - assertEquals("1.0.0|1|ffac537", result.versionStatment) - } - - @Test - fun shortHash() { - val result = factory.buildInfo(data.copy(buildType = "release", commit = "ff")) - - assertTrue(result is BuildInfoState.Release) - assertEquals("1.0.0|1|ff", result.versionStatment) - } - - @Test - fun noHash() { - val factory = BuildInfoFactory( - stringResources = object: StringResources by ParrotStringResources { - override fun getString(key: Int): String = "Test" - }, - logger = EmptyLogger, - ) - val result = factory.buildInfo(data.copy(buildType = "release", commit = null)) - - assertTrue(result is BuildInfoState.Release) - assertEquals("1.0.0|1|Test", result.versionStatment) - } - - @Test - fun debugWithPlayServices() { - val result = factory.buildInfo(data) - - assertTrue(result is BuildInfoState.Debug) - assertEquals(result.playServices, BuildInfoState.ServiceState.Available) - } - - @Test - fun playServicesMissing() { - val result = factory.buildInfo(data.copy(playServicesAvailable = false)) - - assertTrue(result is BuildInfoState.Debug) - assertEquals(result.playServices, BuildInfoState.ServiceState.Unavailable) - } - - @Test - fun playServicesUnconfigured() { - val result = factory.buildInfo(data.copy(usePlayServices = false)) - - assertTrue(result is BuildInfoState.Debug) - assertEquals(result.playServices, BuildInfoState.ServiceState.Unconfigured) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MileTransformerTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MileTransformerTest.kt deleted file mode 100644 index 22cfa444..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MileTransformerTest.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import inkapplications.spondee.measure.us.miles -import kotlin.test.Test -import kotlin.test.assertEquals - -class MileTransformerTest { - @Test - fun toStorage() { - assertEquals(5, 5.miles.let(MileTransformer::toStorage)) - assertEquals(2, 1.5.miles.let(MileTransformer::toStorage)) - } - - @Test - fun toData() { - assertEquals(5.miles, MileTransformer.toData(5)) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MillisecondTransformerTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MillisecondTransformerTest.kt deleted file mode 100644 index a2a35273..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MillisecondTransformerTest.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.time.Duration.Companion.seconds - -class MillisecondTransformerTest { - @Test - fun toStorage() { - val result = MillisecondTransformer.toStorage(45.seconds) - - assertEquals(45000, result) - } - - @Test - fun fromStorage() { - val result = MillisecondTransformer.toData(45000) - - assertEquals(45.seconds, result) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MinuteTransformerTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MinuteTransformerTest.kt deleted file mode 100644 index 7a085398..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/MinuteTransformerTest.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.time.Duration.Companion.hours - -class MinuteTransformerTest { - @Test - fun toStorage() { - val result = MinuteTransformer.toStorage(1.5.hours) - - assertEquals(90, result) - } - - @Test - fun fromStorage() { - val result = MinuteTransformer.toData(90) - - assertEquals(1.5.hours, result) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/SentinelOptionalTransformerTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/SentinelOptionalTransformerTest.kt deleted file mode 100644 index 1cf96c26..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/SentinelOptionalTransformerTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNull - -class SentinelOptionalTransformerTest { - private val backingFake = object: Transformer { - override fun toStorage(data: String): String = "STORED" - override fun toData(storage: String): String = "DATA" - } - val transformer = SentinelOptionalTransformer("TestNull", backingFake) - - @Test - fun toData() { - assertEquals("DATA", transformer.toData("Test")) - assertNull(transformer.toData("TestNull")) - } - - @Test - fun toStorage() { - assertEquals("STORED", transformer.toStorage("Test")) - assertEquals("TestNull", transformer.toStorage(null)) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/StationAddressTransformerTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/StationAddressTransformerTest.kt deleted file mode 100644 index ec83ad70..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/settings/transformer/StationAddressTransformerTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.inkapplications.ack.android.settings.transformer - -import com.inkapplications.ack.structures.station.StationAddress -import kotlin.test.Test -import kotlin.test.assertEquals - -class StationAddressTransformerTest { - @Test - fun toData() { - assertEquals(StationAddress("KE0YOG"), StationAddressTransformer.toData("KE0YOG")) - assertEquals(StationAddress("KE0YOG", "2"), StationAddressTransformer.toData("KE0YOG-2")) - } - - @Test - fun toStorage() { - assertEquals("KE0YOG", StationAddress("KE0YOG").let(StationAddressTransformer::toStorage)) - assertEquals("KE0YOG-2", StationAddress("KE0YOG", "2").let(StationAddressTransformer::toStorage)) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/station/StationInsightViewStateFactoryTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/station/StationInsightViewStateFactoryTest.kt deleted file mode 100644 index 731f1df4..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/station/StationInsightViewStateFactoryTest.kt +++ /dev/null @@ -1,158 +0,0 @@ -package com.inkapplications.ack.android.station - -import com.inkapplications.ack.android.ParrotStringResources -import com.inkapplications.ack.android.log.SummaryFactory -import com.inkapplications.ack.android.testRoute -import com.inkapplications.ack.android.toTestCapturedPacket -import com.inkapplications.ack.android.toTestPacket -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.WindData -import com.inkapplications.ack.structures.station.StationAddress -import com.inkapplications.ack.structures.symbolOf -import inkapplications.spondee.measure.us.fahrenheit -import inkapplications.spondee.measure.us.milesPerHour -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.spatial.degrees -import inkapplications.spondee.spatial.latitude -import inkapplications.spondee.spatial.longitude -import kotlinx.datetime.Instant -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertNull - -class StationInsightViewStateFactoryTest { - val dummySummaryFactory = SummaryFactory(ParrotStringResources) - - @Test - fun unknownPacket() { - val factory = StationInsightViewStateFactory(dummySummaryFactory) - val packet = CapturedPacket( - id = CaptureId(1), - received = Instant.fromEpochMilliseconds(2), - parsed = AprsPacket( - route = testRoute.copy( - source = StationAddress("KE0YOG", "1"), - ), - data = PacketData.Unknown( - body = "test", - ), - ), - origin = PacketOrigin.AprsIs, - raw = byteArrayOf(), - ) - val data = StationData( - packets = listOf(packet), - metric = false, - ) - val result = factory.create(data) - - assertEquals("KE0YOG", result.name) - assertNull(result.temperature, "No temperature for non weather packet") - assertNull(result.wind, "No wind data for non weather packet") - assertNull(result.comment, "No comment for unknown packet") - assertNull(result.altitude, "No altitude for unknown packet") - assertNull(result.telemetryValues, "No telemetry for unknown packet") - assertNull(result.telemetrySequence, "No telemetry for unknown packet") - } - - @Test - fun positionlessWeatherPacket() { - val factory = StationInsightViewStateFactory(dummySummaryFactory) - val packet = PacketData.Weather( - temperature = 72.fahrenheit, - windData = WindData( - direction = 12.degrees, - speed = 34.milesPerHour, - gust = 56.milesPerHour, - ) - ).toTestPacket().toTestCapturedPacket() - val data = StationData( - packets = listOf(packet), - metric = false, - ) - - val result = factory.create(data) - - assertEquals("KE0YOG", result.name) - assertEquals("72ºF", result.temperature) - assertEquals("12º|34mph|56mph", result.wind) - assertNull(result.comment, "No comment for positionless weather") - assertNull(result.altitude, "No altitude for positionless weather") - assertNull(result.telemetryValues, "No telemetry for positionless weather") - assertNull(result.telemetrySequence, "No telemetry for positionless weather") - } - - @Test - fun weatherPacket() { - val factory = StationInsightViewStateFactory(dummySummaryFactory) - val packet = PacketData.Weather( - coordinates = GeoCoordinates(1.0.latitude, 2.0.longitude), - temperature = 72.fahrenheit, - windData = WindData(12.degrees, 34.milesPerHour, 56.milesPerHour), - ).toTestPacket().toTestCapturedPacket() - val data = StationData( - packets = listOf(packet), - metric = false, - ) - - val result = factory.create(data) - - assertEquals("KE0YOG", result.name) - assertEquals("72ºF", result.temperature) - assertEquals("12º|34mph|56mph", result.wind) - assertNull(result.comment, "No comment for weather packet") - assertNull(result.altitude, "No altitude for weather packet") - assertNull(result.telemetryValues, "No telemetry for weather packet") - assertNull(result.telemetrySequence, "No telemetry for weather packet") - } - - @Test - fun emptyWeatherPacket() { - val factory = StationInsightViewStateFactory(dummySummaryFactory) - val packet = PacketData.Weather( - coordinates = GeoCoordinates(1.latitude, 2.longitude), - ).toTestPacket().toTestCapturedPacket() - val data = StationData( - packets = listOf(packet), - metric = false, - ) - - val result = factory.create(data) - - assertEquals("KE0YOG", result.name) - assertNull(result.temperature, "No temperature for empty weather packet") - assertNull(result.wind, "No wind data for empty non weather packet") - assertNull(result.comment, "No comment for unknown packet") - assertNull(result.altitude, "No altitude for unknown packet") - assertNull(result.telemetryValues, "No telemetry for unknown packet") - assertNull(result.telemetrySequence, "No telemetry for unknown packet") - } - - @Test - fun positionPacket() { - val factory = StationInsightViewStateFactory(dummySummaryFactory) - val packet = PacketData.Position( - coordinates = GeoCoordinates(1.latitude, 2.longitude), - symbol = symbolOf('/', 'a'), - comment = "test", - ).toTestPacket().toTestCapturedPacket() - val data = StationData( - packets = listOf(packet), - metric = false, - ) - - val result = factory.create(data) - - assertEquals("KE0YOG", result.name) - assertNull(result.temperature, "No temperature for non weather packet") - assertNull(result.wind, "No wind data for non weather packet") - assertEquals("test", result.comment) - assertNull(result.altitude, "No altitude for position packet") - assertNull(result.telemetryValues, "No telemetry for position packet") - assertNull(result.telemetrySequence, "No telemetry for position packet") - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/symbol/SymbolDoubles.kt b/android-application/src/test/java/com/inkapplications/ack/android/symbol/SymbolDoubles.kt deleted file mode 100644 index a656068d..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/symbol/SymbolDoubles.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import android.graphics.Bitmap -import com.inkapplications.ack.structures.Symbol - -object SymbolFactoryDummy: SymbolFactory { - override val defaultSymbol: Bitmap? = null - override fun createSymbol(symbol: Symbol): Bitmap? = null -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/symbol/SymbolResourceLocatorTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/symbol/SymbolResourceLocatorTest.kt deleted file mode 100644 index ab34668e..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/symbol/SymbolResourceLocatorTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.inkapplications.ack.android.symbol - -import com.inkapplications.ack.structures.symbolOf -import kimchi.logger.EmptyLogger -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull -import org.junit.Test - -class SymbolResourceLocatorTest { - @Test - fun primaryResources() { - val locator = SymbolResourceLocator(EmptyLogger) - - assertEquals("symbol_0", locator.getBaseResourceName(symbolOf('!', '/'))) - assertEquals("symbol_93", locator.getBaseResourceName(symbolOf('~', '/'))) - } - - @Test - fun alternateResources() { - val locator = SymbolResourceLocator(EmptyLogger) - - assertEquals("symbol_96", locator.getBaseResourceName(symbolOf('!', '\\'))) - assertEquals("symbol_189", locator.getBaseResourceName(symbolOf('~', '\\'))) - } - - @Test - fun overlayResources() { - val locator = SymbolResourceLocator(EmptyLogger) - - assertEquals("symbol_207", locator.getOverlayResourceName(symbolOf('#', '0'))) - assertEquals("symbol_216", locator.getOverlayResourceName(symbolOf('z', '9'))) - assertEquals("symbol_224", locator.getOverlayResourceName(symbolOf('A', 'A'))) - assertEquals("symbol_249", locator.getOverlayResourceName(symbolOf('^', 'Z'))) - } - - @Test - fun unsupportedOverlay() { - val locator = SymbolResourceLocator(EmptyLogger) - - assertNull(locator.getOverlayResourceName(symbolOf('!', '0'))) - assertNull(locator.getOverlayResourceName(symbolOf('~', '9'))) - assertNull(locator.getOverlayResourceName(symbolOf('1', 'A'))) - assertNull(locator.getOverlayResourceName(symbolOf('B', 'Z'))) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/transmit/PathTransformerTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/transmit/PathTransformerTest.kt deleted file mode 100644 index de18d858..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/transmit/PathTransformerTest.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.inkapplications.ack.android.transmit - -import com.inkapplications.ack.structures.Digipeater -import com.inkapplications.ack.structures.station.StationAddress -import kotlin.test.Test -import kotlin.test.assertEquals - -class PathTransformerTest { - @Test - fun toStorage() { - val input = listOf( - Digipeater(StationAddress("KE0YOG")), - ) - - val result = PathTransformer.toStorage(input) - - assertEquals("KE0YOG", result) - } - - @Test - fun toStorageMultiple() { - val input = listOf( - Digipeater(StationAddress("KE0YOG")), - Digipeater(StationAddress("KE0YOF", "2")), - ) - - val result = PathTransformer.toStorage(input) - - assertEquals("KE0YOG,KE0YOF-2", result) - } - - @Test - fun toData() { - val expected = listOf( - Digipeater(StationAddress("KE0YOG")), - ) - val result = PathTransformer.toData("KE0YOG") - - assertEquals(expected, result) - } - - @Test - fun toDataMultiple() { - val expected = listOf( - Digipeater(StationAddress("KE0YOG")), - Digipeater(StationAddress("KE0YOF", "2")), - ) - val result = PathTransformer.toData("KE0YOG,KE0YOF-2") - - assertEquals(expected, result) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/transmit/PercentageTransformer.kt b/android-application/src/test/java/com/inkapplications/ack/android/transmit/PercentageTransformer.kt deleted file mode 100644 index e34f37f4..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/transmit/PercentageTransformer.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.inkapplications.ack.android.transmit - -import com.inkapplications.ack.android.settings.transformer.PercentageTransformer -import inkapplications.spondee.scalar.percent -import kotlin.test.Test -import kotlin.test.assertEquals - -class PercentageTransformer { - @Test - fun toData() { - assertEquals(69.percent, PercentageTransformer.toData(69)) - } - - @Test - fun toStorage() { - assertEquals(69, 69.percent.let(PercentageTransformer::toStorage)) - assertEquals(70, 69.5.percent.let(PercentageTransformer::toStorage)) - } -} diff --git a/android-application/src/test/java/com/inkapplications/ack/android/transmit/SymbolTransformerTest.kt b/android-application/src/test/java/com/inkapplications/ack/android/transmit/SymbolTransformerTest.kt deleted file mode 100644 index d2068224..00000000 --- a/android-application/src/test/java/com/inkapplications/ack/android/transmit/SymbolTransformerTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.inkapplications.ack.android.transmit - -import com.inkapplications.ack.structures.Symbol -import kotlin.test.Test -import kotlin.test.assertEquals - -class SymbolTransformerTest { - @Test - fun toStorage() { - assertEquals("$/", Symbol.Primary('$').let(SymbolTransformer::toStorage)) - } - - @Test - fun toData() { - assertEquals(Symbol.Primary('$'), SymbolTransformer.toData("$/")) - } -} diff --git a/android-extensions/build.gradle.kts b/android-extensions/build.gradle.kts deleted file mode 100644 index 1f4177a3..00000000 --- a/android-extensions/build.gradle.kts +++ /dev/null @@ -1,47 +0,0 @@ -plugins { - id("com.android.library") - kotlin("android") - kotlin("kapt") -} - -android { - namespace = "com.inkapplications.android.extensions" - compileSdk = 33 - - defaultConfig { - minSdk = 21 - } - - buildFeatures { - compose = true - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() - } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() - } - compileOptions { - targetCompatibility = JavaVersion.VERSION_11 - sourceCompatibility = JavaVersion.VERSION_11 - } -} - -dependencies { - implementation(libs.coroutines.core) - - api(libs.androidx.core) - api(libs.androidx.compose.ui) - api(libs.androidx.compose.foundation) - implementation(libs.androidx.preference) - - api(libs.ack.structures) - - implementation(libs.bundles.dagger.libraries) - kapt(libs.bundles.dagger.kapt) - - testImplementation(libs.junit) - testImplementation(libs.coroutines.test) - testImplementation(libs.kotlin.test.core) -} diff --git a/android-extensions/src/main/AndroidManifest.xml b/android-extensions/src/main/AndroidManifest.xml deleted file mode 100644 index 508d5b01..00000000 --- a/android-extensions/src/main/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/Activities.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/Activities.kt deleted file mode 100644 index fff7f026..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/Activities.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.inkapplications.android.extensions - -import android.app.Activity -import android.app.Application -import android.os.Bundle - -/** - * Sends lifecycle event logs to a logger. - */ -class LifecycleLogger( - private val logger: (String) -> Unit -): Application.ActivityLifecycleCallbacks { - override fun onActivityPaused(activity: Activity) { - logger("${activity.javaClass.simpleName} -> Paused") - } - - override fun onActivityStarted(activity: Activity) { - logger("${activity.javaClass.simpleName} -> Started") - } - - override fun onActivityDestroyed(activity: Activity) { - logger("${activity.javaClass.simpleName} -> Destroyed") - } - - override fun onActivitySaveInstanceState(activity: Activity, p1: Bundle) { - logger("${activity.javaClass.simpleName} -> Saved Instance") - } - - override fun onActivityStopped(activity: Activity) { - logger("${activity.javaClass.simpleName} -> Stopped") - } - - override fun onActivityCreated(activity: Activity, bundle: Bundle?) { - logger("${activity.javaClass.simpleName} -> Created") - } - - override fun onActivityResumed(activity: Activity) { - logger("${activity.javaClass.simpleName} -> Resumed") - } -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/ApplicationModule.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/ApplicationModule.kt deleted file mode 100644 index 11dc2feb..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/ApplicationModule.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.inkapplications.android.extensions - -import android.app.Application -import android.app.NotificationManager -import android.bluetooth.BluetoothAdapter -import android.content.Context -import android.content.SharedPreferences -import android.content.res.Resources -import android.location.LocationManager -import androidx.preference.PreferenceManager -import com.inkapplications.android.extensions.bluetooth.AndroidBluetoothAccess -import com.inkapplications.android.extensions.bluetooth.BluetoothDeviceAccess -import com.inkapplications.android.extensions.bluetooth.DummyBluetoothDeviceAccess -import com.inkapplications.android.extensions.format.AndroidResourceDateTimeFormatter -import com.inkapplications.android.extensions.format.DateTimeFormatter -import com.inkapplications.android.extensions.location.AndroidLocationAccess -import com.inkapplications.android.extensions.location.LocationAccess -import dagger.Binds -import dagger.Module -import dagger.Provides -import dagger.Reusable -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module(includes = [ StaticApplicationModule::class ]) -@InstallIn(SingletonComponent::class) -class ApplicationModule { - @Provides - fun context(application: Application): Context = application - - @Provides - fun sharedPreferences(application: Application): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(application) - - @Provides - fun resources(application: Application): Resources = application.resources - - @Provides - fun locationManager(application: Application) = application.getSystemService(Context.LOCATION_SERVICE) as LocationManager - - @Provides - fun notificationManager(application: Application) = application.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - - @Provides - @Reusable - fun bluetooth(): BluetoothAdapter = BluetoothAdapter.getDefaultAdapter() - - @Provides - @Reusable - fun bluetoothAccess( - context: Context, - ): BluetoothDeviceAccess { - val bluetooth = BluetoothAdapter.getDefaultAdapter() ?: return DummyBluetoothDeviceAccess - return AndroidBluetoothAccess( - context = context, - bluetoothAdapter = bluetooth, - ) - } -} - -@Module -@InstallIn(SingletonComponent::class) -internal abstract class StaticApplicationModule { - @Binds - abstract fun stringResources(androidStringResources: AndroidStringResources): StringResources - - @Binds - abstract fun integerResources(android: AndroidIntegerResources): IntegerResources - - @Binds - abstract fun locationAccess(locationAccess: AndroidLocationAccess): LocationAccess - - @Binds - abstract fun timeFormat(formatter: AndroidResourceDateTimeFormatter): DateTimeFormatter -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/ExtendedActivity.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/ExtendedActivity.kt deleted file mode 100644 index 4aad8be3..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/ExtendedActivity.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.inkapplications.android.extensions - -import android.os.Bundle -import androidx.annotation.CallSuper -import androidx.appcompat.app.AppCompatActivity -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.cancel - -/** - * An Activity with some generic add-ons. - */ -abstract class ExtendedActivity: AppCompatActivity() { - /** - * Only run while the screen is in the foreground, aka started. - */ - protected lateinit var foregroundScope: CoroutineScope - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - onCreate() - - if (savedInstanceState == null) { - onFirstCreate() - } else { - onRestore(savedInstanceState) - } - } - - @CallSuper - open fun onCreate() {} - - @CallSuper - open fun onRestore(savedInstanceState: Bundle) {} - - @CallSuper - protected open fun onFirstCreate() {} - - override fun onStart() { - super.onStart() - foregroundScope = MainScope() - } - - override fun onStop() { - foregroundScope.cancel() - super.onStop() - } -} \ No newline at end of file diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/IntegerResources.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/IntegerResources.kt deleted file mode 100644 index f9c74b1b..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/IntegerResources.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.inkapplications.android.extensions - -import android.content.res.Resources -import androidx.annotation.IntegerRes -import dagger.Reusable -import javax.inject.Inject - -/** - * Provides access for locating integer configurations in resources. - * - * Using this instead of Android's resources makes testing easier. - */ -interface IntegerResources { - /** - * Get an integer from resources. - */ - fun getInteger(@IntegerRes key: Int): Int -} - -/** - * Use Android's Resource class to fetch integer resources - */ -@Reusable -class AndroidIntegerResources @Inject constructor(private val resources: Resources): IntegerResources { - override fun getInteger(key: Int): Int = resources.getInteger(key) -} - -/** - * Stub implementation of integer resources, used for testing. - */ -object StubIntegerResources: IntegerResources { - override fun getInteger(key: Int): Int = TODO("stub") -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/Notifications.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/Notifications.kt deleted file mode 100644 index 48a1aa3e..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/Notifications.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.android.extensions - -import android.app.Notification -import android.content.Context -import android.os.Build - -/** - * Create a notification builder with a channel ID if the OS supports it. - */ -fun Context.notificationBuilder(channelId: String): Notification.Builder { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Notification.Builder(this, channelId) - } else { - Notification.Builder(this) - } -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/StringResources.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/StringResources.kt deleted file mode 100644 index ba21f003..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/StringResources.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.inkapplications.android.extensions - -import android.content.res.Resources -import androidx.annotation.StringRes -import dagger.Reusable -import javax.inject.Inject - -/** - * Interface for locating string resources. - * - * Using this instead of Android's resource class makes testing - * considerably easier. - */ -interface StringResources { - fun getString(@StringRes key: Int): String - fun getString(@StringRes key: Int, vararg arguments: Any): String -} - -/** - * Load String resources via Android's default resource locator. - */ -@Reusable -class AndroidStringResources @Inject constructor(private val resources: Resources): StringResources { - override fun getString(key: Int): String = resources.getString(key) - override fun getString(key: Int, vararg arguments: Any) = resources.getString(key, *arguments) -} - -/** - * Stub resources, used for testing. - */ -object StubStringResources: StringResources { - override fun getString(key: Int): String = TODO("Stub") - override fun getString(key: Int, vararg arguments: Any): String = TODO("Stub") -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/ViewStateFactory.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/ViewStateFactory.kt deleted file mode 100644 index 356bdd93..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/ViewStateFactory.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.inkapplications.android.extensions - -/** - * Generic interface for creating a view state type from data. - */ -interface ViewStateFactory { - /** - * Create a new instance of the viewmodel from some data. - */ - fun create(data: DATA): STATE -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/AndroidBluetoothAccess.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/AndroidBluetoothAccess.kt deleted file mode 100644 index f36375d9..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/AndroidBluetoothAccess.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.inkapplications.android.extensions.bluetooth - -import android.Manifest -import android.annotation.SuppressLint -import android.bluetooth.BluetoothAdapter -import android.bluetooth.BluetoothDevice -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.os.Build -import androidx.annotation.RequiresPermission -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.scan -import java.io.InputStream -import java.io.OutputStream -import java.util.* - -/** - * Provides access to bluetooth devices via event streams. - */ -internal class AndroidBluetoothAccess( - context: Context, - private val bluetoothAdapter: BluetoothAdapter, -): BluetoothDeviceAccess { - /** - * Flow that starts bluetooth discovery and emits discovered devices as they're found. - */ - @SuppressLint("MissingPermission") - @RequiresPermission(allOf = [Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN]) - private val deviceEmitter: Flow = callbackFlow { - val deviceFoundReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - val action = intent.action - if (BluetoothDevice.ACTION_FOUND == action) { - val device: BluetoothDevice = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, BluetoothDevice::class.java) - ?: return - } else { - intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) as? BluetoothDevice - ?: return - } - trySend( - BluetoothDeviceData( - address = device.address, - alias = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) device.alias else null, - name = device.name.orEmpty(), - majorClass = device.bluetoothClass?.majorDeviceClass, - deviceClass = device.bluetoothClass?.deviceClass, - bondState = device.bondState, - ) - ) - } - } - } - - val filter = IntentFilter(BluetoothDevice.ACTION_FOUND) - context.registerReceiver(deviceFoundReceiver, filter) - bluetoothAdapter.startDiscovery() - awaitClose { context.unregisterReceiver(deviceFoundReceiver) } - } - - /** - * An accumulating list of discovered devices. - * - * Starting this flow will start bluetooth discovery and collect discovered - * devices into a list, de-duplicated by device address. - */ - @RequiresPermission(allOf = [Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN]) - override val devices: Flow> = deviceEmitter.scan(emptyList()) { acc, device -> - if (acc.any { it.address == device.address }) acc else acc + device - } - - /** - * Connect to a bluetooth device. - * - * This starts a connection to the specified bluetooth device and invokes - * the [onConnect] callback with the input and output streams for the connection. - * The [onConnect] method should remain suspended to keep the connection open. - * Once the method returns, the bluetooth socket will be closed. - */ - @RequiresPermission(allOf = [Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN]) - override suspend fun connect( - device: BluetoothDeviceData, - uuid: UUID, - onConnect: suspend (InputStream, OutputStream) -> Unit, - ) { - val bluetoothDevice = bluetoothAdapter.getRemoteDevice(device.address) - bluetoothAdapter.cancelDiscovery() - val socket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid) - socket.connect() - onConnect(socket.inputStream, socket.outputStream) - socket.close() - } -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/BluetoothDeviceAccess.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/BluetoothDeviceAccess.kt deleted file mode 100644 index d6d7f73b..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/BluetoothDeviceAccess.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.inkapplications.android.extensions.bluetooth - -import android.Manifest -import androidx.annotation.RequiresPermission -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf -import java.io.InputStream -import java.io.OutputStream -import java.util.* - -interface BluetoothDeviceAccess { - @get:RequiresPermission(allOf = [Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN]) - val devices: Flow> - - @RequiresPermission(allOf = [Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN]) - suspend fun connect( - device: BluetoothDeviceData, - uuid: UUID, - onConnect: suspend (InputStream, OutputStream) -> Unit, - ) -} - -/** - * No-op implementation of [BluetoothDeviceAccess]. - */ -object DummyBluetoothDeviceAccess: BluetoothDeviceAccess { - override val devices: Flow> = flowOf() - - override suspend fun connect( - device: BluetoothDeviceData, - uuid: UUID, - onConnect: suspend (InputStream, OutputStream) -> Unit, - ) = Unit -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/BluetoothDeviceData.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/BluetoothDeviceData.kt deleted file mode 100644 index d8bae04d..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/bluetooth/BluetoothDeviceData.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.inkapplications.android.extensions.bluetooth - -/** - * Plain Data about a bluetooth device, de-coupled from Android's active model. - */ -data class BluetoothDeviceData( - val address: String, - val alias: String?, - val name: String, - val majorClass: Int?, - val deviceClass: Int?, - val bondState: Int, -) diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/compose/Modifiers.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/compose/Modifiers.kt deleted file mode 100644 index 1b6d7713..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/compose/Modifiers.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.inkapplications.android.extensions.compose - -import android.os.Build -import android.os.VibrationEffect -import android.os.Vibrator -import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.ui.Modifier -import androidx.compose.ui.composed -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalContext -import androidx.core.content.ContextCompat - -fun Modifier.longClickable(action: () -> Unit) = composed { - val vibrator = ContextCompat.getSystemService(LocalContext.current, Vibrator::class.java)!! - pointerInput(Unit) { - detectTapGestures( - onLongPress = { - when { - Build.VERSION.SDK_INT >= 29 -> vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK)) - Build.VERSION.SDK_INT >= 26 -> vibrator.vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE)) - else -> vibrator.vibrate(50) - } - action() - } - ) - } -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/control/ControlState.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/control/ControlState.kt deleted file mode 100644 index 7c34275f..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/control/ControlState.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.inkapplications.android.extensions.control - -import androidx.compose.runtime.Composable - -enum class ControlState { - On, - Off, - Disabled, - Hidden, -} - -@Composable -inline fun ControlState.whenOn(action: @Composable () -> Unit) { - if (this == ControlState.On) action() -} - -@Composable -inline fun ControlState.whenOff(action: @Composable () -> Unit) { - if (this == ControlState.Off) action() -} - -@Composable -inline fun ControlState.whenDisabled(action: @Composable () -> Unit) { - if (this == ControlState.Disabled) action() -} - -@Composable -inline fun ControlState.whenHidden(action: @Composable () -> Unit) { - if (this == ControlState.Hidden) action() -} - -@Composable -inline fun ControlState.whenVisible(action: @Composable () -> Unit) { - if (this != ControlState.Hidden) action() -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/format/AndroidResourceDateTimeFormatter.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/format/AndroidResourceDateTimeFormatter.kt deleted file mode 100644 index f49f246e..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/format/AndroidResourceDateTimeFormatter.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.inkapplications.android.extensions.format - -import com.inkapplications.android.extensions.R -import com.inkapplications.android.extensions.StringResources -import dagger.Reusable -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import java.text.SimpleDateFormat -import javax.inject.Inject - -/** - * Leverages Android's string resources to create time strings. - */ -@Reusable -class AndroidResourceDateTimeFormatter @Inject constructor( - stringResources: StringResources, - private val timeZone: TimeZone, - private val clock: Clock, -): DateTimeFormatter { - private val timeFormat = SimpleDateFormat(stringResources.getString(R.string.datetime_format_time)).also { - it.timeZone = java.util.TimeZone.getTimeZone(timeZone.id) - } - private val dateTimeFormat = SimpleDateFormat(stringResources.getString(R.string.datetime_format_datetime)).also { - it.timeZone = java.util.TimeZone.getTimeZone(timeZone.id) - } - private val fullTimestampFormat = SimpleDateFormat(stringResources.getString(R.string.datetime_format_timestamp)).also { - it.timeZone = java.util.TimeZone.getTimeZone(timeZone.id) - } - - override fun formatTimestamp(instant: Instant): String { - val now = clock.now().toLocalDateTime(timeZone) - val local = instant.toLocalDateTime(timeZone) - - return when { - local.year == now.year && local.dayOfYear == now.dayOfYear -> timeFormat.format(instant.toEpochMilliseconds()) - local.year == now.year && local.month == now.month -> dateTimeFormat.format(instant.toEpochMilliseconds()) - else -> fullTimestampFormat.format(instant.toEpochMilliseconds()) - } - } -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/format/DateTimeFormatter.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/format/DateTimeFormatter.kt deleted file mode 100644 index 4c81f778..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/format/DateTimeFormatter.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.inkapplications.android.extensions.format - -import kotlinx.datetime.Instant - -/** - * Format date/time strings in the application - */ -interface DateTimeFormatter { - /** - * Format used for items with a timestamp, such as messages or logs. - */ - fun formatTimestamp(instant: Instant): String -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/location/AndroidLocationAccess.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/location/AndroidLocationAccess.kt deleted file mode 100644 index 2c764eaf..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/location/AndroidLocationAccess.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.inkapplications.android.extensions.location - -import android.location.Location -import android.location.LocationListener -import android.location.LocationManager -import dagger.Reusable -import inkapplications.spondee.measure.Length -import inkapplications.spondee.measure.metric.meters -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.spatial.latitude -import inkapplications.spondee.spatial.longitude -import inkapplications.spondee.structure.toFloat -import kotlinx.coroutines.cancel -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.channels.trySendBlocking -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import javax.inject.Inject -import kotlin.time.Duration -import kotlin.time.Duration.Companion.minutes - -@Reusable -class AndroidLocationAccess @Inject constructor( - private val locationManager: LocationManager, -): LocationAccess { - override val lastKnownLocation: LocationUpdate? - get() { - val lastGps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) - val lastNetwork = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) - val recent = when { - System.currentTimeMillis() - (lastGps?.time ?: 0) < 30.minutes.inWholeMilliseconds -> lastGps - System.currentTimeMillis() - (lastNetwork?.time ?: 0) < 30.minutes.inWholeMilliseconds -> lastNetwork - else -> lastGps ?: lastNetwork - } - - return recent?.toUpdate() - } - override fun observeLocationChanges(minTime: Duration, minDistance: Length): Flow = callbackFlow { - val callback = object: LocationListener { - override fun onLocationChanged(location: Location) { - trySendBlocking(location.toUpdate()) - } - } - val providerPreferences = listOf( - LocationManager.FUSED_PROVIDER, - LocationManager.GPS_PROVIDER, - LocationManager.NETWORK_PROVIDER, - LocationManager.PASSIVE_PROVIDER, - ) - val provider = providerPreferences.firstOrNull { it in locationManager.getProviders(true) } ?: run { - cancel() - awaitClose() - return@callbackFlow - } - locationManager.requestLocationUpdates( - provider, - minTime.inWholeMilliseconds, - minDistance.toMeters().toFloat(), - callback, - ) - - awaitClose { - locationManager.removeUpdates(callback) - } - } - - private fun Location.toUpdate() = LocationUpdate( - location = GeoCoordinates(latitude.latitude, longitude.longitude), - altitude = altitude.meters, - ) -} diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/location/AndroidLocationUpdate.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/location/AndroidLocationUpdate.kt deleted file mode 100644 index fd755a88..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/location/AndroidLocationUpdate.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.inkapplications.android.extensions.location - -import inkapplications.spondee.measure.Length -import inkapplications.spondee.spatial.GeoCoordinates - -data class LocationUpdate( - val location: GeoCoordinates, - val altitude: Length, -) diff --git a/android-extensions/src/main/java/com/inkapplications/android/extensions/location/LocationAccess.kt b/android-extensions/src/main/java/com/inkapplications/android/extensions/location/LocationAccess.kt deleted file mode 100644 index 884c7826..00000000 --- a/android-extensions/src/main/java/com/inkapplications/android/extensions/location/LocationAccess.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.android.extensions.location - -import inkapplications.spondee.measure.Length -import inkapplications.spondee.measure.us.miles -import kotlinx.coroutines.flow.Flow -import kotlin.time.Duration -import kotlin.time.Duration.Companion.minutes - -interface LocationAccess { - val lastKnownLocation: LocationUpdate? - - fun observeLocationChanges( - minTime: Duration = 5.minutes, - minDistance: Length = 5.miles, - ): Flow -} diff --git a/android-extensions/src/main/res/values/date_formats.xml b/android-extensions/src/main/res/values/date_formats.xml deleted file mode 100644 index 468dd586..00000000 --- a/android-extensions/src/main/res/values/date_formats.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - yyyy-MM-dd HH:mm - HH:mm - MMM d, HH:mm - diff --git a/android-extensions/src/test/java/com/inkapplications/android/extensions/format/AndroidResourceDateTimeFormatterTest.kt b/android-extensions/src/test/java/com/inkapplications/android/extensions/format/AndroidResourceDateTimeFormatterTest.kt deleted file mode 100644 index 4b0923e9..00000000 --- a/android-extensions/src/test/java/com/inkapplications/android/extensions/format/AndroidResourceDateTimeFormatterTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.inkapplications.android.extensions.format - -import com.inkapplications.android.extensions.StringResources -import com.inkapplications.android.extensions.StubStringResources -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.datetime.TimeZone -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.time.Duration.Companion.days -import kotlin.time.Duration.Companion.minutes - -class AndroidResourceDateTimeFormatterTest { - @Test - fun timestampFormatRecent() { - val stubResource = object: StringResources by StubStringResources { - override fun getString(key: Int): String = "HH:mm" - } - val time = Instant.fromEpochMilliseconds(-22073104000) - val formatter = AndroidResourceDateTimeFormatter(stubResource, TimeZone.UTC, (time + 25.minutes).toFixedClock()) - - val result = formatter.formatTimestamp(time) - - assertEquals("12:34", result) - } - - @Test - fun timestampFormatWithinYear() { - val stubResource = object: StringResources by StubStringResources { - override fun getString(key: Int): String = "MMM d, HH:mm" - } - val time = Instant.fromEpochMilliseconds(-22073104000) - val formatter = AndroidResourceDateTimeFormatter(stubResource, TimeZone.UTC, (time + 25.days).toFixedClock()) - - val result = formatter.formatTimestamp(time) - - assertEquals("Apr 20, 12:34", result) - } - - @Test - fun timestampFormatOld() { - val stubResource = object: StringResources by StubStringResources { - override fun getString(key: Int): String = "yyyy-MM-dd HH:mm" - } - val time = Instant.fromEpochMilliseconds(-22073104000) - val formatter = AndroidResourceDateTimeFormatter(stubResource, TimeZone.UTC, (time + 500.days).toFixedClock()) - - val result = formatter.formatTimestamp(time) - - assertEquals("1969-04-20 12:34", result) - } - - private fun Instant.toFixedClock() = object: Clock { - override fun now(): Instant = this@toFixedClock - } -} diff --git a/aprs-android/build.gradle.kts b/aprs-android/build.gradle.kts deleted file mode 100644 index 9e84e01f..00000000 --- a/aprs-android/build.gradle.kts +++ /dev/null @@ -1,76 +0,0 @@ -plugins { - id("com.android.library") - kotlin("android") - kotlin("kapt") - id("app.cash.sqldelight") -} - -sqldelight { - databases { - create("PacketDatabase") { - packageName.set("com.inkapplications.ack.data") - } - } -} - -android { - namespace = "com.inkapplications.ack.data" - compileSdk = 34 - ndkVersion = "21.3.6528147" - - defaultConfig { - minSdk = 14 - kapt { - arguments { - arg("room.schemaLocation", "$projectDir/src/main/schema") - } - } - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } - sourceSets { - // Adds exported schema location as test app assets. - getByName("androidTest").assets.srcDirs("$projectDir/src/main/schema") - } - - externalNativeBuild { - cmake { - version = "3.31.6" - path = File("${projectDir}/src/main/cpp/CMakeLists.txt") - } - } - packaging { - resources { - excludes += "META-INF/kotlinx-coroutines-core.kotlin_module" - } - } - compileOptions { - targetCompatibility = JavaVersion.VERSION_11 - sourceCompatibility = JavaVersion.VERSION_11 - } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() - } -} - -dependencies { - api(libs.coroutines.core) - - implementation(projects.androidExtensions) - - api(libs.ack.codec) - api(libs.ack.client) - api(libs.ack.structures) - - api(libs.kimchi.logger) - - implementation(libs.watermelon.coroutines) - implementation(libs.watermelon.standard) - implementation(libs.spondee.units) - - implementation(libs.bundles.sqldelight.android) - implementation(libs.bundles.dagger.libraries) - kapt(libs.bundles.dagger.kapt) - - androidTestImplementation(libs.androidx.test.runner) - androidTestImplementation(libs.androidx.test.core) -} diff --git a/aprs-android/src/main/AndroidManifest.xml b/aprs-android/src/main/AndroidManifest.xml deleted file mode 100644 index a83cf7be..00000000 --- a/aprs-android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/aprs-android/src/main/cpp/CMakeLists.txt b/aprs-android/src/main/cpp/CMakeLists.txt deleted file mode 100644 index a8b079c7..00000000 --- a/aprs-android/src/main/cpp/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 3.4.1) - -set(SOURCES ${SOURCES} hdlc.c multimon.c demod_afsk12.c) -add_library(multimon SHARED ${SOURCES}) - -# Include libraries needed for kotlin-jni lib -target_link_libraries(multimon android log) diff --git a/aprs-android/src/main/cpp/demod_afsk12.c b/aprs-android/src/main/cpp/demod_afsk12.c deleted file mode 100644 index 925db2bc..00000000 --- a/aprs-android/src/main/cpp/demod_afsk12.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * demod_afsk12.c -- 1200 baud AFSK demodulator - * - * Copyright (C) 1996 - * Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* ---------------------------------------------------------------------- */ - -#include "multimon.h" -#include "filter.h" -#include -#include - -/* ---------------------------------------------------------------------- */ - -/* - * Standard TCM3105 clock frequency: 4.4336MHz - * Mark frequency: 2200 Hz - * Space frequency: 1200 Hz - */ - -#define FREQ_MARK 1200 -#define FREQ_SPACE 2200 -#define FREQ_SAMP 22050 -#define BAUD 1200 -#define SUBSAMP 2 - -/* ---------------------------------------------------------------------- */ - -#define CORRLEN ((int)(FREQ_SAMP/BAUD)) -#define SPHASEINC (0x10000u*BAUD*SUBSAMP/FREQ_SAMP) - -static float corr_mark_i[CORRLEN]; -static float corr_mark_q[CORRLEN]; -static float corr_space_i[CORRLEN]; -static float corr_space_q[CORRLEN]; - -/* ---------------------------------------------------------------------- */ - -static void afsk12_init(struct demod_state *s) -{ - float f; - int i; - - hdlc_init(s); - memset(&s->l1.afsk12, 0, sizeof(s->l1.afsk12)); - for (f = 0, i = 0; i < CORRLEN; i++) { - corr_mark_i[i] = cos(f); - corr_mark_q[i] = sin(f); - f += 2.0*M_PI*FREQ_MARK/FREQ_SAMP; - } - for (f = 0, i = 0; i < CORRLEN; i++) { - corr_space_i[i] = cos(f); - corr_space_q[i] = sin(f); - f += 2.0*M_PI*FREQ_SPACE/FREQ_SAMP; - } -} - -/* ---------------------------------------------------------------------- */ - -static void afsk12_demod(struct demod_state *s, float *buffer, int length) -{ - float f; - unsigned char curbit; - - if (s->l1.afsk12.subsamp) { - int numfill = SUBSAMP - s->l1.afsk12.subsamp; - if (length < numfill) { - s->l1.afsk12.subsamp += length; - return; - } - buffer += numfill; - length -= numfill; - s->l1.afsk12.subsamp = 0; - } - for (; length >= SUBSAMP; length -= SUBSAMP, buffer += SUBSAMP) { - f = fsqr(mac(buffer, corr_mark_i, CORRLEN)) + - fsqr(mac(buffer, corr_mark_q, CORRLEN)) - - fsqr(mac(buffer, corr_space_i, CORRLEN)) - - fsqr(mac(buffer, corr_space_q, CORRLEN)); - s->l1.afsk12.dcd_shreg <<= 1; - s->l1.afsk12.dcd_shreg |= (f > 0); - /* - * check if transition - */ - if ((s->l1.afsk12.dcd_shreg ^ (s->l1.afsk12.dcd_shreg >> 1)) & 1) { - if (s->l1.afsk12.sphase < (0x8000u-(SPHASEINC/2))) - s->l1.afsk12.sphase += SPHASEINC/8; - else - s->l1.afsk12.sphase -= SPHASEINC/8; - } - s->l1.afsk12.sphase += SPHASEINC; - if (s->l1.afsk12.sphase >= 0x10000u) { - s->l1.afsk12.sphase &= 0xffffu; - s->l1.afsk12.lasts <<= 1; - s->l1.afsk12.lasts |= s->l1.afsk12.dcd_shreg & 1; - curbit = (s->l1.afsk12.lasts ^ - (s->l1.afsk12.lasts >> 1) ^ 1) & 1; - hdlc_rxbit(s, curbit); - } - } - s->l1.afsk12.subsamp = length; -} - -/* ---------------------------------------------------------------------- */ - -const struct demod_param demod_afsk1200 = { - "AFSK1200", FREQ_SAMP, CORRLEN, afsk12_init, afsk12_demod -}; - -/* ---------------------------------------------------------------------- */ diff --git a/aprs-android/src/main/cpp/filter.h b/aprs-android/src/main/cpp/filter.h deleted file mode 100644 index 26de7494..00000000 --- a/aprs-android/src/main/cpp/filter.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * filter.h -- optimized filter routines - * - * Copyright (C) 1996 - * Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _FILTER_H -#define _FILTER_H - -#ifdef ARCH_I386 -#include "filter-i386.h" -#endif /* ARCH_I386 */ - -static inline unsigned int hweight32(unsigned int w) -#ifndef _MSC_VER -__attribute__ ((unused)) -#endif -; -static inline unsigned int hweight16(unsigned short w) -#ifndef _MSC_VER -__attribute__ ((unused)) -#endif -; - -static inline unsigned int hweight8(unsigned char w) -#ifndef _MSC_VER -__attribute__ ((unused)) -#endif -; - -static inline unsigned int gcd(unsigned int x, unsigned int y) -#ifndef _MSC_VER -__attribute__ ((unused)) -#endif -; -static inline unsigned int lcm(unsigned int x, unsigned int y) -#ifndef _MSC_VER -__attribute__ ((unused)) -#endif -; - -#ifndef __HAVE_ARCH_MAC -static inline float mac(const float *a, const float *b, unsigned int size) -{ - float sum = 0; - unsigned int i; - - for (i = 0; i < size; i++) - sum += (*a++) * (*b++); - return sum; -} -#endif /* __HAVE_ARCH_MAC */ - -static inline float fsqr(float f) -{ - return f*f; -} - -#endif /* _FILTER_H */ diff --git a/aprs-android/src/main/cpp/hdlc.c b/aprs-android/src/main/cpp/hdlc.c deleted file mode 100644 index 718163de..00000000 --- a/aprs-android/src/main/cpp/hdlc.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * hdlc.c -- hdlc decoder and AX.25 packet dump - * - * Copyright (C) 1996 - * Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "multimon.h" -#include -#include - -static const unsigned short crc_ccitt_table[] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -/* ---------------------------------------------------------------------- */ - -static inline int check_crc_ccitt(const unsigned char *buf, int cnt) -{ - unsigned int crc = 0xffff; - - for (; cnt > 0; cnt--) - crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff]; - return (crc & 0xffff) == 0xf0b8; -} - -/* ---------------------------------------------------------------------- */ -void send_frame_to_java(unsigned char *bp, unsigned int len); - -static void ax25_disp_packet(struct demod_state *s, unsigned char *bp, unsigned int len) -{ - if (!bp || len < 10) - return; - if (!check_crc_ccitt(bp, len)) - return; - - len -= 2; - send_frame_to_java(bp, len); -} - -void hdlc_init(struct demod_state *s) -{ - memset(&s->l2.hdlc, 0, sizeof(s->l2.hdlc)); -} - -void hdlc_rxbit(struct demod_state *s, int bit) -{ - s->l2.hdlc.rxbitstream <<= 1; - s->l2.hdlc.rxbitstream |= !!bit; - if ((s->l2.hdlc.rxbitstream & 0xff) == 0x7e) { - if (s->l2.hdlc.rxstate && (s->l2.hdlc.rxptr - s->l2.hdlc.rxbuf) > 2) - ax25_disp_packet(s, s->l2.hdlc.rxbuf, s->l2.hdlc.rxptr - s->l2.hdlc.rxbuf); - s->l2.hdlc.rxstate = 1; - s->l2.hdlc.rxptr = s->l2.hdlc.rxbuf; - s->l2.hdlc.rxbitbuf = 0x80; - return; - } - if ((s->l2.hdlc.rxbitstream & 0x7f) == 0x7f) { - s->l2.hdlc.rxstate = 0; - return; - } - if (!s->l2.hdlc.rxstate) - return; - if ((s->l2.hdlc.rxbitstream & 0x3f) == 0x3e) /* stuffed bit */ - return; - if (s->l2.hdlc.rxbitstream & 1) - s->l2.hdlc.rxbitbuf |= 0x100; - if (s->l2.hdlc.rxbitbuf & 1) { - if (s->l2.hdlc.rxptr >= s->l2.hdlc.rxbuf+sizeof(s->l2.hdlc.rxbuf)) { - s->l2.hdlc.rxstate = 0; - __android_log_print(ANDROID_LOG_ERROR,"Multimon","Error: packet size too large"); - return; - } - *s->l2.hdlc.rxptr++ = s->l2.hdlc.rxbitbuf >> 1; - s->l2.hdlc.rxbitbuf = 0x80; - return; - } - s->l2.hdlc.rxbitbuf >>= 1; -} - diff --git a/aprs-android/src/main/cpp/multimon.c b/aprs-android/src/main/cpp/multimon.c deleted file mode 100644 index e0b7b693..00000000 --- a/aprs-android/src/main/cpp/multimon.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "multimon.h" - -static const struct demod_param *dem[] = { &demod_afsk1200 }; - -#define NUMDEMOD (sizeof(dem)/sizeof(dem[0])) - -static struct demod_state dem_st[NUMDEMOD]; - -static void process_buffer(float *buf, unsigned int len) -{ - dem[0]->demod(dem_st+0, buf, len); -} - - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) -{ - return JNI_VERSION_1_6; -} - - -void Java_com_inkapplications_ack_data_Multimon_init(JNIEnv *env, jobject object) { - static int sample_rate = -1; - unsigned int i; - unsigned int overlap = 0; - - for (i = 0; i < NUMDEMOD; i++) { - memset(dem_st+i, 0, sizeof(dem_st[i])); - dem_st[i].dem_par = dem[i]; - if (dem[i]->init) - dem[i]->init(dem_st+i); - if (sample_rate == -1) - sample_rate = dem[i]->samplerate; - else if (sample_rate != dem[i]->samplerate) { - exit(3); - } - if (dem[i]->overlap > overlap) - overlap = dem[i]->overlap; - } -} - - -JNIEnv *env_global; -jobject *abp_global; - -void Java_com_inkapplications_ack_data_Multimon_process(JNIEnv *env, jobject object, jfloatArray fbuf, jint length) { - env_global = env; - abp_global = object; - jfloat *jfbuf = (*env)->GetFloatArrayElements(env, fbuf, 0); - process_buffer(jfbuf, length); - (*env)->ReleaseFloatArrayElements(env, fbuf, jfbuf, 0); -} - -void send_frame_to_java(unsigned char *bp, unsigned int len) { - jbyteArray data = (*env_global)->NewByteArray(env_global, len); - if (data == NULL) { - __android_log_print(ANDROID_LOG_ERROR,"Multimon","OOM on allocating data buffer"); - return; - } - (*env_global)->SetByteArrayRegion(env_global, data, 0, len, (jbyte*)bp); - - jclass cls = (*env_global)->GetObjectClass(env_global, abp_global); - jmethodID callback = (*env_global)->GetMethodID(env_global, cls, "callback", "([B)V"); - (*env_global)->CallVoidMethod(env_global, abp_global, callback, data); - -} diff --git a/aprs-android/src/main/cpp/multimon.h b/aprs-android/src/main/cpp/multimon.h deleted file mode 100644 index db6172db..00000000 --- a/aprs-android/src/main/cpp/multimon.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * multimon.h -- Monitor for many different modulation formats - * - * Copyright (C) 1996 - * Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _MULTIMON_H -#define _MULTIMON_H - -#include - -struct demod_state { - const struct demod_param *dem_par; - union { - struct l2_state_hdlc { - unsigned char rxbuf[512]; - unsigned char *rxptr; - unsigned int rxstate; - unsigned int rxbitstream; - unsigned int rxbitbuf; - } hdlc; - - struct l2_state_pocsag { - unsigned long rx_data; - struct l2_pocsag_rx { - unsigned char rx_sync; - unsigned char rx_word; - unsigned char rx_bit; - char func; - unsigned long adr; - unsigned char buffer[128]; - unsigned int numnibbles; - } rx[2]; - } pocsag; - } l2; - union { - struct l1_state_afsk12 { - unsigned int dcd_shreg; - unsigned int sphase; - unsigned int lasts; - unsigned int subsamp; - } afsk12; - } l1; -}; - -struct demod_param { - const char *name; - unsigned int samplerate; - unsigned int overlap; - void (*init)(struct demod_state *s); - void (*demod)(struct demod_state *s, float *buffer, int length); -}; - - -extern const struct demod_param demod_afsk1200; - -void hdlc_init(struct demod_state *s); -void hdlc_rxbit(struct demod_state *s, int bit); - -#endif /* _MULTIMON_H */ diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/AfskModulationConfiguration.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/AfskModulationConfiguration.kt deleted file mode 100644 index ee3f67f4..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/AfskModulationConfiguration.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.inkapplications.ack.data - -import inkapplications.spondee.scalar.Percentage -import inkapplications.spondee.scalar.percent -import kotlin.time.Duration -import kotlin.time.Duration.Companion.milliseconds - -data class AfskModulationConfiguration( - val preamble: Duration = 100.milliseconds, - val volume: Percentage = 50.percent, -) diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidAfskModulator.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidAfskModulator.kt deleted file mode 100644 index 1f93e14c..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidAfskModulator.kt +++ /dev/null @@ -1,147 +0,0 @@ -package com.inkapplications.ack.data - -/* -The following file is based off of jsoundmodem. -It has been modified extensively, ported to kotlin, and is redistributed under -the GNU General Public License v2.0. -The original source code was obtained from https://github.com/nogy/jsoundmodem. - */ -import android.media.AudioAttributes -import android.media.AudioFormat -import android.media.AudioManager -import android.media.AudioTrack -import android.os.Build -import android.os.Process -import inkapplications.spondee.scalar.Percentage -import inkapplications.spondee.structure.toFloat -import kotlinx.coroutines.* -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine -import kotlin.experimental.or -import kotlin.math.PI -import kotlin.math.cos -import kotlin.math.roundToInt -import kotlin.time.Duration - -private const val FREQ_LOW = 1200 -private const val FREQ_HIGH = 2200 -private const val BPS = 1200 -private const val SAMPLE_RATE = 22050 -private const val PCM_BITS = 16 - -internal class AndroidAfskModulator { - private val trackScope = CoroutineScope(SupervisorJob() + newSingleThreadContext("AudioTrack")) - - fun modulate(data: ByteArray, length: Duration, volume: Percentage) { - val crc = crc16(data) - val (frame, frameLength) = frame(data + crc.first + crc.second, (length.inWholeMilliseconds * BPS/8/1000).toInt()) - val pcmData = ShortArray(frameLength.times(SAMPLE_RATE).div(BPS)) - trackScope.launch { - Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO) - - var lastTone = FREQ_LOW - var cosPos = 0.0 - for (i in 0 until frameLength) { - if (frame[i/8].toInt().and(1.shl(i % 8)) == 0) { - lastTone = if (lastTone == FREQ_LOW) FREQ_HIGH else FREQ_LOW - } - for (t in 0 until SAMPLE_RATE / BPS) { - pcmData[i.times(SAMPLE_RATE / BPS).plus(t)] = cos(cosPos).times(1.shl(PCM_BITS-1) - 1).roundToInt().toShort() - cosPos += 2 * PI * lastTone / SAMPLE_RATE - if (cosPos > 2 * PI) { - cosPos -= 2 * PI - } - } - } - - send(pcmData, volume) - } - } - - private suspend fun send(pcmData: ShortArray, volume: Percentage) { - val track = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - AudioTrack( - AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build(), - AudioFormat.Builder().setEncoding(AudioFormat.ENCODING_PCM_16BIT).setChannelMask(AudioFormat.CHANNEL_OUT_MONO).setSampleRate(SAMPLE_RATE).build(), - pcmData.size * 2, - AudioTrack.MODE_STATIC, - AudioManager.AUDIO_SESSION_ID_GENERATE, - ) - } else AudioTrack( - AudioManager.STREAM_RING, - SAMPLE_RATE, - AudioFormat.CHANNEL_OUT_MONO, - AudioFormat.ENCODING_PCM_16BIT, - pcmData.size * 2, - AudioTrack.MODE_STATIC, - ) - - suspendCoroutine { continuation -> - track.setPlaybackPositionUpdateListener(object: AudioTrack.OnPlaybackPositionUpdateListener { - override fun onMarkerReached(track: AudioTrack) { - track.release() - continuation.resume(Unit) - } - override fun onPeriodicNotification(track: AudioTrack?) = Unit - }) - track.notificationMarkerPosition = pcmData.size - val volume = AudioTrack.getMaxVolume() * volume.toDecimal().toFloat() - track.setStereoVolume(volume, volume) - track.write(pcmData, 0, pcmData.size) - runBlocking { - // Without this delay the audiotrack will automatically pause shortly after playing. I hate this, but cannot figure out an alternative. - delay(500) - } - track.play() - } - } - - private fun crc16(data: ByteArray): Pair { - return data.fold(0xFFFF) { crc, byte -> - (0 until 8).fold(crc) { bitCrc, position -> - if (bitCrc.and(1) != byte.toInt().and(1.shl(position)).shr(position)) { - bitCrc.shr(1).xor(0x8408).and(0xFFFF) - } else { - bitCrc.shr(1) - } - } - } - .xor(0xFFFF).let { - Pair( - it.and(0xFF).minus(256).toByte(), - it.and(0xFF00).shr(8).minus(256).toByte(), - ) - } - } - - private fun frame(data: ByteArray, length: Int): Pair { - val out = ByteArray(data.size + length + Math.ceil(data.size / 5.0).toInt() + 1) - for (i in 0 until length ) { - out[i] = 0x7e - } - - var ones = 0 - var k = length*8 - for (i in 0 until data.size*8) { - if (data[i / 8].toInt() and (1 shl i % 8) > 0) { - out[k / 8] = out[k / 8] or if (1 shl k % 8 > 127) ((1 shl k % 8) - 256).toByte() else (1 shl k % 8).toByte() - if (ones++ == 4) { - k++ - ones = 0 - } - } else { - ones = 0 - } - k++ - } - - for (i in 0 until 8) { - if (0x7e and (1 shl i % 8) > 0) { - out[k / 8] = out[k / 8] or if (1 shl k % 8 > 127) ((1 shl k % 8) - 256).toByte() else (1 shl k % 8).toByte() - } - k++ - } - - return out to k+1 - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidAprsModule.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidAprsModule.kt deleted file mode 100644 index 47735154..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidAprsModule.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.inkapplications.ack.data - -import android.content.Context -import app.cash.sqldelight.driver.android.AndroidSqliteDriver -import com.inkapplications.ack.client.AprsClientModule -import com.inkapplications.ack.codec.Ack -import com.inkapplications.ack.codec.AprsCodec -import com.inkapplications.ack.data.adapters.CallsignAdapter -import com.inkapplications.ack.data.adapters.CaptureIdColumnAdapter -import com.inkapplications.ack.data.adapters.InstantAdapter -import com.inkapplications.ack.data.adapters.PacketOriginAdapter -import com.inkapplications.ack.data.drivers.* -import com.inkapplications.android.extensions.bluetooth.BluetoothDeviceAccess -import dagger.Module -import dagger.Provides -import dagger.Reusable -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.datetime.Clock -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -object AndroidAprsModule { - @Provides - @Reusable - fun aprsCodec( - logger: KimchiLogger, - ): AprsCodec { - val logAdapter = object: KimchiLogger by logger { - override fun debug(message: String, cause: Throwable?) = Unit - override fun debug(cause: Throwable?, message: () -> String) = Unit - override fun trace(message: String, cause: Throwable?) = Unit - override fun trace(cause: Throwable?, message: () -> String) = Unit - } - return Ack(logAdapter).defaultParser() - } - - @Provides - @Reusable - fun packetStorage( - context: Context, - codec: AprsCodec, - clock: Clock, - logger: KimchiLogger, - ): PacketStorage { - val driver = AndroidSqliteDriver(PacketDatabase.Schema, context, "packets.db") - val database = PacketDatabase( - driver = driver, - CapturedPacketEntity.Adapter( - idAdapter = CaptureIdColumnAdapter, - timestampAdapter = InstantAdapter, - packet_originAdapter = PacketOriginAdapter, - source_callsignAdapter = CallsignAdapter, - addressee_callsignAdapter = CallsignAdapter, - ), - ) - return DaoPacketStorage(database.capturedPacketEntityQueries, codec, clock, logger) - } - - @Provides - @Singleton - fun drivers( - codec: AprsCodec, - logger: KimchiLogger, - androidLocationProvider: AndroidLocationProvider, - driverSettings: DriverSettingsProvider, - packetStorage: PacketStorage, - bluetoothAccess: BluetoothDeviceAccess, - ): PacketDrivers { - val audioCapture = AudioDataCapture(logger) - val audioProcessor = AudioDataProcessor(audioCapture) - val backgroundScope = CoroutineScope(Dispatchers.Default) - - val internet = InternetDriver( - aprsCodec = codec, - packetStorage = packetStorage, - client = AprsClientModule.createDataClient(), - locationProvider = androidLocationProvider, - settings = driverSettings, - runScope = backgroundScope, - logger = logger, - ) - val afsk = AfskDriver( - aprsCodec = codec, - packetStorage = packetStorage, - audioProcessor = audioProcessor, - modulator = AndroidAfskModulator(), - settings = driverSettings, - runScope = backgroundScope, - logger = logger, - ) - - val tncDriver = TncDriver( - bluetoothAccess = bluetoothAccess, - packetStorage = packetStorage, - ack = codec, - runScope = backgroundScope, - logger = logger, - ) - - return PacketDrivers( - internetDriver = internet, - afskDriver = afsk, - tncDriver = tncDriver, - ) - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidLocationProvider.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidLocationProvider.kt deleted file mode 100644 index 4e456c10..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/AndroidLocationProvider.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.inkapplications.ack.data - -import android.Manifest -import android.location.Location -import android.location.LocationListener -import android.location.LocationManager -import android.os.Bundle -import androidx.annotation.RequiresPermission -import dagger.Reusable -import inkapplications.spondee.measure.metric.meters -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.spatial.latitude -import inkapplications.spondee.spatial.longitude -import inkapplications.spondee.structure.Kilo -import inkapplications.spondee.structure.scale -import inkapplications.spondee.structure.toFloat -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.channels.trySendBlocking -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.withContext -import javax.inject.Inject -import kotlin.time.Duration.Companion.minutes - -@Reusable -class AndroidLocationProvider @Inject constructor( - private val locationManager: LocationManager, - private val logger: KimchiLogger, -) { - private val MIN_TIME = 5.minutes.inWholeMilliseconds - private val MIN_DISTANCE = 1000.scale(Kilo).meters.toFloat() - - @RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION) - private val androidLocationFlow: Flow = callbackFlow { - val listener = object : LocationListener { - override fun onLocationChanged(location: Location) { - logger.debug("Location Changed: $location") - trySendBlocking(location) - } - - override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) { - logger.debug("Location Status Changed: $p0 $p1") - } - - override fun onProviderEnabled(p0: String) { - logger.debug("Location Provider Enabled: $p0") - } - - override fun onProviderDisabled(p0: String) { - logger.debug("Location Provider Disabled: $p0") - } - } - - withContext(Dispatchers.Main) { - locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER) - ?.run { send(this) } - - locationManager.requestLocationUpdates( - LocationManager.GPS_PROVIDER, - MIN_TIME, - MIN_DISTANCE, - listener, - ) - } - awaitClose { - locationManager.removeUpdates(listener) - } - } - - @RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION) - val location: Flow = androidLocationFlow - .distinctUntilChanged { a, b -> - a.distanceTo(b) < MIN_DISTANCE - } - .map { location -> - GeoCoordinates(location.latitude.latitude, location.longitude.longitude) - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/AudioDataCapture.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/AudioDataCapture.kt deleted file mode 100644 index 9c2d84aa..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/AudioDataCapture.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.inkapplications.ack.data - -import android.media.AudioFormat -import android.media.AudioRecord -import android.media.MediaRecorder -import android.os.Process -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.BroadcastChannel -import kotlinx.coroutines.channels.ReceiveChannel - -private const val BUFFER_SIZE = 16 -private const val SAMPLE_RATE = 22050 -private const val AUDIO_BUFFER_SIZE = 16384 -private const val PROCESS_BUFFER_SIZE = 8192 - -/** - * Capture buffered audio data on a separate prioritized thread. - * - * Data from this capture can be processed by consuming the [audioData] channel. - */ -internal class AudioDataCapture( - private val logger: KimchiLogger -) { - private val recorder: AudioRecord by lazy { - AudioRecord( - MediaRecorder.AudioSource.MIC, - SAMPLE_RATE, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT, - AUDIO_BUFFER_SIZE - ) - } - private val captureScope = CoroutineScope(SupervisorJob() + newSingleThreadContext("AudioCapture")) - private val buffers = Array(BUFFER_SIZE) { ShortArray(PROCESS_BUFFER_SIZE) } - private val audioChannel = BroadcastChannel(BUFFER_SIZE) - - /** - * Outputs buffered arrays of audio data. - * - * Note: The arrays from this channel are recycled and should not be stored - * directly. This channel has a limited capacity of [BUFFER_SIZE] arrays. - */ - val audioData: ReceiveChannel get() = audioChannel.openSubscription() - - /** - * Start capturing audio data. - * - * This will suspend until [cancel] is called. - */ - fun capture() { - logger.debug("Audio capture started") - captureScope.launch { - Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO) - recorder.startRecording() - - var bufferIndex = 0 - while (recorder.recordingState != AudioRecord.RECORDSTATE_STOPPED) { - val buffer = buffers[bufferIndex] - recorder.read(buffer, 0, buffer.size) - bufferIndex = if (bufferIndex == buffers.size - 1) 0 else bufferIndex + 1 - audioChannel.trySend(buffer) - } - } - } - - /** - * Stop capturing audio data. - */ - fun cancel() { - logger.debug("Audio capture stopped") - recorder.stop() - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/AudioDataProcessor.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/AudioDataProcessor.kt deleted file mode 100644 index 3415446e..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/AudioDataProcessor.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.inkapplications.ack.data - -import inkapplications.spondee.scalar.Percentage -import inkapplications.spondee.scalar.decimalPercentage -import kotlinx.coroutines.channels.consumeEach -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.map -import kotlin.math.abs -import kotlin.math.absoluteValue - -private const val overlap = 18 - -internal class AudioDataProcessor( - private val audioIn: AudioDataCapture -) { - private val multimon by lazy { - Multimon.apply { - init() - } - } - - private val fbuf = FloatArray(16384) - private var fbuf_cnt = 0 - - val data = callbackFlow { - multimon.onReceive = { trySend(it) } - - audioIn.capture() - - invokeOnClose { - audioIn.cancel() - peak.value = null - } - audioIn.audioData.consumeEach { decode(it) } - } - - private val peak = MutableStateFlow(null) - val volume: Flow = peak.map { - it?.toDouble()?.absoluteValue?.div(Short.MAX_VALUE)?.decimalPercentage - } - - private fun decode(audioData: ShortArray) { - peak.value = audioData.maxOf { abs(it.toInt()) }.toShort() - for (i in audioData.indices) { - fbuf[fbuf_cnt++] = audioData[i] * (1.0f / 32768.0f) - } - - if (fbuf_cnt > overlap) { - multimon.process(fbuf, fbuf_cnt - overlap) - System.arraycopy(fbuf, fbuf_cnt - overlap, fbuf, 0, overlap) - fbuf_cnt = overlap - } - } -} - diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/CaptureId.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/CaptureId.kt deleted file mode 100644 index 878359c7..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/CaptureId.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.inkapplications.ack.data - -@JvmInline -value class CaptureId(val value: Long) diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/CapturedPacket.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/CapturedPacket.kt deleted file mode 100644 index e8fe983c..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/CapturedPacket.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.data - -import com.inkapplications.ack.structures.AprsPacket -import kotlinx.datetime.Instant - -data class CapturedPacket( - val id: CaptureId, - val received: Instant, - val parsed: AprsPacket, - val origin: PacketOrigin, - val raw: ByteArray, -) diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/ConnectionConfiguration.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/ConnectionConfiguration.kt deleted file mode 100644 index 6a2d86ba..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/ConnectionConfiguration.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.inkapplications.ack.data - -import com.inkapplications.ack.client.Credentials -import com.inkapplications.ack.structures.station.StationAddress -import inkapplications.spondee.measure.Length -import inkapplications.spondee.measure.us.miles - -const val DEFAULT_CONNECTION_SERVER = "rotate.aprs2.net" -const val DEFAULT_CONNECTION_PORT = 14580 -const val DEFAULT_SEARCH_RADIUS_MILES = 100 - -data class ConnectionConfiguration( - val address: StationAddress, - val passcode: Int = -1, - val host: String = DEFAULT_CONNECTION_SERVER, - val port: Int = DEFAULT_CONNECTION_PORT, - val searchRadius: Length = DEFAULT_SEARCH_RADIUS_MILES.miles, -) { - val credentials = Credentials(address.toString(), passcode) -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/DaoPacketStorage.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/DaoPacketStorage.kt deleted file mode 100644 index 17dc71b8..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/DaoPacketStorage.kt +++ /dev/null @@ -1,135 +0,0 @@ -package com.inkapplications.ack.data - -import app.cash.sqldelight.Query -import app.cash.sqldelight.coroutines.asFlow -import app.cash.sqldelight.coroutines.mapToList -import app.cash.sqldelight.coroutines.mapToOne -import app.cash.sqldelight.coroutines.mapToOneOrNull -import com.inkapplications.ack.codec.AprsCodec -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.station.Callsign -import com.inkapplications.coroutines.filterItemNotNull -import com.inkapplications.coroutines.mapItems -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import kotlinx.datetime.Clock -import kotlin.reflect.KClass - -internal class DaoPacketStorage( - private val packetDao: CapturedPacketEntityQueries, - private val codec: AprsCodec, - private val clock: Clock, - private val logger: KimchiLogger, -): PacketStorage { - private fun Query.toListFlow() = asFlow().mapToList(Dispatchers.IO) - private fun Query.toSingleFlow() = asFlow().mapToOne(Dispatchers.IO) - private fun Query.toMaybeFlow() = asFlow().mapToOneOrNull(Dispatchers.IO) - - override fun findRecent(count: Long): Flow> { - return packetDao.findRecent(count) - .toListFlow() - .map { entities -> - entities.mapNotNull { createCapturedPacket(it, fromEntityOrNull(it)) } - } - } - - override fun findById(id: CaptureId): Flow { - return packetDao.findById(id) - .toMaybeFlow() - .map { it?.let { createCapturedPacket(it, fromEntityOrNull(it)) } } - } - - override fun findLatestByConversation(callsign: Callsign): Flow> { - return packetDao.findLatestConversationMessages(callsign) - .toListFlow() - .mapItems { createCapturedPacket(it, fromEntityOrNull(it)) } - .filterItemNotNull() - } - - override fun findConversation(addressee: Callsign, callsign: Callsign): Flow> { - return packetDao.findConversation(addressee, callsign) - .toListFlow() - .mapItems { createCapturedPacket(it, fromEntityOrNull(it)) } - .filterItemNotNull() - } - - override fun count(): Flow { - return packetDao.countAll().toSingleFlow() - } - - override fun countStations(): Flow { - return packetDao.countSources().toSingleFlow() - } - - override fun findByStationComments(limit: Long?): Flow> { - return packetDao.findStationComments(limit ?: -1L) - .toListFlow() - .mapItems { createCapturedPacket(it, fromEntityOrNull(it)) } - .filterItemNotNull() - } - - override fun findMostRecentByType(type: KClass): Flow { - return packetDao.findMostRecentByType(type.simpleName!!) - .toMaybeFlow() - .map { if (it == null) null else createCapturedPacket(it, fromEntityOrNull(it)) } - } - - override fun findBySource(callsign: Callsign, limit: Long?): Flow> { - return packetDao.findBySourceCallsign(callsign, limit ?: -1) - .toListFlow() - .mapItems { createCapturedPacket(it, fromEntityOrNull(it)) } - .filterItemNotNull() - } - - override suspend fun save(data: ByteArray, packet: AprsPacket, origin: PacketOrigin): CapturedPacket { - val now = clock.now() - return packetDao.transactionWithResult { - packetDao.addPacket( - timestamp = now, - raw_data = data, - packet_origin = origin, - source_callsign = packet.route.source.callsign, - addressee_callsign = (packet.data as? PacketData.Message)?.addressee?.callsign, - data_type = packet.data.javaClass.simpleName, - comment_field = packet.data.commentLikeField, - ) - - packetDao.lastId() - }.executeAsOne().let { - CapturedPacket( - id = CaptureId(it), - received = now, - parsed = packet, - origin = origin, - raw = data, - ) - } - } - - private fun fromEntityOrNull(data: CapturedPacketEntity): AprsPacket? { - try { - return when (data.packet_origin) { - PacketOrigin.Ax25, PacketOrigin.Tnc -> codec.fromAx25(data.raw_data) - PacketOrigin.AprsIs, PacketOrigin.Local -> codec.fromString(data.raw_data.toString(Charsets.UTF_8)) - } - } catch (error: Throwable) { - logger.warn("Unable to parse packet", error) - return null - } - } - - private fun createCapturedPacket(entity: CapturedPacketEntity, parsed: AprsPacket?): CapturedPacket? { - parsed ?: return null - - return CapturedPacket( - id = entity.id, - received = entity.timestamp, - parsed = parsed, - origin = entity.packet_origin, - raw = entity.raw_data, - ) - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/Multimon.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/Multimon.kt deleted file mode 100644 index 17341eab..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/Multimon.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.inkapplications.ack.data - -/** - * API for interfacing with the JNI Multimon code. - */ -internal object Multimon { - /** - * Invoked when data is parsed from processing. - */ - var onReceive: (ByteArray) -> Unit = {} - - init { - System.loadLibrary("multimon") - } - - /** - * Initialize the Multimon library. - */ - external fun init() - - /** - * Process an array of audio data. - */ - external fun process(buffer: FloatArray, length: Int) - - private fun callback(data: ByteArray) { - onReceive(data) - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/PacketOrigin.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/PacketOrigin.kt deleted file mode 100644 index f265cd97..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/PacketOrigin.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.inkapplications.ack.data - -enum class PacketOrigin { - Ax25, - AprsIs, - Tnc, - Local, -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/PacketStorage.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/PacketStorage.kt deleted file mode 100644 index cd768e7d..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/PacketStorage.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.inkapplications.ack.data - -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.PacketData -import com.inkapplications.ack.structures.station.Callsign -import kotlinx.coroutines.flow.Flow -import kotlin.reflect.KClass - -/** - * Provides query access to packets that have been captured and stored. - */ -interface PacketStorage { - /** - * Find a limited number of packets by recency. - * - * @param count The max limit of packets to find. - */ - fun findRecent(count: Long): Flow> - - /** - * Find the latest packet in every conversation. - * - * @param callsign The callsign to find conversations with. - */ - fun findLatestByConversation(callsign: Callsign): Flow> - - /** - * Find all packets in a specific conversation. - * - * @param addressee The external callsign to look up conversations with. - * @param callsign The user's callsign to look up conversations with. - */ - fun findConversation(addressee: Callsign, callsign: Callsign): Flow> - - /** - * Find a specific packet by its id - * - * @param id The locally generated ID to find a packet by - */ - fun findById(id: CaptureId): Flow - - /** - * Find the quantity of packets saved. - */ - fun count(): Flow - - /** - * Find the number of distinct stations in the packets received. - */ - fun countStations(): Flow - - /** - * Find packets with comments that appear to be broadcasting a station frequency. - */ - fun findByStationComments(limit: Long? = null): Flow> - - /** - * Find the most recent packet received of a specific data type. - * - * @param type The data type of the packet to find. - */ - fun findMostRecentByType(type: KClass): Flow - - /** - * Find all of the packets received from a callsign. - * - * @param callsign The source/origin callsign to find packets of. - */ - fun findBySource(callsign: Callsign, limit: Long? = null): Flow> - - /** - * Store a packet locally. - * - * @param data The raw data of the packet received. - * @param packet The parsed version of the packet data, - * @param origin The origin of the packet data. - */ - suspend fun save(data: ByteArray, packet: AprsPacket, origin: PacketOrigin): CapturedPacket -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/Packets.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/Packets.kt deleted file mode 100644 index 6eb78e52..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/Packets.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.inkapplications.ack.data - -import com.inkapplications.ack.structures.PacketData - -/** - * Extract any comment-like field from a packet, if available. - */ -val PacketData.commentLikeField: String? get() = when(this) { - is PacketData.ItemReport -> comment - is PacketData.Message -> message - is PacketData.ObjectReport -> comment - is PacketData.Position -> comment - is PacketData.StatusReport -> status - is PacketData.TelemetryReport -> comment - is PacketData.CapabilityReport, - is PacketData.Unknown, - is PacketData.Weather -> null -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/CallsignAdapter.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/CallsignAdapter.kt deleted file mode 100644 index b0a5cb43..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/CallsignAdapter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.data.adapters - -import app.cash.sqldelight.ColumnAdapter -import com.inkapplications.ack.structures.station.Callsign - -/** - * SQLDelight ColumnAdapter for storing a Callsign as its canonical string. - */ -internal object CallsignAdapter: ColumnAdapter { - override fun decode(databaseValue: String): Callsign = Callsign(databaseValue) - override fun encode(value: Callsign): String = value.canonical.uppercase() -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/CaptureIdColumnAdapter.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/CaptureIdColumnAdapter.kt deleted file mode 100644 index 78c07699..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/CaptureIdColumnAdapter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.data.adapters - -import app.cash.sqldelight.ColumnAdapter -import com.inkapplications.ack.data.CaptureId - -/** - * SQLDelight ColumnAdapter for storing a CaptureId as a long. - */ -internal object CaptureIdColumnAdapter: ColumnAdapter { - override fun decode(databaseValue: Long): CaptureId = CaptureId(databaseValue) - override fun encode(value: CaptureId): Long = value.value -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/InstantAdapter.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/InstantAdapter.kt deleted file mode 100644 index 15333a58..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/InstantAdapter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.data.adapters - -import app.cash.sqldelight.ColumnAdapter -import kotlinx.datetime.Instant - -/** - * SQLDelight ColumnAdapter for storing an Instant as a long in epoch milliseconds. - */ -internal object InstantAdapter: ColumnAdapter { - override fun decode(databaseValue: Long): Instant = Instant.fromEpochMilliseconds(databaseValue) - override fun encode(value: Instant): Long = value.toEpochMilliseconds() -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/PacketOriginAdapter.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/PacketOriginAdapter.kt deleted file mode 100644 index 75f184eb..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/adapters/PacketOriginAdapter.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.inkapplications.ack.data.adapters - -import app.cash.sqldelight.ColumnAdapter -import com.inkapplications.ack.data.PacketOrigin - -/** - * SQLDelight ColumnAdapter for storing a PacketSource as its string name. - */ -internal object PacketOriginAdapter: ColumnAdapter { - override fun decode(databaseValue: String): PacketOrigin = PacketOrigin.valueOf(databaseValue) - override fun encode(value: PacketOrigin): String = value.name -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AfskDriver.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AfskDriver.kt deleted file mode 100644 index cba97789..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AfskDriver.kt +++ /dev/null @@ -1,115 +0,0 @@ -package com.inkapplications.ack.data.drivers - -import android.Manifest -import android.os.Build -import com.inkapplications.ack.codec.AprsCodec -import com.inkapplications.ack.data.* -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.EncodingConfig -import com.inkapplications.coroutines.combinePair -import inkapplications.spondee.scalar.toWholePercentage -import inkapplications.spondee.structure.roundToInt -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.launch - -class AfskDriver internal constructor( - private val aprsCodec: AprsCodec, - private val packetStorage: PacketStorage, - private val audioProcessor: AudioDataProcessor, - private val modulator: AndroidAfskModulator, - private val settings: DriverSettingsProvider, - private val runScope: CoroutineScope, - private val logger: KimchiLogger, -): PacketDriver, AudioConnectionMonitor { - private val runJob = MutableStateFlow(null) - override val connectionState: Flow = runJob.map { job -> - when { - job?.isActive == true -> DriverConnectionState.Connected - else -> DriverConnectionState.Disconnected - } - } - override val incoming = MutableSharedFlow() - override val receivePermissions: Set = when { - Build.VERSION.SDK_INT >= 34 -> setOf( - Manifest.permission.RECORD_AUDIO, - Manifest.permission.FOREGROUND_SERVICE_MICROPHONE, - // TODO: This could be simplified/removed if we create separate services for transmit and receive. - // Leaving for now, since all the other drivers require it anyway. - Manifest.permission.FOREGROUND_SERVICE_LOCATION, - Manifest.permission.POST_NOTIFICATIONS, - ) - Build.VERSION.SDK_INT >= 33 -> setOf( - Manifest.permission.RECORD_AUDIO, - Manifest.permission.POST_NOTIFICATIONS, - ) - else -> setOf(Manifest.permission.RECORD_AUDIO) - } - override val transmitPermissions: Set = when { - Build.VERSION.SDK_INT >= 33 -> setOf( - Manifest.permission.POST_NOTIFICATIONS - ) - else -> emptySet() - } - override val volume = audioProcessor.volume - private val transmitQueue = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) - - override suspend fun transmitPacket(packet: AprsPacket, encodingConfig: EncodingConfig) { - val data = try { - aprsCodec.toAx25(packet, encodingConfig) - } catch (encodingError: Throwable) { - logger.error("Unable to encode packet for AX25", encodingError) - return - } - - transmitQueue.emit(data) - } - - override suspend fun connect() { - logger.debug("Connecting Audio Packet Capture") - - runJob.updateAndGet { priorJob -> - priorJob?.takeIf { it.isActive } ?: launchNewJob() - } - } - - private fun launchNewJob(): Job { - logger.debug("Launching new job for Audio Packet Capture") - return runScope.launch { - launch { - audioProcessor.data - .mapNotNull { captureAx25Packet(it) } - .onEach { logger.debug("APRS Packet Parsed: $it") } - .collect { incoming.emit(it) } - } - launch { - settings.afskConfiguration.combinePair(transmitQueue) - .collect { (config, data) -> - logger.info("Modulating ${data.size} bytes with a ${config.preamble} preamble at ${config.volume.toWholePercentage().roundToInt()}% volume") - modulator.modulate(data, config.preamble, config.volume) - } - } - } - } - - override suspend fun disconnect() { - logger.debug("Disconnecting Audio Packet Capture") - runJob.value?.cancelAndJoin() - runJob.value = null - logger.debug("Audio Packet Capture Disconnected") - } - - private suspend fun captureAx25Packet(data: ByteArray): CapturedPacket? { - val parsed = try { - aprsCodec.fromAx25(data) - } catch (parsingError: Throwable) { - logger.warn("Unable to parse packet", parsingError) - return null - } - return packetStorage.save(data, parsed, PacketOrigin.Ax25) - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AudioConnectionMonitor.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AudioConnectionMonitor.kt deleted file mode 100644 index a9f43085..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AudioConnectionMonitor.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.inkapplications.ack.data.drivers - -import inkapplications.spondee.scalar.Percentage -import kotlinx.coroutines.flow.Flow - -interface AudioConnectionMonitor { - val volume: Flow -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/ConnectTncData.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/ConnectTncData.kt deleted file mode 100644 index 7dccb687..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/ConnectTncData.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.inkapplications.ack.data.drivers - -import com.inkapplications.android.extensions.bluetooth.BluetoothDeviceData - -/** - * TNC Connection information. - * - * This represents the current state of the TNC connection driver. - */ -data class ConnectTncData( - /** - * List of bluetooth devices discovered that may be TNC devices. - */ - var discoveredDevices: List, - - /** - * Device that is currently being connected to. - */ - var connectingDevice: BluetoothDeviceData?, - - /** - * Device that is currently connected to. - */ - var connectedDevice: BluetoothDeviceData?, -) diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/DriverConnectionState.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/DriverConnectionState.kt deleted file mode 100644 index 71f563ba..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/DriverConnectionState.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.inkapplications.ack.data.drivers - -enum class DriverConnectionState { - Connecting, - Connected, - Disconnecting, - Disconnected, -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/DriverSettingsProvider.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/DriverSettingsProvider.kt deleted file mode 100644 index 11bdd8ee..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/DriverSettingsProvider.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.inkapplications.ack.data.drivers - -import com.inkapplications.ack.data.AfskModulationConfiguration -import com.inkapplications.ack.data.ConnectionConfiguration -import kotlinx.coroutines.flow.Flow - -interface DriverSettingsProvider { - val internetServiceConfiguration: Flow - val afskConfiguration: Flow -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/InternetDriver.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/InternetDriver.kt deleted file mode 100644 index 579a6857..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/InternetDriver.kt +++ /dev/null @@ -1,143 +0,0 @@ -package com.inkapplications.ack.data.drivers - -import android.Manifest -import android.os.Build -import com.inkapplications.ack.client.AprsDataClient -import com.inkapplications.ack.codec.AprsCodec -import com.inkapplications.ack.data.* -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.EncodingConfig -import com.inkapplications.coroutines.combinePair -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.structure.Kilo -import inkapplications.spondee.structure.value -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.channels.consumeEach -import kotlinx.coroutines.flow.* -import kotlin.math.pow - -class InternetDriver internal constructor( - private val aprsCodec: AprsCodec, - private val packetStorage: PacketStorage, - private val client: AprsDataClient, - private val locationProvider: AndroidLocationProvider, - private val settings: DriverSettingsProvider, - private val runScope: CoroutineScope, - private val logger: KimchiLogger, -): PacketDriver { - private val runJob = MutableStateFlow(null) - private val clientConnectionState = MutableStateFlow(DriverConnectionState.Disconnected) - override val connectionState: Flow = clientConnectionState - override val incoming = MutableSharedFlow() - override val receivePermissions: Set = when { - Build.VERSION.SDK_INT >= 34 -> setOf( - Manifest.permission.POST_NOTIFICATIONS, - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.FOREGROUND_SERVICE_LOCATION, - ) - Build.VERSION.SDK_INT >= 33 -> setOf( - Manifest.permission.POST_NOTIFICATIONS, - Manifest.permission.ACCESS_FINE_LOCATION, - ) - else -> setOf(Manifest.permission.ACCESS_FINE_LOCATION) - } - override val transmitPermissions: Set = when { - Build.VERSION.SDK_INT >= 33 -> setOf( - Manifest.permission.POST_NOTIFICATIONS, - ) - else -> emptySet() - } - private val transmitQueue = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) - - override suspend fun transmitPacket(packet: AprsPacket, encodingConfig: EncodingConfig) { - val encoded = try { - aprsCodec.toString(packet, encodingConfig) - } catch (encodingError: Throwable) { - logger.error("Unable to encode packet to String", encodingError) - return - } - - transmitQueue.emit(encoded) - } - - override suspend fun connect() { - logger.debug("Connecting Internet Packet Capture") - - runJob.updateAndGet { priorJob -> - priorJob?.takeIf { it.isActive } ?: launchNewJob() - } - } - - override suspend fun disconnect() { - clientConnectionState.value = DriverConnectionState.Disconnecting - runJob.value?.cancelAndJoin() - } - - private fun launchNewJob(): Job { - logger.debug("Launching new job for Internet Packet Capture") - return runScope.launch { - settings.internetServiceConfiguration - .combinePair(locationProvider.location) - .onEach { logger.debug("New Settings/Location pair: $it") } - .flatMapLatest { (settings, location) -> connectWithRetry(settings, location) } - .onEach { if (it.startsWith('#')) logger.info("APRS-IS: $it") } - .filter { !it.startsWith('#') } - .mapNotNull { captureStringPacket(it) } - .onEach { logger.debug("IS Packet Parsed: $it") } - .flowOn(Dispatchers.IO) - .collect { incoming.emit(it) } - } - } - - private fun connectWithRetry(settings: ConnectionConfiguration, location: GeoCoordinates): Flow { - return callbackFlow { - logger.info("Opening APRS-IS Client to ${settings.host}:${settings.port}") - var attempts = 0 - while (currentCoroutineContext().isActive) { - clientConnectionState.value = DriverConnectionState.Connecting - try { - client.connect( - server = settings.host, - port = settings.port, - credentials = settings.credentials, - filters = listOf( - "r/${location.latitude.asDecimal}/${location.longitude.asDecimal}/${ - settings.searchRadius.toMeters().value(Kilo).toInt() - }" - ) - ) { read, write -> - logger.info("APRS-IS Connected") - clientConnectionState.value = DriverConnectionState.Connected - attempts = 0 - coroutineScope { - launch { read.consumeEach { send(it) } } - launch { transmitQueue.collect { write.send(it) } } - } - } - } catch (error: CancellationException) { - logger.trace("APRS-IS Connection cancelling", error) - throw error - } catch (error: Throwable) { - logger.error("APRS-IS Connection terminated unexpectedly", error) - delay(100*(2.0.pow(attempts)).toLong().coerceAtMost(60_000)) - ++attempts - } finally { - clientConnectionState.value = DriverConnectionState.Disconnected - } - } - } - } - - private suspend fun captureStringPacket(data: String): CapturedPacket? { - val parsed = try { - aprsCodec.fromString(data) - } catch (parsingError: Throwable) { - logger.warn("Unable to parse packet", parsingError) - return null - } - - return packetStorage.save(data.toByteArray(Charsets.US_ASCII), parsed, PacketOrigin.AprsIs) - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/PacketDriver.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/PacketDriver.kt deleted file mode 100644 index 9ad7780f..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/PacketDriver.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.data.drivers - -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.EncodingConfig -import kotlinx.coroutines.flow.Flow - -interface PacketDriver { - val connectionState: Flow - val incoming: Flow - val transmitPermissions get() = emptySet() - val receivePermissions get() = emptySet() - suspend fun transmitPacket(packet: AprsPacket, encodingConfig: EncodingConfig) - suspend fun connect() - suspend fun disconnect() -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/PacketDrivers.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/PacketDrivers.kt deleted file mode 100644 index 989d385a..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/PacketDrivers.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.inkapplications.ack.data.drivers - -class PacketDrivers( - val internetDriver: InternetDriver, - val afskDriver: AfskDriver, - val tncDriver: TncDriver, -) diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/TncDriver.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/TncDriver.kt deleted file mode 100644 index 83836ca8..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/TncDriver.kt +++ /dev/null @@ -1,156 +0,0 @@ -package com.inkapplications.ack.data.drivers - -import android.Manifest -import android.bluetooth.BluetoothClass -import android.os.Build -import androidx.annotation.RequiresPermission -import com.inkapplications.ack.codec.AprsCodec -import com.inkapplications.ack.data.CapturedPacket -import com.inkapplications.ack.data.PacketOrigin -import com.inkapplications.ack.data.PacketStorage -import com.inkapplications.ack.data.kiss.kissData -import com.inkapplications.ack.data.kiss.writeKissData -import com.inkapplications.ack.structures.AprsPacket -import com.inkapplications.ack.structures.EncodingConfig -import com.inkapplications.android.extensions.bluetooth.BluetoothDeviceAccess -import com.inkapplications.android.extensions.bluetooth.BluetoothDeviceData -import com.inkapplications.coroutines.filterItems -import com.inkapplications.standard.throwCancels -import kimchi.logger.KimchiLogger -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.launch -import java.io.IOException -import java.io.OutputStream -import java.util.* - -class TncDriver internal constructor( - private val bluetoothAccess: BluetoothDeviceAccess, - private val packetStorage: PacketStorage, - private val ack: AprsCodec, - private val runScope: CoroutineScope, - private val logger: KimchiLogger, -): PacketDriver { - /** - * Bluetooth Serial Port Profile (SPP) UUID. - */ - private val SPP_UID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") - - private val runJob = MutableStateFlow(null) - private val selectedDevice = MutableStateFlow(null) - private val deviceConnectionState = MutableStateFlow(DriverConnectionState.Disconnected) - override val connectionState: Flow = combine(deviceConnectionState, selectedDevice) { connection, device -> - when { - device == null -> DriverConnectionState.Disconnected - connection == DriverConnectionState.Disconnected -> DriverConnectionState.Connecting - else -> connection - } - } - override val receivePermissions: Set = when { - Build.VERSION.SDK_INT >= 34 -> setOf( - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.FOREGROUND_SERVICE_LOCATION, - Manifest.permission.BLUETOOTH_CONNECT, - Manifest.permission.BLUETOOTH_SCAN, - ) - Build.VERSION.SDK_INT > 31 -> setOf( - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.BLUETOOTH_CONNECT, - Manifest.permission.BLUETOOTH_SCAN, - ) - else -> setOf(Manifest.permission.ACCESS_FINE_LOCATION) - } - override val transmitPermissions: Set = when { - Build.VERSION.SDK_INT >= 34 -> setOf( - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.FOREGROUND_SERVICE_LOCATION, - Manifest.permission.BLUETOOTH_CONNECT, - Manifest.permission.BLUETOOTH_SCAN - ) - Build.VERSION.SDK_INT > 31 -> setOf( - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.BLUETOOTH_CONNECT, - Manifest.permission.BLUETOOTH_SCAN - ) - else -> setOf(Manifest.permission.ACCESS_FINE_LOCATION) - } - private val outputStream = MutableStateFlow(null) - private val networkDevices = bluetoothAccess.devices - .filterItems { it.majorClass == BluetoothClass.Device.Major.NETWORKING } - - val deviceData: Flow = combine( - deviceConnectionState, - selectedDevice, - networkDevices, - ) { connectionState, selectedDevice, devices -> - ConnectTncData( - connectedDevice = selectedDevice.takeIf { connectionState == DriverConnectionState.Connected }, - connectingDevice = selectedDevice.takeIf { connectionState == DriverConnectionState.Connecting }, - discoveredDevices = devices, - ) - } - - override val incoming = MutableSharedFlow() - - fun selectDevice(device: BluetoothDeviceData) { - selectedDevice.value = device - } - - override suspend fun disconnect() { - deviceConnectionState.value = DriverConnectionState.Disconnecting - runJob.value?.cancelAndJoin() - } - - override suspend fun transmitPacket(packet: AprsPacket, encodingConfig: EncodingConfig) { - val data = ack.toAx25(packet, encodingConfig) - outputStream.value?.writeKissData(data) - } - - @RequiresPermission(allOf = [Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN]) - override suspend fun connect() { - runJob.updateAndGet { priorJob -> - priorJob?.takeIf { it.isActive } ?: launchNewJob() - } - } - - @RequiresPermission(allOf = [Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN]) - private fun launchNewJob(): Job { - logger.debug("Launching new job for Bluetooth Packet Capture") - return runScope.launch { - try { - selectedDevice - .filterNotNull() - .collectLatest { deviceData -> - deviceConnectionState.value = DriverConnectionState.Connecting - try { - bluetoothAccess.connect( - device = deviceData, - uuid = SPP_UID - ) { input, output -> - outputStream.value = output - deviceConnectionState.value = DriverConnectionState.Connected - input.kissData().collect { data -> - runCatching { - val packet = ack.fromAx25(data) - val saved = packetStorage.save(data, packet, PacketOrigin.Tnc) - incoming.emit(saved) - }.throwCancels().onFailure { - logger.error("Failed to capture packet", it) - } - } - } - } catch (error: IOException) { - logger.warn("IO Error while connecting to TNC. Possibly during Disconnect.", error) - } finally { - outputStream.value = null - deviceConnectionState.value = DriverConnectionState.Disconnected - } - } - } finally { - selectedDevice.value = null - } - } - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/kiss/KissSchema.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/kiss/KissSchema.kt deleted file mode 100644 index 9e551200..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/kiss/KissSchema.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.inkapplications.ack.data.kiss - -/** - * KISS Protocol signifiers used for parsing. - * - * @see http://www.ka9q.net/papers/kiss.html - */ -internal object KissSchema { - const val FrameEnd = 0xC0 - const val FrameEscape = 0xDB - const val TransposedFrameEnd = 0xDC - const val TransposedFrameEscape = 0xDD - - object HostTypes { - const val Data = 0x00 - } - - object TncTypes { - const val Data = 0x00 - const val TxDelay = 0x01 - const val Persistence = 0x02 - const val SlotTime = 0x03 - const val TxTail = 0x04 - const val FullDuplex = 0x05 - const val SetHardware = 0x06 - const val Return = 0xFF - } -} diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/kiss/Streams.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/kiss/Streams.kt deleted file mode 100644 index cb983fca..00000000 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/kiss/Streams.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.inkapplications.ack.data.kiss - -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import java.io.InputStream -import java.io.OutputStream -import kotlin.coroutines.resume - -/** - * Extract frame data from a serial stream via the KISS protocol. - * - * @see http://www.ka9q.net/papers/kiss.html - */ -fun InputStream.kissData(): Flow { - return flow { - val buffer = ArrayList() - while (currentCoroutineContext().isActive) { - when (val char = readSuspend()) { - KissSchema.FrameEnd -> { - if (buffer.isNotEmpty()) { - val command = buffer[0] - - when (command) { - KissSchema.HostTypes.Data.toByte() -> { - emit(buffer.drop(1).toByteArray()) - buffer.clear() - } - } - } - } - KissSchema.FrameEscape -> when (readSuspend()) { - KissSchema.TransposedFrameEnd -> buffer += KissSchema.FrameEnd.toByte() - KissSchema.TransposedFrameEscape -> buffer += KissSchema.FrameEscape.toByte() - } - else -> buffer += char.toByte() - } - } - } -} - -/** - * Write a byte array to the stream via the KISS protocol. - * - * @param bytes The data to write. - * @param type The type of frame the data bytes represent. - * @see http://www.ka9q.net/papers/kiss.html - */ -fun OutputStream.writeKissData( - bytes: ByteArray, - type: Int = KissSchema.TncTypes.Data, -) { - write(KissSchema.FrameEnd) - write(type) - write(bytes) - write(KissSchema.FrameEnd) - flush() -} - -/** - * Read a single byte from the stream, suspending on the IO thread until - * it is available. - */ -private suspend fun InputStream.readSuspend(): Int { - return withContext(Dispatchers.IO) { - suspendCancellableCoroutine { cont -> - cont.invokeOnCancellation { close() } - cont.resume(read()) - } - } -} diff --git a/aprs-android/src/main/sqldelight/com/inkapplications/ack/data/CapturedPacketEntity.sq b/aprs-android/src/main/sqldelight/com/inkapplications/ack/data/CapturedPacketEntity.sq deleted file mode 100644 index 73554277..00000000 --- a/aprs-android/src/main/sqldelight/com/inkapplications/ack/data/CapturedPacketEntity.sq +++ /dev/null @@ -1,69 +0,0 @@ -import kotlinx.datetime.Instant; -import com.inkapplications.ack.data.CaptureId; -import com.inkapplications.ack.data.PacketOrigin; -import com.inkapplications.ack.structures.station.Callsign; - -CREATE TABLE CapturedPacketEntity ( - id INTEGER AS CaptureId PRIMARY KEY AUTOINCREMENT, - timestamp INTEGER AS Instant NOT NULL, - raw_data BLOB NOT NULL, - packet_origin TEXT AS PacketOrigin NOT NULL, - source_callsign TEXT AS Callsign NOT NULL, - addressee_callsign TEXT AS Callsign, - data_type TEXT NOT NULL, - comment_field TEXT -); - -findById: -SELECT * FROM CapturedPacketEntity WHERE id = :id; - -countAll: -SELECT count(*) FROM CapturedPacketEntity; - -findRecent: -SELECT * FROM CapturedPacketEntity ORDER BY timestamp DESC LIMIT :count; - -findBySourceCallsign: -SELECT * FROM CapturedPacketEntity WHERE source_callsign = :callsign LIMIT :limit; - -countSources: -SELECT count(DISTINCT source_callsign) FROM CapturedPacketEntity; - -findMostRecentByType: -SELECT * FROM CapturedPacketEntity WHERE data_type = :type ORDER BY timestamp DESC LIMIT 1; - -findStationComments: -SELECT * FROM CapturedPacketEntity WHERE comment_field LIKE '%MHz%' ORDER BY timestamp DESC LIMIT :limit; - -findConversation: -SELECT * FROM CapturedPacketEntity -WHERE (source_callsign = :addresseeCallsign AND addressee_callsign = :callsign) -OR (source_callsign = :callsign AND addressee_callsign = :addresseeCallsign); - -findLatestConversationMessages: -SELECT * FROM CapturedPacketEntity -WHERE id IN ( - SELECT id FROM ( - SELECT source_callsign AS filterkey, * FROM CapturedPacketEntity - WHERE addressee_callsign = :callsign - UNION - SELECT addressee_callsign AS filterkey, * FROM CapturedPacketEntity - WHERE (source_callsign = :callsign AND addressee_callsign IS NOT NULL) - ORDER BY timestamp DESC - ) - GROUP BY filterkey -); - -addPacket: - INSERT INTO CapturedPacketEntity ( - timestamp, - raw_data, - packet_origin, - source_callsign, - addressee_callsign, - data_type, - comment_field - ) VALUES (?, ?, ?, ?, ?, ?, ?); - -lastId: - SELECT last_insert_rowid(); diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts deleted file mode 100644 index e0a3ab61..00000000 --- a/buildSrc/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -plugins { - `kotlin-dsl` -} -repositories { - gradlePluginPortal() - mavenCentral() - google() -} -dependencies { - implementation(libs.kotlin.gradle) - implementation(libs.android.gradle) - implementation(libs.google.services) - implementation(libs.google.license.plugin) - implementation(libs.firebase.crashlytics.gradle) - implementation(libs.hilt.plugin) - implementation(libs.sqldelight.gradle) -} diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts deleted file mode 100644 index b5a0fabf..00000000 --- a/buildSrc/settings.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -dependencyResolutionManagement { - versionCatalogs { - create("libs") { - from(files("../gradle/libs.versions.toml")) - } - } -} diff --git a/buildSrc/src/main/kotlin/Properties.kt b/buildSrc/src/main/kotlin/Properties.kt deleted file mode 100644 index 4f2f296c..00000000 --- a/buildSrc/src/main/kotlin/Properties.kt +++ /dev/null @@ -1,21 +0,0 @@ -import org.gradle.api.Project - -fun Project.stringProperty(key: String, default: String): String { - return if (hasProperty(key)) property(key).toString() else default -} - -fun Project.optionalStringProperty(key: String): String? { - return if (hasProperty(key)) property(key).toString() else null -} - -fun Any?.buildQuote(): String { - return if (this == null) "null" else "\"$this\"" -} - -fun Project.intProperty(key: String, default: Int): Int { - return if (hasProperty(key)) property(key).toString().toInt() else default -} - -fun Project.booleanProperty(key: String, default: Boolean): Boolean { - return if (hasProperty(key)) property(key).toString().toBoolean() else default -} diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 23bba3eb..00000000 --- a/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -android.enableJetifier=false -android.useAndroidX=true -org.gradle.jvmargs=-Xmx2G diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml deleted file mode 100644 index 971eeb52..00000000 --- a/gradle/libs.versions.toml +++ /dev/null @@ -1,283 +0,0 @@ -[versions] -activity = "1.9.3" -compose-compiler = "1.5.9" -ack = "1.0.0" -kimchi-core = "2.2.0" -kimchi-firebase = "2.0.0" -watermelon = "1.7.0" -kotlin = "1.9.22" -coroutines = "1.8.1" -dagger = "2.46.1" -sqldelight = "2.0.1" - -## -# Kotlin Dependencies -## -[libraries.kotlin-gradle] -version.ref = "kotlin" -module = "org.jetbrains.kotlin:kotlin-gradle-plugin" - -[libraries.kotlin-test-junit] -version.ref = "kotlin" -module = "org.jetbrains.kotlin:kotlin-test-junit" - -[libraries.kotlin-test-core] -version.ref = "kotlin" -module = "org.jetbrains.kotlin:kotlin-test" - -[libraries.kotlin-test-annotations] -version.ref = "kotlin" -module = "org.jetbrains.kotlin:kotlin-test-annotations-common" - -[libraries.coroutines-core] -version.ref = "coroutines" -module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" - -[libraries.coroutines-android] -version.ref = "coroutines" -module = "org.jetbrains.kotlinx:kotlinx-coroutines-android" - -[libraries.coroutines-test] -version.ref = "coroutines" -module = "org.jetbrains.kotlinx:kotlinx-coroutines-test" - -## -# Android Dependencies -## -[libraries.android-gradle] -version = "8.1.1" -module = "com.android.tools.build:gradle" - -[libraries.androidx-core] -version = "1.12.0" -module = "androidx.core:core-ktx" - -[libraries.androidx-test-core] -version = "1.9.0" -module = "androidx.test:core" - -[libraries.androidx-test-runner] -version = "1.5.2" -module = "androidx.test:runner" - -[libraries.androidx-appcompat] -version = "1.6.1" -module = "androidx.appcompat:appcompat" - -[libraries.androidx-preference] -version = "1.2.0" -module = "androidx.preference:preference-ktx" - -[libraries.androidx-compose-ui] -version = "1.6.1" -module = "androidx.compose.ui:ui" - -[libraries.androidx-compose-foundation] -version = "1.6.1" -module = "androidx.compose.foundation:foundation" - -[libraries.androidx-compose-material-core] -version = "1.4.3" -module = "androidx.compose.material:material" - -[libraries.androidx-activity-compose] -version.ref = "activity" -module = "androidx.activity:activity-compose" - -[libraries.androidx-activity-ktx] -version.ref = "activity" -module = "androidx.activity:activity-ktx" - -[libraries.androidx-compose-navigation] -version = "2.5.3" -module = "androidx.navigation:navigation-compose" - -[libraries.androidx-compose-material-icons-core] -version = "1.4.3" -module = "androidx.compose.material:material-icons-core" - -[libraries.androidx-compose-material-icons-extended] -version = "1.4.3" -module = "androidx.compose.material:material-icons-extended" - -[libraries.android-tools-desugar-jdk] -version = "2.0.4" -module = "com.android.tools:desugar_jdk_libs" - -[libraries.androidx-annotation] -version = "1.7.1" -module = "androidx.annotation:annotation" - -## -# Ink Dependencies -## -[libraries.kimchi-logger] -version.ref = "kimchi-core" -module = "com.inkapplications.kimchi:logger" - -[libraries.kimchi-core] -version.ref = "kimchi-core" -module = "com.inkapplications.kimchi:core" - -[libraries.kimchi-analytics] -version.ref = "kimchi-core" -module = "com.inkapplications.kimchi:analytics" - -[libraries.kimchi-firebase-crashlytics] -version.ref = "kimchi-firebase" -module = "com.inkapplications.kimchi-firebase:crashlytics" - -[libraries.kimchi-firebase-analytics] -version.ref = "kimchi-firebase" -module = "com.inkapplications.kimchi-firebase:analytics" - -[libraries.ack-codec] -version.ref = "ack" -module = "com.inkapplications.ack:codec" - -[libraries.ack-client] -version.ref = "ack" -module = "com.inkapplications.ack:client" - -[libraries.ack-structures] -version.ref = "ack" -module = "com.inkapplications.ack:structures" - -[libraries.spondee-units] -version = "1.2.0" -module = "com.inkapplications.spondee:units" - -[libraries.watermelon-coroutines] -version.ref = "watermelon" -module = "com.inkapplications.watermelon:coroutines" - -[libraries.watermelon-standard] -version.ref = "watermelon" -module = "com.inkapplications.watermelon:standard" - -[libraries.watermelon-android] -version.ref = "watermelon" -module = "com.inkapplications.watermelon:android" - -## -# Other / Misc -## -[libraries.sqldelight-gradle] -version.ref = "sqldelight" -module = "app.cash.sqldelight:app.cash.sqldelight.gradle.plugin" - -[libraries.sqldelight-android-driver] -version.ref = "sqldelight" -module = "app.cash.sqldelight:android-driver" - -[libraries.sqldelight-primitives] -version.ref = "sqldelight" -module = "app.cash.sqldelight:primitive-adapters" - -[libraries.sqldelight-coroutines-extensions] -version.ref = "sqldelight" -module = "app.cash.sqldelight:coroutines-extensions" - -[libraries.dagger-core] -version.ref = "dagger" -module = "com.google.dagger:dagger" - -[libraries.dagger-compiler] -version.ref = "dagger" -module = "com.google.dagger:dagger-compiler" - -[libraries.hilt-compiler] -version.ref = "dagger" -module = "com.google.dagger:hilt-compiler" - -[libraries.hilt-plugin] -version.ref = "dagger" -module = "com.google.dagger:hilt-android-gradle-plugin" - -[libraries.hilt-core] -version.ref = "dagger" -module = "com.google.dagger:hilt-android" - -[libraries.androidx-hilt-common] -version.ref = "dagger" -module = "com.google.dagger:hilt-android" - -[libraries.androidx-hilt-compiler] -version.ref = "dagger" -module = "com.google.dagger:hilt-compiler" - -[libraries.androidx-hilt-navigation-compose] -version = "1.0.0" -module = "androidx.hilt:hilt-navigation-compose" - -[libraries.firebase-config] -version = "21.2.1" -module = "com.google.firebase:firebase-config-ktx" - -[libraries.firebase-analytics] -version = "21.2.0" -module = "com.google.firebase:firebase-analytics-ktx" - -[libraries.firebase-crashlytics-gradle] -version = "2.9.4" -module = "com.google.firebase:firebase-crashlytics-gradle" - -[libraries.google-material-core] -version = "1.8.0" -module = "com.google.android.material:material" - -[libraries.google-services] -version = "4.3.15" -module = "com.google.gms:google-services" - -[libraries.google-license-plugin] -version = "0.10.5" -module = "com.google.android.gms:oss-licenses-plugin" - -[libraries.google-license-core] -version = "17.0.0" -module = "com.google.android.gms:play-services-oss-licenses" - -[libraries.junit] -version = "4.12" -module = "junit:junit" - -[libraries.mapbox-android-sdk] -version = "10.11.2" -module = "com.mapbox.maps:android" - -[bundles] -androidx-compose-icons = [ - "androidx-compose-material-icons-core", - "androidx-compose-material-icons-extended", -] -androidx-compose-full = [ - "androidx-compose-ui", - "androidx-compose-foundation", - "androidx-compose-material-core", - "androidx-compose-material-icons-core", - "androidx-compose-material-icons-extended", - "androidx-compose-navigation", - "androidx-activity-compose", -] -watermelon = [ - "watermelon-coroutines", - "watermelon-standard", - "watermelon-android", -] -dagger-kapt = [ - "dagger-compiler", - "hilt-compiler", - "androidx-hilt-compiler", -] -dagger-libraries = [ - "dagger-core", - "hilt-core", - "androidx-hilt-common", - "androidx-hilt-navigation-compose", -] -sqldelight-android = [ - "sqldelight-android-driver", - "sqldelight-primitives", - "sqldelight-coroutines-extensions", -] diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ac72c34e..00000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100755 index 0adc8e1a..00000000 --- a/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 6689b85b..00000000 --- a/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/mapbox/build.gradle.kts b/mapbox/build.gradle.kts deleted file mode 100644 index 5f3d969a..00000000 --- a/mapbox/build.gradle.kts +++ /dev/null @@ -1,37 +0,0 @@ -plugins { - id("com.android.library") - kotlin("android") -} - -android { - namespace = "com.inkapplications.ack.android.mapbox" - compileSdk = 34 - - defaultConfig { - minSdk = 21 - buildConfigField("String", "MAPBOX_ACCESS_TOKEN", optionalStringProperty("mapboxPublic").buildQuote()) - } - buildFeatures { - compose = true - buildConfig = true - } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() - } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() - } - compileOptions { - targetCompatibility = JavaVersion.VERSION_11 - sourceCompatibility = JavaVersion.VERSION_11 - } -} - -dependencies { - api(projects.maps) - implementation(projects.aprsAndroid) - implementation(libs.androidx.annotation) - api(libs.androidx.compose.foundation) - implementation(libs.mapbox.android.sdk) - implementation(libs.watermelon.android) -} diff --git a/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapController.kt b/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapController.kt deleted file mode 100644 index fb5c627a..00000000 --- a/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapController.kt +++ /dev/null @@ -1,140 +0,0 @@ -package com.inkapplications.ack.android.mapbox - -import android.Manifest -import android.annotation.SuppressLint -import android.content.res.Resources -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import androidx.annotation.RequiresPermission -import com.google.gson.JsonObject -import com.inkapplications.ack.android.maps.* -import com.inkapplications.ack.data.CaptureId -import com.inkapplications.android.continuePropagation -import com.mapbox.geojson.Point -import com.mapbox.maps.CameraOptions -import com.mapbox.maps.MapView -import com.mapbox.maps.MapboxMap -import com.mapbox.maps.Style -import com.mapbox.maps.plugin.animation.easeTo -import com.mapbox.maps.plugin.annotation.annotations -import com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptions -import com.mapbox.maps.plugin.annotation.generated.createPointAnnotationManager -import com.mapbox.maps.plugin.attribution.attribution -import com.mapbox.maps.plugin.gestures.addOnMapClickListener -import com.mapbox.maps.plugin.gestures.gestures -import com.mapbox.maps.plugin.locationcomponent.location -import com.mapbox.maps.plugin.logo.logo -import com.mapbox.maps.plugin.scalebar.scalebar -import com.mapbox.maps.plugin.viewport.data.FollowPuckViewportStateBearing -import com.mapbox.maps.plugin.viewport.data.FollowPuckViewportStateOptions -import com.mapbox.maps.plugin.viewport.viewport -import java.util.* - -/** - * Adapt a Mapbox Map view into our controller interface. - */ -class MapboxMapController( - private val view: MapView, - private val map: MapboxMap, - private val style: Style, - private val resources: Resources, - private val onSelect: (CaptureId?) -> Unit, -): MapController { - private val defaultMarkerId = UUID.randomUUID().toString() - - private val symbolManager = view.annotations.createPointAnnotationManager().also { - it.iconAllowOverlap = true - it.addClickListener { - val json = (it.getData() as JsonObject) - map.easeTo( - CameraOptions.Builder() - .center(Point.fromLngLat(json.get("lon").asDouble, json.get("lat").asDouble)) - .build() - ) - onSelect(CaptureId(json.get("id").asLong)) - true - } - map.addOnMapClickListener { - continuePropagation { onSelect(null) } - } - style.addImage(defaultMarkerId, BitmapFactory.decodeResource(resources, R.drawable.default_marker)) - } - - override fun initDefaults() { - view.scalebar.enabled = false - view.gestures.rotateEnabled = false - view.gestures.pitchEnabled = false - setCamera(CameraPositionDefaults.unknownLocation) - view.location.updateSettings { - pulsingEnabled = true - } - } - - override fun setBottomPadding(padding: Float) { - view.attribution.marginBottom = padding - view.logo.marginBottom = padding - } - - override fun showMarkers(markers: Collection) { - markers - .map { marker -> - PointAnnotationOptions() - .withData(JsonObject().also { - it.addProperty("id", marker.id.value) - it.addProperty("lat", marker.coordinates.latitude.asDecimal) - it.addProperty("lon", marker.coordinates.longitude.asDecimal) - }) - .withPoint(Point.fromLngLat(marker.coordinates.longitude.asDecimal, marker.coordinates.latitude.asDecimal)) - .withIconImage(marker.symbol?.let { createImage(it, style) } ?: defaultMarkerId) - } - .run { symbolManager.create(this) } - } - - override fun zoomTo(cameraPosition: MapCameraPosition) { - map.easeTo( - CameraOptions.Builder() - .center(Point.fromLngLat(cameraPosition.coordinates.longitude.asDecimal, cameraPosition.coordinates.latitude.asDecimal)) - .zoom(cameraPosition.zoom.mapboxValue) - .build() - ) - } - - override fun setCamera(cameraPosition: MapCameraPosition) { - map.setCamera( - CameraOptions.Builder() - .center(Point.fromLngLat(cameraPosition.coordinates.longitude.asDecimal, cameraPosition.coordinates.latitude.asDecimal)) - .zoom(cameraPosition.zoom.mapboxValue) - .build() - ) - } - - @RequiresPermission(anyOf = [Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION]) - override fun enablePositionTracking() { - view.location.enabled = true - val state = view.viewport.makeFollowPuckViewportState( - FollowPuckViewportStateOptions.Builder() - .zoom(ZoomLevels.ROADS.mapboxValue) - .pitch(0.0) - .bearing(FollowPuckViewportStateBearing.Constant(0.0)) - .build() - ) - view.viewport.transitionTo(state) - } - - @SuppressLint("MissingPermission") - override fun disablePositionTracking() { - view.location.enabled = false - } - - override fun setPanEnabled(boolean: Boolean) { - view.gestures.scrollEnabled = boolean - } - - private fun createImage(image: Bitmap, style: Style): String { - val id = UUID.randomUUID().toString() - - style.addImage(id, image) - - return id - } -} diff --git a/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapRenderer.kt b/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapRenderer.kt deleted file mode 100644 index 4aacd35d..00000000 --- a/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapRenderer.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.inkapplications.ack.android.mapbox - -import android.annotation.SuppressLint -import android.app.Application -import androidx.compose.runtime.* -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.viewinterop.AndroidView -import com.inkapplications.ack.android.maps.MapController -import com.inkapplications.ack.android.maps.MapRenderer -import com.inkapplications.ack.android.maps.MapViewModel -import com.inkapplications.ack.data.CaptureId -import com.mapbox.maps.MapView -import com.mapbox.maps.ResourceOptionsManager -import kotlinx.coroutines.delay - -object MapboxMapRenderer: MapRenderer { - @SuppressLint("MissingPermission") - @Composable - override fun renderMarkerMap( - viewModel: MapViewModel, - onMapItemClicked: (CaptureId?) -> Unit, - bottomProtection: Dp, - interactive: Boolean, - modifier: Modifier - ) { - var controllerState by remember { mutableStateOf(null) } - val bottomProtectionPx = with(LocalDensity.current) { - bottomProtection.toPx() - } - AndroidView( - factory = { context -> - MapView(context).apply { - createController( - activity = context, - onInit = { controller -> - controllerState = controller - controller.setCamera(viewModel.cameraPosition) - controller.showMarkers(viewModel.markers) - controller.setBottomPadding(bottomProtectionPx) - controller.setPanEnabled(interactive) - if (viewModel.enablePositionTracking) { - controller.enablePositionTracking() - } else { - controller.disablePositionTracking() - } - }, - onSelect = onMapItemClicked, - ) - } - }, - update = { mapView -> - controllerState?.let { controller -> - controller.setCamera(viewModel.cameraPosition) - controller.showMarkers(viewModel.markers) - controller.setBottomPadding(bottomProtectionPx) - controller.setPanEnabled(interactive) - if (viewModel.enablePositionTracking) { - controller.enablePositionTracking() - } else { - controller.disablePositionTracking() - } - } - }, - modifier = modifier, - ) - } - - override suspend fun initialize(application: Application) { - ResourceOptionsManager.getDefault(application, BuildConfig.MAPBOX_ACCESS_TOKEN) - delay(500) // Fix race condition in MapView initialization - } -} diff --git a/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapViews.kt b/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapViews.kt deleted file mode 100644 index df3785df..00000000 --- a/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxMapViews.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.inkapplications.ack.android.mapbox - -import android.content.Context -import android.content.res.Configuration -import com.inkapplications.ack.android.maps.MapController -import com.inkapplications.ack.data.CaptureId -import com.mapbox.maps.MapView -import com.mapbox.maps.Style - -/** - * Create a Map controller by initializing a Mapbox Map. - */ -internal inline fun MapView.createController( - activity: Context, - crossinline onInit: (MapController) -> Unit, - noinline onSelect: (CaptureId?) -> Unit, -) { - val map = getMapboxMap() - val styleUri = if (activity.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) { - Style.DARK - } else { - Style.LIGHT - } - - map.loadStyleUri(styleUri) { style -> - val controller = MapboxMapController(this, map, style, activity.resources, onSelect = onSelect) - controller.initDefaults() - onInit(controller) - } -} diff --git a/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxZoomLevels.kt b/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxZoomLevels.kt deleted file mode 100644 index 26855660..00000000 --- a/mapbox/src/main/kotlin/com/inkapplications/ack/android/mapbox/MapboxZoomLevels.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.inkapplications.ack.android.mapbox - -import com.inkapplications.ack.android.maps.ZoomLevels - -/** - * Mapbox adaptation of zoom levels. - */ -internal val ZoomLevels.mapboxValue: Double get() = when (this) { - ZoomLevels.MIN -> 0.0 - ZoomLevels.CONTINENT -> 2.0 - ZoomLevels.ISLANDS -> 4.0 - ZoomLevels.RIVERS -> 7.0 - ZoomLevels.ROADS -> 10.0 - ZoomLevels.BUILDINGS -> 15.0 - ZoomLevels.MAX -> 22.0 -} diff --git a/mapbox/src/main/res/drawable-nodpi/default_marker.png b/mapbox/src/main/res/drawable-nodpi/default_marker.png deleted file mode 100644 index fd82b6d923d6fc54503e05ca6e9f7f0a932f964d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1420 zcmZ`(cTkgO82=#bAt-xEzyPx3BMd_XA&>wcvNE6`1`?7$83`+lAg&0~fSzE*s*PwYKM|Jy2}*PVe*&T1mc)FN+MJ^uzY9cfIS~`#$6MJim86&%Ki3!W>s8 zeUz(*c9ZbJK?usIsXg6_5bn>T%~4wk_&oIk~g~0O$?}fP=jNU_qgS zO90Rg0)U(a0L0S(;L|L`xL=$f#*nM1=YqLf#uYZ)rqsKljlrgp>7XN zoe(Q`a)e!+5kkBsd#8?`r)QTM_X^DYBFo3(chbR?(P7Ic{iXvg`YHyJk^paTQALF# z1iX$8>8nZ%jVxnly?L<5azbo5*=ruyYwW1gRZtOPg2Kx~5s2Ohr%nbnS*hBh97Aoz zatqHSZZr3HnLiSl`Z^5_RSM5d3O^rZc&IinQ&*C&XO$T0n9I%F9up@F3>%2ovVtG42h)MOoFmu`2lzLJ5Eh^n|Kg`cI}QNs-nWw@iA&bJd%;3ArUnhDM;FOWoWS6&Q2K|sEUq&U0q<$P0HW^ zg|`R1!BuW!Be%C(TU#4yO}T?MpRbTsNCz@lSFp3Qpjxe-o1Jx^dp);q%{9keqK=?B zR@J+5$WPzAxIBqE_ClzDV!vpQ@%F-LCCp#Y@O_9(VwBzEuzYPtS)ND5R4^0R;y!fc zQ%QLyEpK<;ku#DQWz5&#v}&CO@*WLDU22ROgKOUw)1S{jd-~gxUl+E6i`)q2?9}kp zLz3|`Gkq8PMy|*Ej0@h}xOzQdva?y(+R@V9W}Me8hQzPnZr|S5v$}$@J}l14y!XSF zDL&*336e%1Y=xIjzxdYFJOAU@{NhPQB~7opIPU*tE%z*s_qO-#kw1R#_xAMm(hakK zQL<#ZsIFW@>EM;L7x4MaeOaTik&y$`8_?(sW%~NWozX9@MNi-QYWm6nYl&UHG*R@3 zp{rY9);yLb?Wip@FV5inuvC20{$Yc-Z_qnVmfIm?-fWz?>qK*5LG%(y;)l;FWG`xF z>J9!s^BR;R49JmeCy0F64i6?TWjDQ=YHT~o(Vv=lX@Z{2eUH1v{Hg1H;XCGrTXb4S z-0N%4yMiUc? zFyRDMdJL_XQ}*2kY?vRiooiQ81o!$N#^Esw@y Vb44u=dFU4j01%~+d^wXP{tIgmY)SwC diff --git a/maps/build.gradle.kts b/maps/build.gradle.kts deleted file mode 100644 index 857c3344..00000000 --- a/maps/build.gradle.kts +++ /dev/null @@ -1,34 +0,0 @@ -plugins { - id("com.android.library") - kotlin("android") -} - -android { - namespace = "com.inkapplications.ack.android.maps" - compileSdk = 34 - - defaultConfig { - minSdk = 21 - } - - buildFeatures { - compose = true - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() - } - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() - } - compileOptions { - targetCompatibility = JavaVersion.VERSION_11 - sourceCompatibility = JavaVersion.VERSION_11 - } -} - -dependencies { - implementation(libs.androidx.annotation) - api(projects.aprsAndroid) - api(libs.androidx.compose.foundation) -} diff --git a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/DummyMapRenderer.kt b/maps/src/main/kotlin/com/inkapplications/ack/android/maps/DummyMapRenderer.kt deleted file mode 100644 index f9b7403f..00000000 --- a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/DummyMapRenderer.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.inkapplications.ack.android.maps - -import android.app.Application -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.Dp -import com.inkapplications.ack.data.CaptureId - -object DummyMapRenderer: MapRenderer { - @Composable - override fun renderMarkerMap( - viewModel: MapViewModel, - onMapItemClicked: (CaptureId?) -> Unit, - bottomProtection: Dp, - interactive: Boolean, - modifier: Modifier - ) {} - override suspend fun initialize(application: Application) {} -} diff --git a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapCameraPosition.kt b/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapCameraPosition.kt deleted file mode 100644 index 1c7926e5..00000000 --- a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapCameraPosition.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.inkapplications.ack.android.maps - -import inkapplications.spondee.spatial.GeoCoordinates -import inkapplications.spondee.spatial.latitude -import inkapplications.spondee.spatial.longitude - -/** - * Contains information on how to display the map to the user - */ -data class MapCameraPosition( - val coordinates: GeoCoordinates, - val zoom: ZoomLevels, -) - -object CameraPositionDefaults { - val unknownLocation = MapCameraPosition( - coordinates = GeoCoordinates(39.828497055897344.latitude, (-98.57943535336678).longitude), - zoom = ZoomLevels.CONTINENT, - ) -} diff --git a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapController.kt b/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapController.kt deleted file mode 100644 index abceb0b1..00000000 --- a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapController.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.inkapplications.ack.android.maps - -import android.Manifest.permission -import androidx.annotation.RequiresPermission - -/** - * Actions that can be sent to control the map view. - */ -interface MapController { - /** - * Initialize the map with default settings - */ - fun initDefaults() - - /** - * Add padding to the bottom of the map. - * - * This is used when there is an element like a bottom bar obstructing - * the full map, and ensures that elements are still displayed properly. - */ - fun setBottomPadding(padding: Float) - - /** - * Display a set of markers on the map. - */ - fun showMarkers(markers: Collection) - - /** - * Animate the map to a specific location and zoom level - */ - fun zoomTo(cameraPosition: MapCameraPosition) - - /** - * Immediately set the position and zoom level of the map to a location, without animating. - */ - fun setCamera(cameraPosition: MapCameraPosition) - - /** - * Display and zoom to the device's current location on the map. - */ - @RequiresPermission(anyOf = [permission.ACCESS_FINE_LOCATION, permission.ACCESS_COARSE_LOCATION]) - fun enablePositionTracking() - - /** - * Disable the device's current location from being tracked and displayed. - */ - fun disablePositionTracking() - - /** - * Enable or disable panning the map view. - */ - fun setPanEnabled(boolean: Boolean) -} - diff --git a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapRenderer.kt b/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapRenderer.kt deleted file mode 100644 index b041b870..00000000 --- a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapRenderer.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.inkapplications.ack.android.maps - -import android.app.Application -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.Dp -import com.inkapplications.ack.data.CaptureId - -interface MapRenderer { - @Composable - fun renderMarkerMap( - viewModel: MapViewModel, - onMapItemClicked: (CaptureId?) -> Unit, - bottomProtection: Dp, - interactive: Boolean, - modifier: Modifier, - ) - - suspend fun initialize(application: Application) -} diff --git a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapViewModel.kt b/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapViewModel.kt deleted file mode 100644 index 59f15e24..00000000 --- a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MapViewModel.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.inkapplications.ack.android.maps - -data class MapViewModel( - val cameraPosition: MapCameraPosition, - val markers: Collection, - val enablePositionTracking: Boolean = false, -) diff --git a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MarkerViewState.kt b/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MarkerViewState.kt deleted file mode 100644 index 712949f1..00000000 --- a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/MarkerViewState.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.inkapplications.ack.android.maps - -import android.graphics.Bitmap -import com.inkapplications.ack.data.CaptureId -import inkapplications.spondee.spatial.GeoCoordinates - -/** - * View data for a marker displayed on the map. - */ -data class MarkerViewState( - val id: CaptureId, - val coordinates: GeoCoordinates, - val symbol: Bitmap? -) diff --git a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/ZoomLevels.kt b/maps/src/main/kotlin/com/inkapplications/ack/android/maps/ZoomLevels.kt deleted file mode 100644 index d2e34c91..00000000 --- a/maps/src/main/kotlin/com/inkapplications/ack/android/maps/ZoomLevels.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.inkapplications.ack.android.maps - -/** - * Shorthand for common zoom levels. - */ -enum class ZoomLevels { - MIN, - CONTINENT, - ISLANDS, - RIVERS, - ROADS, - BUILDINGS, - MAX, -} diff --git a/settings.gradle.kts b/settings.gradle.kts deleted file mode 100644 index 1f5faf7c..00000000 --- a/settings.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") - -rootProject.name = "ack-android" - -include("android-extensions") -include("aprs-android") -include("android-application") -include("maps") -include("mapbox")

-m$Obb@^lI7A6A_ya7EEV<*XuT}VsGU{W|R6k%_s9lf=+;LC{gA#=6ww4o;aY> zd@3XHkxg^4eF|P1Z{gtIyi<0cl>y{4i{Eeex;Gst%`fk81wA*}0-hyKI0p13dc?h5 z-zdsEn)_6q5!iT-((bOm(|7cd2P*Sh0KjoG-liUrHF}+znJHKZ)~Z!{!qIoXxrev$ z6m8V$C7-G$?omH*iSNo!`BYb9-Oun}N{2gNS*-bPv2g3TU?8}|iQTRFA89L*#B$b| z0c!o$1@pY$7b5yMPbgco=GhMO&UPhxv@WH@L$;u4-~?(qZ&nyKzLwH}q#PXyd&e=wKN&wFvK*Rj?4P#11Vu3i;mW-4X6D z>{q9kQs=ueHbm!Odonn_7%WcS2B_mcFgWkB= zw5W_;#%H;XitpY40Dhj54)S|jX}$B}ea5#2GUX;Ihirns*Q$HFGcIeijJrFDD|URo zjLJU9QwDc-nYR`=X5LU3j8#w_sj0F&e@SqBzD=s_pP?-|&Dn|Kg)eHPhU^jtD?buB zKXAdh#%~5U^3t#He&+@dQXL)7KR9~u*`5c^E}?spnE?zwf+|wu2d2V4C>&>ebN#9* zBgZoJglAbt(gAII1{nnh~y!X~+xAh_UQns%cM&n zxDvpv9+m7iALzboYS@2@dlqR#f4chS<3+!`CT$uB)?=H<53={*VYEl*de_CP^_662 zk_KA#n}{N$o#&D@YOfDH`35=j{Q(h%@MV;#Hzr zfe#cznZVc&F*^NDlpnhTY<9MkcfKeMrY^C^h(bMSR+WFxfECl5!nBOT0rm9xe0*Ue z`{uR)JFf}Ovq?E%9kcM{7UYz~yK2$xRh+6v|Ib#Xc)qz%Ok9f;PrLCIgqGHi_0VV9 zel)m-o6)qpn<-rF9izUF;}9fYJK^pZ0zfxzs5>9S!3R02@<4_#!v8EAO+y^#vg{Rt zz;OquYs?(~heH0BHZGkL$$#u-|Q)_RtSLV68-_44*KN7v8_lZUa?N7*-I#5oL9TI)f4PZc z38Jn=zMp8Xtn^5R?#4t8OS*K0qk_~0uea1VZJGqxpe3N_hQPhm;X-p{`%T2r*hst- z(frY%?NHI%(Ng}mV%=8)=mH$Cv;k*hqE6?F_lP_=Be4YhgkIl|iN*SR3d0ITFh?;q zt|j45+yP?7J8I_;JJF#?c_c(}n)vAve^Yho#Y~8qUQ}NN0$t5nr)*(v-a7ZJX_kA0 z{aXRzxh6_6jk{joNk#Te&i-6Xz&jiD&iS9hZ#@zD&u3lF!~ zUOrwV7`xRp_k zdEs@sHWi37YFKHn!uC48O5uB3-X2ZvbAuovNoup`t|L^M=vNG5KYCtk8DJv6a>RsR-H;{Ct;0lqj+{PEBr$Mifz0St8DuI6x_jm#TB&?7kauyTNFic7dMbiXYB6LQAh1@ zZEY3X(P@`)>!EQ&Y*cUoL?FqV^FPl`-4vCiDtT3@s@(T|_X||L?cVdh|NQ6N^KK0r zrZ%;yO>JsZo7$py8%`|_?dYSA9?@G9`|&Yq8)_f{2qsRP7>~w)7zhxC`#GNiS1bWW zGHkE=wzjsWH#avIj2kzutfi%;uBoZXK6dO_7aIPJ&+r}g!M=TgL;y1tL)3|l;XS;cyPx+YV_#BIIPMjOp z=m}5;FrM1N2%0#s2DOvOz$>V2pte;4MX1_V0@G{s_byx;_rNTqz!YIy9J`3F4X%X@ zHkFLGoZ6er82cHS3@jK0tsM=YaqH}(b@1`+-1PJCXZ`@So9|^g?v34F*Cx3+wG9T_ zzyPFC4kY8;K}Oo>$AH4f0wkTGVjlr8`I>(A+lYIm{U*r|fMTT(Z@z;IK}*J1MD0Bv z19eJ(=?sI*>JwBFpnUHK_r3^y@qI{?#X|%f8t_(ng4fdDoj%6s&5cA%lia8L`A+Ur zs{)dNz>x=#26qazXM91^gPVw!*6s&P&k)EC>S-L*7J$x?wE@w43k~X%e%Pinih<+L z&G`c9Nn)jOK4M$xquw?dI5dFeOzXbdMvL**O)K#jl=~YawfSeA;WS{EQv1P&>a`)( zsjz zg7`;MQ&R;E&`UlVKmn&`eI!8j62{J7sw3v7AS9uD47Kl-yXv=F!`L0`Z){^;?@-5= zD%LTEji_BO7$|0Sk%+R)W^*ES_z@ABE3Gr&NUf8Z=~0u(loXSpz7TpO{<68OLbonH6F(t0W(|}|cwGX-DdzJAG2a-OfB&wx|Y?pit^e19j>f1)i`o(YH>g(;k)XOrV}?cD_{L88i@Wi8^;C!pQOC$B&{; zysyABxF90=@F6i#UbKYxaUxWw4s1~18T6))z1!`6qqw*@CDN0P!=>5uKPvD<4v6Ss z28bS$z%x8jT^GQ!L}iyFFKbPDNF!Hv)5XDhi9*LVb=RooWVhR&=G;(RNZE(bI!St0 zT^S%YS|{06BNmzwN*0P^?em11u86&94%R}?hJ=NDw2w*}#;z99YHMpJ8O}l?@}djf ztJo*DS;%Iy86J`8c^?v4V^rQJ_VYq6m+Skgswxxbg+>^ab&m6RJPQ>2#590(+hUH) zVzDfS&5fuT8qO`AF7T!TQ0%)g0ExWKyJYiZ$^HY=K7_>aN<0raF+FXVpT*q!Q>r?G zPJE+cpP|D-m}IqDt#`xr194+IeVNVXGy>53N<0r8G0kr5y13UB@ zyRpOi?Z)_^c%rjwmHQf+Zj8Lo9l$_;03>J&Z<~Op;Ys$Brl#eAxUVy3d$jk7aRfkqT5HzcxWT5~a<)smWR6=qpV;Q|;~TZ*^IY0H z%Wd75=^uAkbr7{E!$qVHvREwl0Sm$CATbA$L;!leF96LY=K1!1OBW!%xZ6Ttardf^ z7N63n{qtV$F`wRL)s8!)Nf|8yb&%C+eU)`kz-v+K`lqOh4T>Hw)%O?b!mFAt| zNr4~LTj}aiQ=7D}BscW%Wsab45=?}MOq>I*aN0!0LJ=gSJ2|0vIxrECkY)fS(%;K@ zoxT0s7g%P+`L3?W3a$wGp8nkE(bJl=?^gW+#J$93V70*r@1f0RPHxstAwdtpzw9iR zelJ&%UOW2;kDkM79XGT91UCjDO_A7jz(ha*;+>M{z&m>q&=bZtYaiX}jk+HH7l(F0 zYyWN($36KQFAKeMlP&Blbka-@F`-lYfWks;#`pNgx|iVqdRPBuuOY zCISuRp@C8eK#%nVpwkZbbj$UebEJDfH+tbQZapuAbHRW}GKOP-0MtKR?$C8uJNE_G z|B@m}q$S=aFauP3)_K1}pm5VXmv-O*%|j*9gWT1#i|t*EgWS}c6j5GHfdEnyU>Zb)aIu#i@77+s z&Zg~N=go70b>Y?q+sJLi;JDBE^w8aUj!Rp+z)AALsr}}pMm@QUsiXc%0@$8s=HDhv zq%$^#_Z7lprwlsqLw^98OgHq`>%F1-)4w&w*biRfbz>irdkp0hK9!i~`K#<**W0n$ ztle>*t5-KXp1!+{qQvhxY6JssSUR|=2Y7;q>0$eJrDZ?2D;|n>m)rCQe(rQnP!Y0h zdy2?65+?E(8@-0|NEXFY*j7jY`odohXzuhTqIheUHdu0cqalNF@v-i%3^m-u>9ayJ z#et{skwuQK0AM=_cqBFhnc&4f3+K4IlAv&V8=g z_69xN$o7A+!qU}8uq^id^EGzu{G&YDgtq3Ob3p|K1r-dS_`U#?P+D4ANe6%H4?xf> zd)9ly?z3haV`vNt^o9WDwFUvx*ZuzLI4@8!u*)gZYHJM+fEWXSTs-N|5}O@7A@ody zDDc-OHg*eO;7(uoon4t!YAy{CU`*Q3q89vTTi z+X+AxUQ4J?043Jc)YQ>|JNzXPLG|Khpj!?#NC!+9KURN2yspu1xB-rw+SH}B@Z>&! zwLK{C$PGaJ`hKtQe~Ruml<5Zmbp0jHZj;jQ-)z+u%yIV#cs%5A**n)*xBnnarN3GPq5#zsqU4YCNF zb&zq|0uhOvIlp(l(~#sNw1{8@h}rWEPC?A3F+fT|03XIj8lk_;iQ^U!d%nKZ)@`hz z1p%&wbKPAJfjpf-4Ak0ZE=T~#WHLGZ0SFPtH`2^Ie5{d!g(qN}6j3ZY(`A@;_~Yf? zC=bPM$T}P1dg-2JR^EI!n9XB|SVmQY40`0JkQFy-yunC+y3(Q7aLHiWO8O2D#=^O- z&NgFd7?i#cVyH62gsRaY_5&Atbr3SahZ>M) zx%&cVw+Y)&^fecTRT;AB;0^LgFyZ-}G=KEyB1gzNh{{B9 z9SFOr{d@{9!Yn^)HfV})&GNT!z=423Ox7YBjHw1pbS^sKmwF?(Cqz7ApIvKzNk~HP zM8Zo3VlvfYvHXqa!jk)%3meWmjdHu){~?!iz$Xf3Km@k>;?QXcM0dN^iiu8(cIjMq zzap6@D2fwh8khh+D9l=7`hiV)z6s&C?>ln7lb(1`P!c>TvdTpCdZ31e29$GT2Lzy^ zq9W9NWHmN6-X#MFEb!S~-npvl&j?-pGOi`NF#sW0w!>V{&edK6^#_DTHGl%whXlY& z2%88j7)wN%_zZyqrg9>2!6~jt#Iko;jE!E)IfnC(vu2WTS|qzLL|nVpcnyNNpis^@ z-+Z>$jcs3P399x6S_2V~EcpAIxiz|M7A%NbBWNEyD3SV_wlu969ECpWHLc% zr&m=~jgu!-5uSPruq+{ozMf@NH-|`3LznODDsa(#{=i8|xc;^E0f6odbjnY+N$d{Mc!`2aKExG*Qy_>E2jJNMx z7JwqB889h}%&>areqa$;eSQ6_oC6ve=n5Tid3kwh^f#C2>t?+U`he#4|B(`Mp$y^u zCFZU;!QJis`(0}++I!1w+9MRf;9j00a3c{XnCG**EIRNMcm}@YFA3;Xzyf0;pr1g9 zW3iM?=sW3`w@^Kuo9^_^C*hUkaCQhFLJbRCn7({W5BU_N|FO@>Gd*hUAp-=o%jJTA zo)0WACgK8Jog<0EHq-@eJMSou_WdezhbWpdx{M>3x*iB=Oo+mbBD0I-VUSzFtJPo~ zWXu%^jF|(o+wI>I^RxjA(z?+B0SIC#gW4F6$Me#%c`j|=`g$EeDCnL!d2o#cc0m+~ zoC+p%ktJ8l<{2xX`HfU8aaYP%NEjBxGIt|#b93<`Ss|ftDUx#S3?RG#(5j3T^Y6q% z|Cmgsdl5`!XJ=;w`@0!&1qB6&#B$Ab6*IR#U}^8vbw)#HC|bsFiuVxG+1-nYCo>0up%p3(B^uITn zmUrs)G}ev@ZAzpL5%;wcw$I4O$PVP4_}+9-{>`Tq9`fUA^PY<-%27YI68r9pbnjl0 zFvr67{n0;iaamG&`mh|hu_qQaY(R~TzXhjMi=FVD>wmBsM-?hl*?slvH&pd-zQwFl z*qFoGYOW9zrv^KA*M{cg;ZoQ#Y3abLdW9S~AQ zqeqXP=J9y;^tSY`YSAm6Z8qCpvhfkHHBVo}55#@RPx_wy&%mTf#TnBT?-R7@xGyFsOeg@uREMRzF{iVgN5LimZ;=SZG;&tY4~4Kr{P zER>p(k}?KJZD?p%g`|^Wq3C8Gyme7kRfWjQM7AyFa^`p=*{54b&j>9gs`EIV&M$Ez zDmxv$lcpAn<(~wcR%V}EBSQB+-`HTJR+&tuMev`tAM9woe%+YQVD(4}NWJ?HgpndbVX&D6~(H5m{<#Y9Vq41qB5&TrSs7 zYMw0WrYv@6XJWzi;n(5@^C@l|_Eehg{cRU^BLzShgiB?6aSs=C>9h!dmQh`(_o| zM=p4{)@KW`&H-HSQxp#2+?Sxv6t1kKq~ufz?K_knicH-@0Z&I!QPH{Vx+-|WG%;MR zt0z~6Nw=J&q$Cq)k?3(5l2drIQDvzkCfnRe-a)IVsJI+65dAX2U@0$dk)1=RUG4%@Je@(0s(_2kOZ*{9-F5G#r57dgqOKs3lx7339OA)DCQ zHe=XUgXX&Yu~3}!9$6WDEH#J4VtI=}w2wQaT9}iCb#-;`;%89UCS}rlUU8AYKK}Gj zHVL#!WU15B(_4s%{?6gO0#W$E^AEDYc-Vq%k{t=Ur!PH(jAkwiwfd~AtVzT~n*nu8;~ukd7^Y=r0AZ$R`!5E%M+0qKtxRRvC>50(L4m6jSLQK69;B#9TON8n*H8n5O7`rjnJmv*#gM>&E&4ET{BD^o; z4mD5*9o5yQXr{lmqN1WR8X6itXI<2x zTw1^`tAoYz=EB0la{wM5(@GxWv`9)68mWm=Ih-uz4qK6@Am9DGrM{!J4MmA0#4UU z3!NAni^a0Dyu5rl#tdV}4`KBv|FkH2IivZ14R?yQCe!3rAA$;mk!^EO~3p^b*B zTa(;XyTm%L(HI@UF3XCs<1rk?V;UbzZYz+A#tasGlC!k5^h$ctzCgGyMQWWx z0Z0s-P7zpO3`i$_SyEDRHAh*(WtH>TWei3|VWfaah-=VqF;DpEY?Pdw+(wbwI&y12 zvd9)1ASM|}VjNuqqR;dY{a9I9`5=wO1dg)6I(0l&Ig(f&QsD8Yi&A)&xX_1<97Nf( zh`JxAaP?;iNbN!+MKhSh{j?p$J|r)Y3@Nv^Fk8r_?Zo6;Wy^a*{Vi1cX!&It@08;?N^k4Y|%QPNOl zoj}kVaI|daZl4yM$(fekIZ7vnj*tK;;DwqUlm^nN6^>NeHkw?j+HaYW!(2sJQj(Hb%JA~c&6$!E`%D*8lX;cZ4PRUR*C=(?hW@?QBiRZTr%#R^Etv* z)o~w3bDz_A4B{2*7zZT5NHzSl>U57M7&FoN`S~Z3JGis9w)Ryr*jBhXh;IPO2P{Ik zwhM5HCb`3IP2NX7R$g3!MX`QOT$|j}R^+yDPkDKHC(}K8_+E9lEah_q;|Sm+E8rLp zq+}l4QC#Oz%=14DKCA=-xiT{|4=ye)o=;Ewy%g2FXf~TS5~zNFVZjK9cmOOIJQyYt zAi=RX2hIg8gL5}DG;GARa80`Qg&7$cQ<-U;K5Wy#_g>6>8KoE}d_YR%w0#CgCZkz! zS4m(J%+v)aYGaWWC@LztptQ8~dUAVf$ka^fwE#c3W3)iKNnWo+z9b}iM+81>v5xQYMQ z@;+63Oa-5#gwI*X*U08;rt>{0&_pSiMzGNmSe&MCP9=@?lK@r@yOul_v;_?>0LnSARTEzL6BZU z3B83TQbdp{CCPVklCx*X zSw>y0pXtX;w{htp9W7w!+Az!S;|0B~*r#d=bZkK9gVDNw(8q8uqq~yl1&b_X> z(e$*Ex;>EoBGWKUm~eo;E6-7u5SMYJt(ydN69LNq*Wz(T& zBfKKKbT3{*9&-_>w%cTVaz)Q_r#x5=SB8d$0-w2?p|RQP?@P9Of*a$W5ff8Q*xlXz z1O&4e78cf%f@=GPc4tNJpy4SOiB=9%7d|#NaZcxlXlUV#s)TkOOn8cKj6!Sfg;(sM z?Jx45%@|i)E98FRu-}z}B7+7CX}L{|{*8@qF!w?CL~RG_(S)MNLT)cV`y4iUU$<&_ z)$OkSv%!82Cpw->_@p>TR(nWh{{i`qA=PH3@MQF<(uVaSEa{hilqKU_(d?E{lkacY zi`>fO6Qw|k)zt05y7D(UW+nC|5817k9Y2y_XchsHm*a_W!0ZOzz&d5;Ja>#aCZ)gg z<>0h*El4pj6#qopjKExFU%DLY7v~zy5KdaPJCUc?(PYcE-V8vH9*-y+YpA@FDEfE4 z+I6~qc^n1;Bt$|77@Ba(opJYj$<@9o(~BMYHy4&#G#Gw$CL<#&`JqSCHN-lsX^+u^ zqApW{WJqC~v+`W^$;rv67fDuiu2KL6h*t-f$k<_J6O`wKkFi*67aYV}gRoZTbXm_w zcB~-92@v+z@kKn4ECveHN?*EKi!(dMo)p6e?$ThI+0Lm+FtOXF;j~-?0vVeHmA^IhmYevdPtiuAN2u}#g)O{iu z^81^JcK7(lL0nVo`_tx`4>JvY9~3554H|x8A@i=`M|)TD>K*;xtkFZ%<-waVtDsV= z$e)qde{&Q~uVX8rk4Ca=rRy4vX_(S=bc?kUOl+4&Fuu-F&Wbt-6emlg>gr-L{s>w$l2BhMrh&73l}g3z?!i7=IF?<_2lib zSdwuN3IDQ*uc{O()5W7eQhN!S48}PzyUpL$@y=7nkr7j;^%qZJ%R99_`vueOggI{^ zWMPn^Xe0$D3R35@yguzLB(5r^{XvrV7OQ&M}nv27Xq1oVZ6fcD!U8gWpb7kafJR ztJIoz1AO1fY?xxazuUIT6+`#vv~9JDlK5yn{D!lOPLptDEQPwjzD{1xMJ=4Kj$T6t z>+_L*vE4$BKw@pzgq>h3DME&|U0FJczHIMmHkCG&>czDk^h|E*+4M$s@7dJ#7PVOx|N5z@U$a{Kj6Whl+-y8g47r*i>jKCq;M&U+RpO4jJQ92PjJoBYl)wew_?d=V83O=Ba#qk``C{u6x+!e zA_cVUi61}X80~O%LpdxFUm# zWkAonYcu}&-o3vs=l%#^o8U~>G0~{fV9}<;@;(|4_8zTge>gt)RuNY&$PQf^i_*Bv zKJq}g=;H5Q5uw$3yUGPl315pQ7Nijq!cdFCc!Rf6KPFVM&l|B^)DMzmK-SD-g#i^2 zoxDg&lVR7T6>C-XT#fB4UA%;vsxU3baX`7X%or)#ZHRY8iUU76iiFw-kl|pi9mU_|pokh0SE8E-# zJm8R|)qC#~aHhepY#7+&HhEy5*CX?KcE=Z+E9q9|i7r8d#UJ`1QKtOoZ;-y#!qoZo zQr{V<&QF3@_!^>Uv;u}2K)|2~=q zK{RAZBUf8?9GSCTC&4KHAkrvQx1|o4dsXDp62DTd88rrR50U`L2%}S{9=W*| zR;YK$6Q%j0uxH?==b(hMY52RydWBJ4AQqcS3E@)pJ8@y6-EWK2@$SyVH8th4OAaZs zvKpq}pZEgJ8cMeX<|o6elmkSn0E%84n>Ms?+f{r0mNGXgQ~XN>A_o&O$LyHaY2U$+eR4Z3?!=-iG6 z;7%SEwwc7frt@mp2;Sis-%2%&ccfLoRXN}nB&30s zmNeMrO$BLkS9Z+eZ}jb6rmkO>AoqO|)Onp+P}yFM>w@*l#`_-9y3sY;-5W+@GPT8t z^u^DLhQnogVP8YyZx4#G8LyW-V;wDqOchkYR^2g$T8*qvJkxK<$W_LOVEgMyW*0qk zG(vCa^{~C0sw7|SN%>$2Z@9PfIbnn!k8}uFY4oy27oY}orO~!2!od_i2fyOu2nZ{*0@4xdTP~h1s z7vZgjGTZNYR*|jM!zVQol=jF*n#Im_`#OV9vbw5b??Aib*)m z#*`B)k@xr4Jt~=-D>Aj0vKS;s!o-Loc()8T32~Rl)NLyvHT20} z>YyQ^E5!cU`YHGClh{FFY{`R?o8A4jH!om#UIj zwNvCWgmfS7!=O5Jpy%PR9W_NY2sDh72 zh(XS;Tg>Bjxpv<-%EPbL2!>)Q_oq^iU3C`QnYHK989z?+{*Wql~gkJl8n(v&Le z^HiHS-J)A)+q(OyjgRMb_0>KP3ui8D<)q5zzId((xk(C$_g=ZGykDLf;SuNxStYhN z$Crq{58oN*ixIh#LE1tDF3F2gra&y?LCjbJ|FGa`ZYsY+1wVFKjD zknQx;Qjj0CC>_KLrQ>x|``g{OsN;FT+=trP*+FL>Fn&j0xBV?&JOo6RQg5}3`L%XO z@|D%4N=D}>o;%}0DZ3xeH~5tWrm})M?~Fvbs|9;7#D#pw+=N=tJO3$#e)qVPYbBd(Aem^e-2u4QBoQDWRZD5a`$%??|3 z7eY=mtg&5nl3)G<9sMtX%?JJw?f)N8kY=4L_KRewz`#IfbAuRe`K~1;?+fSu6X1i) zNPqtPdF#Bi{3?M2^Wwz|!`*M!v_kXSa~1xqd&o*0^@r6GY93EQEQd2HnL$43@&X@vI&{4EI-{|^@dM_5@;hAF zhX;JW*G5Yw|8B?a8++q`EgLI}^l&U|zNO%}j`|q0bYi$( z+^@H%AZKt=9qKk zJGi{3LKb-G8gu16bN7v@8iX-)aj^I79$MPk+H{AeBiU%Gdx@eJL`}^-Q54FQi8Ayi zm5%QD!Gk?>x|j9j{r3IE6cx|-e8{V8<_M{ zTDEWN>JE-U+e8Psb(!O1zgEs}KDpT(b~Re@^p8UuKUJHM&EvqteVyk0I1#n8aTCB* z&y!FaiTn`c^?e*-fsqUM9CXKKA5}mS(6wJYE_{}?RMwxHM zj}qj1^?Oe|dtoBK4Mq*$1tf_&bJ++acEOYTPo8XsdJ#BEs*Ec1C;pUQNRm{l5q(%a zGHe#z>?HV$>G`Qh_0YjMvN~eMxRlMMq{NYu=~C9|2UU-=g!PBGdp$ne81oM?ZVD{<=+1}=YPt*-yZv9CFAZha7UqA%`5pJjRlYJLHf<#zW@Kn>Qg5QQyNk_*`Z$8OhEc5Yy z_#1zw4d20cagKPELzF^}v{+qO+*lv*csx^kdU{%B&6>54Gz+|&!_0; zizIK*@9)#kEhJk>21o`;ES5q3Km2VAfA$T0m(PK7-HCJK8n_m&iEGEYFT+d7AxHe6 z*T7?fs*u3fMRE|yB_!V_d7k8L2C$VO8Q^O^&-ZW%DaU~%ow!HyzBMHlWsoDbrH=xT zaR3!r-{l0do7ft^Hv}*T=`#T5_Gp5?#Un#~-|!r!yvO&5dtHuukM>OB8RXb$8BI%1 zoO=oZXb$KG$z$~UJ2AipP;S$J4e$@9+xn~PXo|9pe@6TKJ9q}BPIK^VyLx^(MnN#k zbYQF=tWpr#Pas)M@_Uj`VgX)(J%e;75yco7LLolkXIqVDHG=DiF_B~B(wv7aE#BBoPl!-o;7~`8T=F#RtjtpCUvQ$UYguH4@mRS7sQ6u$# zuVU=Q8)TmAE4tH2lkgoqt23HXnORPu>RF@jU@oG~ksN8FJTwW16Cd3mbSF1x5#|DO zB9tgilt)<=aj8b0{P(O_O9RzGjO!L>Ap<3$OQ06zs*rDRq9!|2@+ zfaQnmoGYS34^doDE=rIX_}jErhV2<%Z!41GbSeG*OehrU5G9DCxJ82%q(OT{`2NVs z64CFkk`nYv(QJq`C%MZ7G+6)Q0o*De8ZlzeB?ZR+3Iqa+Bu%P;e+>7S(*W&9vQfZ4 z;+0?{8M=d1l4CS0fwKH)Up|mGjgm~yD98{I9oj-laHx)f(HiiMr2*Mjz(4wwfIPt# zzu&*iY;GJ?;K!brMuAHJGK!Rdyue0|2}X|+XqG=f@|J*q)GNW;qy)1@g%TKf{+A`- zmB5%-0F>Yrx7*!0qU!`I)ydn1|53m%qANi#7<`suf{KyaK&Q6T0QLF4&>j(!4pC5S z5fyq!^$v|0L0how+)02m{c3I7L8Pzw zC#Ta{Iwnsy;To$%Tf-~h7l~U5K!r#N?$)uCH|Xb=FM#?SD!gAL*?54ckmYu}j|Gn}1KD&+V3-y|hy$(MLQxhbsWyC=`qO4dgtWmzGv4Qz5co%3@oE2MI?k}# zT}854@rCt2UaY@JCcS{m<@!9ZM=?P`R;@qXKoQ;4vy%A{$y7#&y}%0%4Gksi1;&f@ z7a4V4fQ;`7U@#jQA=~;lH8mB|4gFTQzeqM>0k7BltQHH5&vf2@TqqQh%#TRcyg(oj zusStl>00);|yk z;2mBcO7JU^OTjSFppVG5fyKiu{C zgap4Lxfl$4Jf7c`mX=OWISo?uhuln$&>xXpra`T(t$U`N2Jy)zkd~dJ+8!kPBa&m; zph3pa%;*Lti!eAQz;cA3|@bA{hJeObubZH`Q=Nc?dCe)|1>tG&Jb zL|`@*y+LC+tpxgWRkG<%0Qt;ALe`^~dacd(x~zc*oN>u}ce<>HzUZ?~I4IMCcUO6Apqrq6 zmZ;CoX9R3IblS2W>x_d#))$rst()loeoNmmKfj&M@$4Fp9V^I$i|i^6Xl`!y4m%sf zU!I7!c`ND@Z~AlDUcJ_T6JT|VzV&{m^_wfb)>%Y{cAq=T>hF*IUO&n1M0ZX(C}b-F zzN0GwVg{UBCR-#{a~#D10~7}w4(tvm4p7_A6_8swHxd572Z8$+mwUr3|Call*1B_j z*532`5~5G{t@K-;-WN`r9$)RXGe|P&B2j3N-4@Z=*?9%9t6tWUZ2o@&^Zz^Jr9X3K z&$4bgD-Z_$Psxgd!_V$d?!ll0TkZ?@B*+xaoh_3t5*Y^|5GKoycM23ThQ}qX09bWT zCw?+s1vqxU9_!sZ!UJA-gU{@dyv3eR*8Z_eyL`F%zI9q4^*7vU*8N@tpB>iOYwqGA(6;H*zI<2 zsHv&x0EStT3V;hplV;ONKaQsWhD;7}_c~R%)xI z7l6mf^+`c{$3c7bS|=RPV}0@Hp!M}r1GZtf@r;0V(Px7;mBZh6mttQkGeMTa;Wz~t zMjL;kfv{45LJBC(j%VX5v^b!srGxVa7y45EfNRh3hf^%_0{bn@-L&Y1%Y!ymd-W!_ z^~rtFE8g&w_&b#O{G);by~v;0YCn9^nOFE}b>y>Oi;YGr#ULBS7wQ7aD*+392fb#kdt zWP-Z7y6ymm8Ovi6?EyjzFtw+r=Ucl9fRUwnVs&`%i>hrRIsdr9wOgO{)Rp0tVl>eW zC(D#dSwQ#k-~~SGL&F;)6}*8c;d%o1&oA{_-#O1ml+kPb`Ri^wxHk)aNFF@=MW1!R zXL_R+4D&_$*&u)+>@{!4PbhY}43^#!LEQhxz%XNZY@$6t_)-y_@aH&jZ*Ol*4{+Gt zz1BYsZhrUK{^qY|Nb5si7So|*s)JK0%1;t z{)R9-ov}PV(G(~m=NWXOKkP~Yz;jJkkAN>-1A8D1+Qzlv*Sm%WI@{ofWjFht9{IA* zIxr3^j=y7V#BHDRTOS$TFx?`Y-TE5UI<+xO+i2P2A!ph>4K3*}U-qsu&^rife6|F!vEBd#IA|9wmffuGTu zBRAdavirPN9~ZP0VK~nTta2^j<%)`mHefjs1sKbD(@8BYEsj~d1!61(fD3>AT6fsP zpjRiI{rec4yH@z^fKgrZwVT~pX_ABGUQK}2Cl&XF){o(=ZaeSDkoA^P_yd(X`>@>e z1Q>TLWQvyM`umM;>;7~7)-y7o&>|#CqIrhDe8X*Bbz;ztEr+83 zUa$Af+S*zlu$)LBtQ4TIv$NApCwzM-1ppn{aGN`9^3l?q?!avY0b%1>S6CbX3zX@} zKjokvo1*9w2r9H_nC=`(jzvVKC-}!LZtM6Qi3t$Q0@%1G-57z|yiCBq;)I~x&={={ z3gZB3i0t7rWcf|yLGRa#qzIQB8?Jxsg+J$d^0@t0{%Q; zIVlC`?(Qc1_iY?X0ls!}czXhJ^hYeojD<4e0Q@_X)aR-b17TgNn~2|j^`z7nvOotu zUKx0OvXlBfVoBs$56DZ`yX~rWvfdv`1w6rfY+n~yAHiA@Bm;KUTBCV@%?%9= z3lmlV{_qs?0O$kS5=#NlpYxsbeG!~*{%)C>n7hsnuL>hGl&N-tr3?D(iPEo+R9`xR ze^@^BL2Wf!%zyX=pIsNpB=}E1xX1b*q9)r7EB&7rd+oGmDh$j13wt>&?2ZVS;c+m| zXeq(!!2Y2X;FG$#y2Ze9BGurr{NX9&0d}JkZH=V>0GnBq!oM>$8Q}b%8ZI+aEz;=c z(XR^*yCRJNDv}D=R6w_kxF&!yCqwHZPNuOn>pjTo+;)~f>40@8MSwy*aIVj8cQFHH z%sX}y!SgRMmdR=gu#IAXeSqbfnwlx`D!@2h0f+*98cP9?`a*S6zcDOc$z-AB6~hXr zvjC?A{MNMo$oJ1nvo!|g`Sn-45ghr#qk>T_VX6cQ29ExLk+nhc1Nr+*)L3r+oZtHE z4eqEZR44<|;9sGj8*THu&F)b#z*a*6;#wCljw#U8_V)I1J>XnYZr)aW#A5!|8!j%sx;4=>HNn3s&^eZe7U$^6$rykUk zG4F$f0J28NEFn$0ajh$AVGS|p`fFSR$i!WJeD{{6eN{_<<^CN;eOw|QU@FA`{X+%8 zSp8+*1a^4HBqzPchyxIVV4%`(mqgw9Vy`OasOWedxgj?7Om%8S^xJ{btg<0rCRhc2PfQ0)Sjwb-6foK2Y z)#3X&A=pLMY2hBZxdatP0a!p|;n{};1`r%ydt%2s2liFWwJA`40u)Fo0M=BJ0=yba z0e*B*cnTB+i^UnvO#=vjy2caHijj_Mf!>*b`|>f_Tfl-WoV{(#{gJH%$)qF!egNm+ zce)}{k6%A6kT)yVR4atX<9VaJygUdj*Ci4IaP!dA;^N{)I@zD2DF6oJS4IH(_+{RV z@9vD?=)RS{h@fzBiq|4w!T(Rc>^0gFT-K8L*|mr;0BFS9bZ=x2&Pt+Y@oXIf>v;gpyP`&xG8+(x0&`$gV1=*o(>ZPVe%bs#sJL4ZxTy z7%a4s|J_LI;`vbUN>_F%-3#N<4owR1JYl$&v0RX-0w8E8Ck2SQAO?XD21p+?bZBPd zf%jd|YrS!6ctalg>QkwV4;U@q*wFXzy>n+RGCZMbOf$10pfLaWC9nN=7zQ-(q1*JE zpZ7=1p-LoR!OG(KefbD}TLG{ltgEXF3t}o5%M;^O0JSB05i7vDXbOOAgP9IYSMV8+ z3xCwuI16z>s@Bw^-eFcFAGz3j)G`V zo_u{#iBbTp3GVFd{1GtBSdM$E^s#D3IQm)U_xsmGTNICFdhZ*c$mXggw9T4DkyPZx zp?eD^qnGwtZ{Hr-hcB;d%Kfbo-EQ|sH8nN+1H)|06H9KdE*y#n<;l&*OgsPZ!`|pXtunOxoJMZrs zF^3ll<1T{f3Q)k>Q%Mo^9l8P_Q}DL2V*zr?xx#fHSQSpsP~AkY zc)Z}nK1XIdfV`h9e-wcC1$_|MWegW2qW}{*dYFhxe4xd0{(1ZH_;+kSSpk= zLB(h&qQK&(OcS=7ZP3U7B!1CYHSwyeaG`~J^bM}R)-@QuN+`GA(t-`F&OSV3zriNj5<0zZfW3vV z+A1F#!G!i3X6_)t9iT>heUE@4S>t#dcCBiWDYQ!YzD||iw1`(BdHGtgFmo$f?N0h9ssMa za`_!yBBLh&=GP)U%KX2Ku{&W*l5dJvfpFopY17bCUDF?Mt->pQ25s#wXMfQBN%ZFlrav>2?Eu|nI@HxX744-BKU~>x z*2=?!R5u#wq@}eZjxP+A>i@ zB$NC9ba!{ZI(hQsK46pc|AncdKjs3NY4zn(aFJ%>TsNpKC}cuJvbFsQdjH$n+U^4; zr%bW2IW3j+CxQl1gbj{Wk9RMT_I)5UNF-bIhu8joR8>`VFfd8A)hHI+Aws0>4nzIGG%g3@?2D17Wa}u~?R>;@2*FgAiy? z)QxSYTO1C@sffhI3y5UW`g=Sci{j8#z#w6<&Io?fq5x)#G&)4meWI_(4gL$Dk74Oz8|*!gJk{B2lfbq4P5z6 zTkt#N8)SI*tuDH$$FU*@8Y&qfk#t#qWPaM)+keZ}zkxA0HJ!n4%*rs*PRzgBnwy(H zOJ3kpi3LQ`ocZ~*wzl?EV2&9`aXKo$39l1CEZ}mv9z;N_I`m}XL{g~$sQNk_j-PVo zrzuL`f5sF*1;e@*XsxcUUQ9RnHoz}ELLzDC`FXdjtn47>{<`&_kV){HDN*}fVugi; zE%dX4j_a^GXBO`xDw8OZiUlv+@rnI@Iwnn;)T+Jvt02?XKUyp>gI`D4I&tDeF9pQU zazHFC5+cKHdEkEkKNGfs-1A?@n9Df#kLCqbMyO1Af%^LTV~GlFRqjhBQzTjH14BxI z@79`{8fNQK1*OO+sn|B1u(z$&mh)u+$4o@rGBWiN5$cQ(mBe`!QxxkOEEZ z1QiMd0$U_2B$5pEak*TdR8>`-1}qV#9K7CF_59?7^^evmiqup!-Ecdqb)>;JpnAuJ z49N!DLL$4QJ}7v#x3{C! z*~=Je%B8?Jo`4uzs8lK{R905DkTm)qDjtx@7TE>wf3u{dWC>HBHh$UN^jr#jhYE;w zDpW%c&;d8r)YNpU&*$3=ZYS}8NG#sp-QB&VwzhU9Q=blPsiUGk?- z5h{eDMTs5{OrJh|7ID325b#J)JgUXc_;hr1te-Y*+FXP8mly@Fyi$N@9iw_Y;6!G~ z>2&^8lwkCNA1r{t|4K+%$YL}z)Q_o3APC+ zM%|`X8%j${59Xj(U*edTyg#0JKy9(!NDu5nz*ALKbqINa4Wb02Mr`nRb#=W(2Jk3g zfUw}^!s$%LNMSytJQJltsy;A-3mZ*J32JI;j?k1q=+FqKJ!JXcCh#Avfxk%$di8w& z*fAsI(1T)CB*OzYYf5k!=nw{oTP7qsG_qE8*#R$Tk7oH@obIgBid_>&8u*9G3{|rd zzzTQ}6Cg0gKuL;p#PIz=%q8C8)!yFzcjo*ansX0>zj`EOe1?@CC28RS@gO@yR^k~} zfjz1Cj7h{gGY!-8Fq&o{nI{2fdN2l@v2c-nICzw2Wa(_oh$Kx0{ zwb_<{D*qbW)E=I#t*uYeoX*iKzXE?LV_?*PKiVQ1T?ux^1XxifGh~2zDukd%e24dW8Z%&t;Pq@Cx{c z2#i&V6oruv1WXVLpcZv?bv>z5BJl>fWAzcMVQz@FK83|BJa0bk>}=FhohsWS;2%N> zRI$w7VM1kyXh8kMDQ_ljxk;@v7H^PUt53fVU@nOAY{JfM%=cBW>)<)8BTeg2r1+F z+ZEkG7bkK3o8W;ptMAe%PbJTlp6LL`w;)3ZKC2H2QM6g8V<>mWfT`AF`joeD1 z(sQB+iGhCSxZ!t<(aPWeaZBsAucH5Tyhm>7}_{C z@Uuk