From 993f659742c5fb5edbad7ebaa29d2ab92ea08a1b Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:02:57 -0600 Subject: [PATCH] feat: add support for Device Hardware json and svg graphics (#1449) * feat: add support for Device Hardware json and svg graphics Allows for better hardware device display names, graphics, and indication of support. * make detekt happy * Fix: Use first image name to find vector drawable Use the first image name from the `images` list (after removing the ".svg" suffix) to find the corresponding vector drawable resource. * Refactor: Update device detail layout Updated the device detail layout to group device-specific information under a "Device" category. Added a circular background with device-specific color behind the device icon. Moved hardware, support status details to the Device section. * Refactor: Move device hardware logic to MetricsViewModel Moves the logic for retrieving device hardware information and image resources from NodeDetail to MetricsViewModel. Also replaces id lookup with when statement for image resource id mapping. * fix: cache deviceHardwareList, add exception handling * refactor: mutable list unnecessary * default to hw_unknown device image --- app/src/main/assets/device_hardware.json | 764 ++++ .../geeksville/mesh/model/DeviceHardware.kt | 17 + .../geeksville/mesh/model/MetricsViewModel.kt | 73 +- .../java/com/geeksville/mesh/ui/NodeDetail.kt | 81 +- app/src/main/res/drawable/hw_diy.xml | 1631 +++++++++ .../hw_heltec_ht62_esp32c3_sx1262.xml | 1714 +++++++++ .../res/drawable/hw_heltec_mesh_node_t114.xml | 277 ++ .../hw_heltec_mesh_node_t114_case.xml | 179 + app/src/main/res/drawable/hw_heltec_v3.xml | 1141 ++++++ .../main/res/drawable/hw_heltec_v3_case.xml | 49 + .../drawable/hw_heltec_vision_master_e213.xml | 117 + .../drawable/hw_heltec_vision_master_e290.xml | 162 + .../drawable/hw_heltec_vision_master_t190.xml | 146 + .../res/drawable/hw_heltec_wireless_paper.xml | 428 +++ .../hw_heltec_wireless_paper_v1_0.xml | 428 +++ .../drawable/hw_heltec_wireless_tracker.xml | 1619 +++++++++ .../hw_heltec_wireless_tracker_v1_0.xml | 1619 +++++++++ .../main/res/drawable/hw_heltec_wsl_v3.xml | 1496 ++++++++ .../main/res/drawable/hw_nano_g2_ultra.xml | 185 + app/src/main/res/drawable/hw_pico.xml | 1717 +++++++++ app/src/main/res/drawable/hw_promicro.xml | 1555 +++++++++ app/src/main/res/drawable/hw_rak11310.xml | 1228 +++++++ app/src/main/res/drawable/hw_rak4631.xml | 1999 +++++++++++ app/src/main/res/drawable/hw_rak4631_case.xml | 263 ++ .../main/res/drawable/hw_rak_wismeshtap.xml | 180 + app/src/main/res/drawable/hw_rpipicow.xml | 1645 +++++++++ .../drawable/hw_seeed_sensecap_indicator.xml | 292 ++ .../main/res/drawable/hw_seeed_xiao_s3.xml | 711 ++++ app/src/main/res/drawable/hw_station_g2.xml | 437 +++ app/src/main/res/drawable/hw_t_deck.xml | 658 ++++ app/src/main/res/drawable/hw_t_echo.xml | 247 ++ app/src/main/res/drawable/hw_t_watch_s3.xml | 80 + app/src/main/res/drawable/hw_tbeam.xml | 2693 ++++++++++++++ .../main/res/drawable/hw_tbeam_s3_core.xml | 1583 +++++++++ app/src/main/res/drawable/hw_tlora_c6.xml | 515 +++ .../res/drawable/hw_tlora_t3s3_epaper.xml | 226 ++ .../main/res/drawable/hw_tlora_t3s3_v1.xml | 932 +++++ .../main/res/drawable/hw_tlora_v2_1_1_6.xml | 880 +++++ .../main/res/drawable/hw_tlora_v2_1_1_8.xml | 880 +++++ .../main/res/drawable/hw_tracker_t1000_e.xml | 259 ++ app/src/main/res/drawable/hw_unknown.xml | 138 + .../res/drawable/hw_wio_tracker_wm1110.xml | 2178 ++++++++++++ .../main/res/drawable/hw_wm1110_dev_kit.xml | 3080 +++++++++++++++++ 43 files changed, 36489 insertions(+), 13 deletions(-) create mode 100644 app/src/main/assets/device_hardware.json create mode 100644 app/src/main/java/com/geeksville/mesh/model/DeviceHardware.kt create mode 100644 app/src/main/res/drawable/hw_diy.xml create mode 100644 app/src/main/res/drawable/hw_heltec_ht62_esp32c3_sx1262.xml create mode 100644 app/src/main/res/drawable/hw_heltec_mesh_node_t114.xml create mode 100644 app/src/main/res/drawable/hw_heltec_mesh_node_t114_case.xml create mode 100644 app/src/main/res/drawable/hw_heltec_v3.xml create mode 100644 app/src/main/res/drawable/hw_heltec_v3_case.xml create mode 100644 app/src/main/res/drawable/hw_heltec_vision_master_e213.xml create mode 100644 app/src/main/res/drawable/hw_heltec_vision_master_e290.xml create mode 100644 app/src/main/res/drawable/hw_heltec_vision_master_t190.xml create mode 100644 app/src/main/res/drawable/hw_heltec_wireless_paper.xml create mode 100644 app/src/main/res/drawable/hw_heltec_wireless_paper_v1_0.xml create mode 100644 app/src/main/res/drawable/hw_heltec_wireless_tracker.xml create mode 100644 app/src/main/res/drawable/hw_heltec_wireless_tracker_v1_0.xml create mode 100644 app/src/main/res/drawable/hw_heltec_wsl_v3.xml create mode 100644 app/src/main/res/drawable/hw_nano_g2_ultra.xml create mode 100644 app/src/main/res/drawable/hw_pico.xml create mode 100644 app/src/main/res/drawable/hw_promicro.xml create mode 100644 app/src/main/res/drawable/hw_rak11310.xml create mode 100644 app/src/main/res/drawable/hw_rak4631.xml create mode 100644 app/src/main/res/drawable/hw_rak4631_case.xml create mode 100644 app/src/main/res/drawable/hw_rak_wismeshtap.xml create mode 100644 app/src/main/res/drawable/hw_rpipicow.xml create mode 100644 app/src/main/res/drawable/hw_seeed_sensecap_indicator.xml create mode 100644 app/src/main/res/drawable/hw_seeed_xiao_s3.xml create mode 100644 app/src/main/res/drawable/hw_station_g2.xml create mode 100644 app/src/main/res/drawable/hw_t_deck.xml create mode 100644 app/src/main/res/drawable/hw_t_echo.xml create mode 100644 app/src/main/res/drawable/hw_t_watch_s3.xml create mode 100644 app/src/main/res/drawable/hw_tbeam.xml create mode 100644 app/src/main/res/drawable/hw_tbeam_s3_core.xml create mode 100644 app/src/main/res/drawable/hw_tlora_c6.xml create mode 100644 app/src/main/res/drawable/hw_tlora_t3s3_epaper.xml create mode 100644 app/src/main/res/drawable/hw_tlora_t3s3_v1.xml create mode 100644 app/src/main/res/drawable/hw_tlora_v2_1_1_6.xml create mode 100644 app/src/main/res/drawable/hw_tlora_v2_1_1_8.xml create mode 100644 app/src/main/res/drawable/hw_tracker_t1000_e.xml create mode 100644 app/src/main/res/drawable/hw_unknown.xml create mode 100644 app/src/main/res/drawable/hw_wio_tracker_wm1110.xml create mode 100644 app/src/main/res/drawable/hw_wm1110_dev_kit.xml diff --git a/app/src/main/assets/device_hardware.json b/app/src/main/assets/device_hardware.json new file mode 100644 index 00000000..853bec3b --- /dev/null +++ b/app/src/main/assets/device_hardware.json @@ -0,0 +1,764 @@ +[ + { + "hwModel": 1, + "hwModelSlug": "TLORA_V2", + "platformioTarget": "tlora-v2", + "architecture": "esp32", + "activelySupported": false, + "displayName": "LILYGO T-LoRa V2", + "tags": [ + "LilyGo" + ] + }, + { + "hwModel": 2, + "hwModelSlug": "TLORA_V1", + "platformioTarget": "tlora-v1", + "architecture": "esp32", + "activelySupported": false, + "displayName": "LILYGO T-LoRa V1", + "tags": [ + "LilyGo" + ] + }, + { + "hwModel": 3, + "hwModelSlug": "TLORA_V2_1_1P6", + "platformioTarget": "tlora-v2-1-1_6", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 1, + "displayName": "LILYGO T-LoRa V2.1-1.6", + "tags": [ + "LilyGo" + ], + "images": [ + "tlora-v2-1-1_6.svg" + ] + }, + { + "hwModel": 4, + "hwModelSlug": "TBEAM", + "platformioTarget": "tbeam", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 1, + "displayName": "LILYGO T-Beam", + "tags": [ + "LilyGo" + ], + "images": [ + "tbeam.svg" + ] + }, + { + "hwModel": 5, + "hwModelSlug": "HELTEC_V2_0", + "platformioTarget": "heltec-v2_0", + "architecture": "esp32", + "activelySupported": false, + "displayName": "Heltec V2.0", + "tags": [ + "Heltec" + ] + }, + { + "hwModel": 6, + "hwModelSlug": "TBEAM_V0P7", + "platformioTarget": "tbeam0_7", + "architecture": "esp32", + "activelySupported": false, + "displayName": "LILYGO T-Beam V0.7", + "tags": [ + "LilyGo" + ] + }, + { + "hwModel": 7, + "hwModelSlug": "T_ECHO", + "platformioTarget": "t-echo", + "architecture": "nrf52840", + "supportLevel": 1, + "activelySupported": true, + "displayName": "LILYGO T-Echo", + "tags": [ + "LilyGo" + ], + "images": [ + "t-echo.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 8, + "hwModelSlug": "TLORA_V1_1P3", + "platformioTarget": "tlora-v1_3", + "architecture": "esp32", + "activelySupported": false, + "displayName": "LILYGO T-LoRa V1.1-1.3", + "tags": [ + "LilyGo" + ] + }, + { + "hwModel": 9, + "hwModelSlug": "RAK4631", + "platformioTarget": "rak4631", + "architecture": "nrf52840", + "activelySupported": true, + "supportLevel": 1, + "displayName": "RAK WisBlock 4631", + "tags": [ + "RAK" + ], + "images": [ + "rak4631.svg", + "rak4631_case.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 10, + "hwModelSlug": "HELTEC_V2_1", + "platformioTarget": "heltec-v2_1", + "architecture": "esp32", + "activelySupported": false, + "displayName": "Heltec V2.1", + "tags": [ + "Heltec" + ] + }, + { + "hwModel": 11, + "hwModelSlug": "HELTEC_V1", + "platformioTarget": "heltec-v1", + "architecture": "esp32", + "activelySupported": false, + "displayName": "Heltec V1", + "tags": [ + "Heltec" + ] + }, + { + "hwModel": 12, + "hwModelSlug": "TBEAM_S3_CORE", + "platformioTarget": "tbeam-s3-core", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "LILYGO T-Beam Supreme", + "tags": [ + "LilyGo" + ], + "images": [ + "tbeam-s3-core.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 13, + "hwModelSlug": "RAK11200", + "platformioTarget": "rak11200", + "architecture": "esp32", + "activelySupported": false, + "displayName": "RAK WisBlock 11200", + "tags": [ + "RAK" + ] + }, + { + "hwModel": 14, + "hwModelSlug": "NANO_G1", + "platformioTarget": "nano-g1", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 3, + "displayName": "Nano G1", + "tags": [ + "B&Q" + ] + }, + { + "hwModel": 15, + "hwModelSlug": "TLORA_V2_1_1P8", + "platformioTarget": "tlora-v2-1-1_8", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 2, + "displayName": "LILYGO T-LoRa V2.1-1.8", + "tags": [ + "LilyGo", + "2.4G LoRA" + ], + "images": [ + "tlora-v2-1-1_8.svg" + ] + }, + { + "hwModel": 16, + "hwModelSlug": "TLORA_T3_S3", + "platformioTarget": "tlora-t3s3-v1", + "architecture": "esp32-s3", + "activelySupported": true, + "displayName": "LILYGO T-LoRa T3-S3", + "supportLevel": 1, + "tags": [ + "LilyGo" + ], + "images": [ + "tlora-t3s3-v1.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 16, + "hwModelSlug": "TLORA_T3_S3", + "platformioTarget": "tlora-t3s3-epaper", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "LILYGO T-LoRa T3-S3 E-Ink", + "tags": [ + "LilyGo" + ], + "images": [ + "tlora-t3s3-epaper.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 17, + "hwModelSlug": "NANO_G1_EXPLORER", + "platformioTarget": "nano-g1-explorer", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 3, + "displayName": "Nano G1 Explorer", + "tags": [ + "B&Q" + ] + }, + { + "hwModel": 18, + "hwModelSlug": "NANO_G2_ULTRA", + "platformioTarget": "nano-g2-ultra", + "architecture": "nrf52840", + "activelySupported": true, + "supportLevel": 2, + "displayName": "Nano G2 Ultra", + "tags": [ + "B&Q" + ], + "requiresDfu": true, + "images": [ + "nano-g2-ultra.svg" + ] + }, + { + "hwModel": 21, + "hwModelSlug": "WIO_WM1110", + "platformioTarget": "wio-tracker-wm1110", + "architecture": "nrf52840", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Seeed Wio WM1110 Tracker", + "tags": [ + "Seeed" + ], + "images": [ + "wio-tracker-wm1110.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 25, + "hwModelSlug": "STATION_G1", + "platformioTarget": "station-g1", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 3, + "displayName": "Station G1", + "tags": [ + "B&Q" + ] + }, + { + "hwModel": 26, + "hwModelSlug": "RAK11310", + "platformioTarget": "rak11310", + "architecture": "rp2040", + "activelySupported": true, + "supportLevel": 2, + "displayName": "RAK WisBlock 11310", + "tags": [ + "RAK" + ], + "images": [ + "rak11310.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 29, + "hwModelSlug": "CANARYONE", + "platformioTarget": "canaryone", + "architecture": "nrf52840", + "activelySupported": true, + "supportLevel": 3, + "displayName": "Canary One", + "tags": [ + "Canary" + ], + "requiresDfu": true + }, + { + "hwModel": 30, + "hwModelSlug": "RP2040_LORA", + "platformioTarget": "rp2040-lora", + "architecture": "rp2040", + "activelySupported": true, + "supportLevel": 2, + "displayName": "RP2040 LoRa", + "tags": [ + "Waveshare" + ], + "requiresDfu": true + }, + { + "hwModel": 31, + "hwModelSlug": "STATION_G2", + "platformioTarget": "station-g2", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 2, + "displayName": "Station G2", + "tags": [ + "B&Q" + ], + "requiresDfu": true, + "images": [ + "station-g2.svg" + ] + }, + { + "hwModel": 39, + "hwModelSlug": "DIY_V1", + "platformioTarget": "meshtastic-diy-v1", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 3, + "displayName": "DIY V1", + "tags": [ + "DIY" + ], + "images": [ + "diy.svg" + ] + }, + { + "hwModel": 39, + "hwModelSlug": "HYDRA", + "platformioTarget": "hydra", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 3, + "displayName": "Hydra", + "tags": [ + "DIY" + ] + }, + { + "hwModel": 41, + "hwModelSlug": "DR_DEV", + "platformioTarget": "meshtastic-dr-dev", + "architecture": "esp32", + "activelySupported": false, + "displayName": "DR-DEV", + "tags": [ + "DIY" + ] + }, + { + "hwModel": 42, + "hwModelSlug": "M5STACK", + "platformioTarget": "m5stack-core", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 3, + "displayName": "M5 Stack", + "tags": [ + "M5Stack" + ] + }, + { + "hwModel": 43, + "hwModelSlug": "HELTEC_V3", + "platformioTarget": "heltec-v3", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Heltec V3", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-v3.svg", + "heltec-v3-case.svg" + ] + }, + { + "hwModel": 44, + "hwModelSlug": "HELTEC_WSL_V3", + "platformioTarget": "heltec-wsl-v3", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Heltec Wireless Stick Lite V3", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-wsl-v3.svg" + ] + }, + { + "hwModel": 47, + "hwModelSlug": "RPI_PICO", + "platformioTarget": "pico", + "architecture": "rp2040", + "activelySupported": true, + "supportLevel": 3, + "displayName": "Raspberry Pi Pico", + "tags": [ + "RPi", + "DIY" + ], + "requiresDfu": true, + "images": [ + "pico.svg" + ] + }, + { + "hwModel": 47, + "hwModelSlug": "RPI_PICO", + "platformioTarget": "picow", + "architecture": "rp2040", + "activelySupported": true, + "supportLevel": 3, + "displayName": "Raspberry Pi Pico W", + "tags": [ + "RPi", + "DIY" + ], + "requiresDfu": true, + "images": [ + "rpipicow.svg" + ] + }, + { + "hwModel": 48, + "hwModelSlug": "HELTEC_WIRELESS_TRACKER", + "platformioTarget": "heltec-wireless-tracker", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Heltec Wireless Tracker V1.1", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-wireless-tracker.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 58, + "hwModelSlug": "HELTEC_WIRELESS_TRACKER_V1_0", + "platformioTarget": "heltec-wireless-tracker-V1-0", + "architecture": "esp32-s3", + "activelySupported": false, + "supportLevel": 3, + "displayName": "Heltec Wireless Tracker V1.0", + "images": [ + "heltec-wireless-tracker.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 49, + "hwModelSlug": "HELTEC_WIRELESS_PAPER", + "platformioTarget": "heltec-wireless-paper", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Heltec Wireless Paper", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-wireless-paper.svg" + ] + }, + { + "hwModel": 50, + "hwModelSlug": "T_DECK", + "platformioTarget": "t-deck", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "LILYGO T-Deck", + "tags": [ + "LilyGo" + ], + "images": [ + "t-deck.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 51, + "hwModelSlug": "T_WATCH_S3", + "platformioTarget": "t-watch-s3", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "LILYGO T-Watch S3", + "tags": [ + "LilyGo" + ], + "images": [ + "t-watch-s3.svg" + ] + }, + { + "hwModel": 52, + "hwModelSlug": "PICOMPUTER_S3", + "platformioTarget": "picomputer-s3", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 3, + "displayName": "Pi Computer S3" + }, + { + "hwModel": 53, + "hwModelSlug": "HELTEC_HT62", + "platformioTarget": "heltec-ht62-esp32c3-sx1262", + "architecture": "esp32-c3", + "supportLevel": 1, + "activelySupported": true, + "displayName": "Heltec HT62", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-ht62-esp32c3-sx1262.svg" + ] + }, + { + "hwModel": 57, + "hwModelSlug": "HELTEC_WIRELESS_PAPER_V1_0", + "platformioTarget": "heltec-wireless-paper-v1_0", + "architecture": "esp32-s3", + "activelySupported": false, + "supportLevel": 3, + "tags": [ + "Heltec" + ], + "displayName": "Heltec Wireless Paper V1.0", + "images": [ + "heltec-wireless-paper-v1_0.svg" + ] + }, + { + "hwModel": 59, + "hwModelSlug": "UNPHONE", + "platformioTarget": "unphone", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 3, + "displayName": "unPhone", + "requiresDfu": true + }, + { + "hwModel": 48, + "hwModelSlug": "HELTEC_WIRELESS_TRACKER", + "platformioTarget": "tracksenger", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 3, + "displayName": "TrackSenger (small TFT)", + "requiresDfu": true + }, + { + "hwModel": 48, + "hwModelSlug": "HELTEC_WIRELESS_TRACKER", + "platformioTarget": "tracksenger-lcd", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 3, + "displayName": "TrackSenger (big TFT)", + "requiresDfu": true + }, + { + "hwModel": 48, + "hwModelSlug": "HELTEC_WIRELESS_TRACKER", + "platformioTarget": "tracksenger-oled", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 3, + "displayName": "TrackSenger (big OLED)" + }, + { + "hwModel": 61, + "hwModelSlug": "CDEBYTE_EORA_S3", + "platformioTarget": "CDEBYTE_EoRa-S3", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 3, + "displayName": "EBYTE EoRa-S3", + "tags": [ + "EByte" + ], + "requiresDfu": true + }, + { + "hwModel": 64, + "hwModelSlug": "RADIOMASTER_900_BANDIT_NANO", + "platformioTarget": "radiomaster_900_bandit_nano", + "architecture": "esp32", + "activelySupported": true, + "supportLevel": 2, + "displayName": "RadioMaster 900 Bandit Nano", + "tags": [ + "RadioMaster" + ] + }, + { + "hwModel": 66, + "hwModelSlug": "HELTEC_VISION_MASTER_T190", + "platformioTarget": "heltec-vision-master-t190", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Heltec Vision Master T190", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-vision-master-t190.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 67, + "hwModelSlug": "HELTEC_VISION_MASTER_E213", + "platformioTarget": "heltec-vision-master-e213", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Heltec Vision Master E213", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-vision-master-e213.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 68, + "hwModelSlug": "HELTEC_VISION_MASTER_E290", + "platformioTarget": "heltec-vision-master-e290", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Heltec Vision Master E290", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-vision-master-e290.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 69, + "hwModelSlug": "HELTEC_MESH_NODE_T114", + "platformioTarget": "heltec-mesh-node-t114", + "architecture": "nrf52840", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Heltec Mesh Node T114", + "tags": [ + "Heltec" + ], + "images": [ + "heltec-mesh-node-t114.svg", + "heltec-mesh-node-t114-case.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 70, + "hwModelSlug": "SENSECAP_INDICATOR", + "platformioTarget": "seeed-sensecap-indicator", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Seeed SenseCAP Indicator", + "tags": [ + "Seeed" + ], + "images": [ + "seeed-sensecap-indicator.svg" + ] + }, + { + "hwModel": 71, + "hwModelSlug": "TRACKER_T1000_E", + "platformioTarget": "tracker-t1000-e", + "architecture": "nrf52840", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Seeed Card Tracker T1000-E", + "tags": [ + "Seeed" + ], + "images": [ + "tracker-t1000-e.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 72, + "hwModelSlug": "Seeed_XIAO_S3", + "platformioTarget": "seeed-xiao-s3", + "architecture": "esp32-s3", + "activelySupported": true, + "supportLevel": 1, + "displayName": "Seeed Xiao ESP32-S3", + "tags": [ + "Seeed" + ], + "images": [ + "seeed-xiao-s3.svg" + ], + "requiresDfu": true + }, + { + "hwModel": 84, + "hwModelSlug": "WISMESH_TAP", + "platformioTarget": "rak_wismeshtap", + "architecture": "nrf52840", + "activelySupported": false, + "supportLevel": 1, + "displayName": "RAK WisMesh Tap", + "tags": [ + "RAK" + ], + "images": [ + "rak-wismeshtap.svg" + ], + "requiresDfu": true + } +] diff --git a/app/src/main/java/com/geeksville/mesh/model/DeviceHardware.kt b/app/src/main/java/com/geeksville/mesh/model/DeviceHardware.kt new file mode 100644 index 00000000..85a727cf --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/model/DeviceHardware.kt @@ -0,0 +1,17 @@ +package com.geeksville.mesh.model + +import kotlinx.serialization.Serializable + +@Serializable +data class DeviceHardware( + val hwModel: Int, + val hwModelSlug: String, + val platformioTarget: String, + val architecture: String, + val activelySupported: Boolean, + val supportLevel: Int? = null, + val displayName: String, + val tags: List? = listOf(), + val images: List? = listOf(), + val requiresDfu: Boolean? = null +) diff --git a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt index 1a4be6f9..4ac46c0e 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt @@ -20,6 +20,7 @@ package com.geeksville.mesh.model import android.app.Application import android.content.SharedPreferences import android.net.Uri +import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -29,6 +30,7 @@ import androidx.lifecycle.viewModelScope import androidx.navigation.toRoute import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits import com.geeksville.mesh.CoroutineDispatchers +import com.geeksville.mesh.MeshProtos.HardwareModel import com.geeksville.mesh.MeshProtos.MeshPacket import com.geeksville.mesh.MeshProtos.Position import com.geeksville.mesh.Portnums.PortNum @@ -56,9 +58,11 @@ import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json import java.io.BufferedWriter import java.io.FileNotFoundException import java.io.FileWriter +import java.io.IOException import java.text.SimpleDateFormat import java.util.Locale import java.util.concurrent.TimeUnit @@ -75,6 +79,8 @@ data class MetricsState( val tracerouteRequests: List = emptyList(), val tracerouteResults: List = emptyList(), val positionLogs: List = emptyList(), + val deviceHardware: DeviceHardware? = null, + @DrawableRes val deviceImageRes: Int = R.drawable.hw_unknown, ) { fun hasDeviceMetrics() = deviceMetrics.isNotEmpty() fun hasEnvironmentMetrics() = environmentMetrics.isNotEmpty() @@ -212,7 +218,17 @@ class MetricsViewModel @Inject constructor( radioConfigRepository.nodeDBbyNum .mapLatest { nodes -> nodes[destNum] } .distinctUntilChanged() - .onEach { node -> _state.update { state -> state.copy(node = node) } } + .onEach { node -> + _state.update { state -> state.copy(node = node) } + node?.user?.hwModel?.let { hwModel -> + _state.update { state -> + state.copy( + deviceHardware = getDeviceHardwareFromHardwareModel(hwModel), + deviceImageRes = getDeviceVectorImageFromHardwareModel(hwModel) + ) + } + } + } .launchIn(viewModelScope) radioConfigRepository.deviceProfileFlow.onEach { profile -> @@ -316,4 +332,59 @@ class MetricsViewModel @Inject constructor( errormsg("Can't write file error: ${ex.message}") } } + + private var deviceHardwareList: List = listOf() + private fun getDeviceHardwareFromHardwareModel( + hwModel: HardwareModel + ): DeviceHardware? { + if (deviceHardwareList.isEmpty()) { + try { + val json = + app.assets.open("device_hardware.json").bufferedReader().use { it.readText() } + deviceHardwareList = Json.decodeFromString>(json) + } catch (ex: IOException) { + errormsg("Can't read device_hardware.json error: ${ex.message}") + } + } + return deviceHardwareList.find { it.hwModel == hwModel.number } + } + + @Suppress("CyclomaticComplexMethod") + private fun getDeviceVectorImageFromHardwareModel(hwModel: HardwareModel): Int { + return when (hwModel) { + HardwareModel.DIY_V1 -> R.drawable.hw_diy + HardwareModel.HELTEC_HT62 -> R.drawable.hw_heltec_ht62_esp32c3_sx1262 + HardwareModel.HELTEC_MESH_NODE_T114 -> R.drawable.hw_heltec_mesh_node_t114 + HardwareModel.HELTEC_V3 -> R.drawable.hw_heltec_v3 + HardwareModel.HELTEC_VISION_MASTER_E213 -> R.drawable.hw_heltec_vision_master_e213 + HardwareModel.HELTEC_VISION_MASTER_E290 -> R.drawable.hw_heltec_vision_master_e290 + HardwareModel.HELTEC_VISION_MASTER_T190 -> R.drawable.hw_heltec_vision_master_t190 + HardwareModel.HELTEC_WIRELESS_PAPER -> R.drawable.hw_heltec_wireless_paper + HardwareModel.HELTEC_WIRELESS_TRACKER -> R.drawable.hw_heltec_wireless_tracker + HardwareModel.HELTEC_WIRELESS_TRACKER_V1_0 -> R.drawable.hw_heltec_wireless_tracker_v1_0 + HardwareModel.HELTEC_WSL_V3 -> R.drawable.hw_heltec_wsl_v3 + HardwareModel.NANO_G2_ULTRA -> R.drawable.hw_nano_g2_ultra + HardwareModel.RPI_PICO -> R.drawable.hw_pico + HardwareModel.NRF52_PROMICRO_DIY -> R.drawable.hw_promicro + HardwareModel.RAK11310 -> R.drawable.hw_rak11310 + HardwareModel.RAK4631 -> R.drawable.hw_rak4631 + HardwareModel.RPI_PICO2 -> R.drawable.hw_rpipicow + HardwareModel.SENSECAP_INDICATOR -> R.drawable.hw_seeed_sensecap_indicator + HardwareModel.SEEED_XIAO_S3 -> R.drawable.hw_seeed_xiao_s3 + HardwareModel.STATION_G2 -> R.drawable.hw_station_g2 + HardwareModel.T_DECK -> R.drawable.hw_t_deck + HardwareModel.T_ECHO -> R.drawable.hw_t_echo + HardwareModel.T_WATCH_S3 -> R.drawable.hw_t_watch_s3 + HardwareModel.TBEAM -> R.drawable.hw_tbeam + HardwareModel.LILYGO_TBEAM_S3_CORE -> R.drawable.hw_tbeam_s3_core + HardwareModel.TLORA_C6 -> R.drawable.hw_tlora_c6 + HardwareModel.TLORA_T3_S3 -> R.drawable.hw_tlora_t3s3_v1 + HardwareModel.TLORA_V2_1_1P6 -> R.drawable.hw_tlora_v2_1_1_6 + HardwareModel.TLORA_V2_1_1P8 -> R.drawable.hw_tlora_v2_1_1_8 + HardwareModel.TRACKER_T1000_E -> R.drawable.hw_tracker_t1000_e + HardwareModel.WIO_WM1110 -> R.drawable.hw_wio_tracker_wm1110 + HardwareModel.WISMESH_TAP -> R.drawable.hw_rak_wismeshtap + else -> R.drawable.hw_unknown + } + } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt b/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt index 7e1c226a..f17ea7f9 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt @@ -15,10 +15,12 @@ * along with this program. If not, see . */ -@file:Suppress("TooManyFunctions") +@file:Suppress("TooManyFunctions", "LongMethod") package com.geeksville.mesh.ui +import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -36,6 +38,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card import androidx.compose.material.CircularProgressIndicator @@ -64,6 +67,7 @@ import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.SignalCellularAlt import androidx.compose.material.icons.filled.Speed import androidx.compose.material.icons.filled.Thermostat +import androidx.compose.material.icons.filled.Verified import androidx.compose.material.icons.filled.WaterDrop import androidx.compose.material.icons.filled.Work import androidx.compose.material.icons.outlined.Navigation @@ -71,6 +75,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector @@ -98,8 +103,8 @@ import kotlin.math.ln @Composable fun NodeDetailScreen( - viewModel: MetricsViewModel = hiltViewModel(), modifier: Modifier = Modifier, + viewModel: MetricsViewModel = hiltViewModel(), onNavigate: (Any) -> Unit, ) { val state by viewModel.state.collectAsStateWithLifecycle() @@ -124,15 +129,20 @@ fun NodeDetailScreen( @Composable private fun NodeDetailList( + modifier: Modifier = Modifier, node: NodeEntity, metricsState: MetricsState, - modifier: Modifier = Modifier, onNavigate: (Any) -> Unit = {}, ) { LazyColumn( modifier = modifier.fillMaxSize(), contentPadding = PaddingValues(horizontal = 16.dp), ) { + item { + PreferenceCategory("Device") { + DeviceDetailsContent(metricsState) + } + } item { PreferenceCategory("Details") { NodeDetailsContent(node) @@ -176,7 +186,12 @@ private fun NodeDetailList( } @Composable -private fun NodeDetailRow(label: String, icon: ImageVector, value: String) { +private fun NodeDetailRow( + label: String, + icon: ImageVector, + value: String, + iconTint: Color = MaterialTheme.colors.onSurface +) { Row( modifier = Modifier .fillMaxWidth() @@ -186,7 +201,8 @@ private fun NodeDetailRow(label: String, icon: ImageVector, value: String) { Icon( imageVector = icon, contentDescription = label, - modifier = Modifier.size(24.dp) + modifier = Modifier.size(24.dp), + tint = iconTint ) Spacer(modifier = Modifier.width(8.dp)) Text(label) @@ -196,7 +212,50 @@ private fun NodeDetailRow(label: String, icon: ImageVector, value: String) { } @Composable -private fun NodeDetailsContent(node: NodeEntity) { +private fun DeviceDetailsContent( + state: MetricsState, +) { + val node = state.node ?: return + val deviceHardware = state.deviceHardware ?: return + val deviceImageRes = state.deviceImageRes + val hwModelName = deviceHardware.displayName + val isSupported = deviceHardware.activelySupported + Box( + modifier = Modifier + .size(100.dp) + .padding(4.dp) + .clip(CircleShape) + .background( + color = Color(node.colors.second).copy(alpha = .5f), + shape = CircleShape + ), + contentAlignment = Alignment.Center + ) { + Image( + modifier = Modifier.padding(16.dp), + imageVector = ImageVector.vectorResource(deviceImageRes), + contentDescription = hwModelName, + ) + } + NodeDetailRow( + label = "Hardware", + icon = Icons.Default.Router, + value = hwModelName + ) + if (isSupported) { + NodeDetailRow( + label = "Supported", + icon = Icons.Default.Verified, + value = "", + iconTint = Color.Green + ) + } +} + +@Composable +private fun NodeDetailsContent( + node: NodeEntity, +) { if (node.mismatchKey) { Row(verticalAlignment = Alignment.CenterVertically) { Icon( @@ -232,11 +291,6 @@ private fun NodeDetailsContent(node: NodeEntity) { icon = Icons.Default.Work, value = node.user.role.name ) - NodeDetailRow( - label = "Hardware", - icon = Icons.Default.Router, - value = node.user.hwModel.name - ) if (node.deviceMetrics.uptimeSeconds > 0) { NodeDetailRow( label = "Uptime", @@ -541,6 +595,9 @@ private fun NodeDetailsPreview( node: NodeEntity ) { AppTheme { - NodeDetailList(node, MetricsState.Empty) + NodeDetailList( + node = node, + metricsState = MetricsState.Empty, + ) } } diff --git a/app/src/main/res/drawable/hw_diy.xml b/app/src/main/res/drawable/hw_diy.xml new file mode 100644 index 00000000..feedd56c --- /dev/null +++ b/app/src/main/res/drawable/hw_diy.xml @@ -0,0 +1,1631 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_ht62_esp32c3_sx1262.xml b/app/src/main/res/drawable/hw_heltec_ht62_esp32c3_sx1262.xml new file mode 100644 index 00000000..1a0c1977 --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_ht62_esp32c3_sx1262.xml @@ -0,0 +1,1714 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_mesh_node_t114.xml b/app/src/main/res/drawable/hw_heltec_mesh_node_t114.xml new file mode 100644 index 00000000..457ffd6c --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_mesh_node_t114.xml @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_mesh_node_t114_case.xml b/app/src/main/res/drawable/hw_heltec_mesh_node_t114_case.xml new file mode 100644 index 00000000..e95e13e6 --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_mesh_node_t114_case.xml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_v3.xml b/app/src/main/res/drawable/hw_heltec_v3.xml new file mode 100644 index 00000000..2031cb19 --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_v3.xml @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_v3_case.xml b/app/src/main/res/drawable/hw_heltec_v3_case.xml new file mode 100644 index 00000000..5e444b6f --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_v3_case.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_vision_master_e213.xml b/app/src/main/res/drawable/hw_heltec_vision_master_e213.xml new file mode 100644 index 00000000..017b80bd --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_vision_master_e213.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_vision_master_e290.xml b/app/src/main/res/drawable/hw_heltec_vision_master_e290.xml new file mode 100644 index 00000000..f617ecd7 --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_vision_master_e290.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_vision_master_t190.xml b/app/src/main/res/drawable/hw_heltec_vision_master_t190.xml new file mode 100644 index 00000000..6fd688f1 --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_vision_master_t190.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_wireless_paper.xml b/app/src/main/res/drawable/hw_heltec_wireless_paper.xml new file mode 100644 index 00000000..66db18fc --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_wireless_paper.xml @@ -0,0 +1,428 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_wireless_paper_v1_0.xml b/app/src/main/res/drawable/hw_heltec_wireless_paper_v1_0.xml new file mode 100644 index 00000000..66db18fc --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_wireless_paper_v1_0.xml @@ -0,0 +1,428 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_wireless_tracker.xml b/app/src/main/res/drawable/hw_heltec_wireless_tracker.xml new file mode 100644 index 00000000..74d14932 --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_wireless_tracker.xml @@ -0,0 +1,1619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_wireless_tracker_v1_0.xml b/app/src/main/res/drawable/hw_heltec_wireless_tracker_v1_0.xml new file mode 100644 index 00000000..74d14932 --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_wireless_tracker_v1_0.xml @@ -0,0 +1,1619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_heltec_wsl_v3.xml b/app/src/main/res/drawable/hw_heltec_wsl_v3.xml new file mode 100644 index 00000000..f4246b21 --- /dev/null +++ b/app/src/main/res/drawable/hw_heltec_wsl_v3.xml @@ -0,0 +1,1496 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_nano_g2_ultra.xml b/app/src/main/res/drawable/hw_nano_g2_ultra.xml new file mode 100644 index 00000000..60bfb06d --- /dev/null +++ b/app/src/main/res/drawable/hw_nano_g2_ultra.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_pico.xml b/app/src/main/res/drawable/hw_pico.xml new file mode 100644 index 00000000..eb3935ab --- /dev/null +++ b/app/src/main/res/drawable/hw_pico.xml @@ -0,0 +1,1717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_promicro.xml b/app/src/main/res/drawable/hw_promicro.xml new file mode 100644 index 00000000..2f69e14c --- /dev/null +++ b/app/src/main/res/drawable/hw_promicro.xml @@ -0,0 +1,1555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_rak11310.xml b/app/src/main/res/drawable/hw_rak11310.xml new file mode 100644 index 00000000..5d39943f --- /dev/null +++ b/app/src/main/res/drawable/hw_rak11310.xml @@ -0,0 +1,1228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_rak4631.xml b/app/src/main/res/drawable/hw_rak4631.xml new file mode 100644 index 00000000..ff6225c0 --- /dev/null +++ b/app/src/main/res/drawable/hw_rak4631.xml @@ -0,0 +1,1999 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_rak4631_case.xml b/app/src/main/res/drawable/hw_rak4631_case.xml new file mode 100644 index 00000000..d937ffbc --- /dev/null +++ b/app/src/main/res/drawable/hw_rak4631_case.xml @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_rak_wismeshtap.xml b/app/src/main/res/drawable/hw_rak_wismeshtap.xml new file mode 100644 index 00000000..fb9084b4 --- /dev/null +++ b/app/src/main/res/drawable/hw_rak_wismeshtap.xml @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_rpipicow.xml b/app/src/main/res/drawable/hw_rpipicow.xml new file mode 100644 index 00000000..96107856 --- /dev/null +++ b/app/src/main/res/drawable/hw_rpipicow.xml @@ -0,0 +1,1645 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_seeed_sensecap_indicator.xml b/app/src/main/res/drawable/hw_seeed_sensecap_indicator.xml new file mode 100644 index 00000000..9aecd2b9 --- /dev/null +++ b/app/src/main/res/drawable/hw_seeed_sensecap_indicator.xml @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_seeed_xiao_s3.xml b/app/src/main/res/drawable/hw_seeed_xiao_s3.xml new file mode 100644 index 00000000..242e2d73 --- /dev/null +++ b/app/src/main/res/drawable/hw_seeed_xiao_s3.xml @@ -0,0 +1,711 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_station_g2.xml b/app/src/main/res/drawable/hw_station_g2.xml new file mode 100644 index 00000000..72f187ae --- /dev/null +++ b/app/src/main/res/drawable/hw_station_g2.xml @@ -0,0 +1,437 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_t_deck.xml b/app/src/main/res/drawable/hw_t_deck.xml new file mode 100644 index 00000000..d13a6f1e --- /dev/null +++ b/app/src/main/res/drawable/hw_t_deck.xml @@ -0,0 +1,658 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_t_echo.xml b/app/src/main/res/drawable/hw_t_echo.xml new file mode 100644 index 00000000..c9642c1b --- /dev/null +++ b/app/src/main/res/drawable/hw_t_echo.xml @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_t_watch_s3.xml b/app/src/main/res/drawable/hw_t_watch_s3.xml new file mode 100644 index 00000000..9da42a48 --- /dev/null +++ b/app/src/main/res/drawable/hw_t_watch_s3.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_tbeam.xml b/app/src/main/res/drawable/hw_tbeam.xml new file mode 100644 index 00000000..1ab61b31 --- /dev/null +++ b/app/src/main/res/drawable/hw_tbeam.xml @@ -0,0 +1,2693 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_tbeam_s3_core.xml b/app/src/main/res/drawable/hw_tbeam_s3_core.xml new file mode 100644 index 00000000..8387e402 --- /dev/null +++ b/app/src/main/res/drawable/hw_tbeam_s3_core.xml @@ -0,0 +1,1583 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_tlora_c6.xml b/app/src/main/res/drawable/hw_tlora_c6.xml new file mode 100644 index 00000000..dad87ed5 --- /dev/null +++ b/app/src/main/res/drawable/hw_tlora_c6.xml @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_tlora_t3s3_epaper.xml b/app/src/main/res/drawable/hw_tlora_t3s3_epaper.xml new file mode 100644 index 00000000..37cc0e04 --- /dev/null +++ b/app/src/main/res/drawable/hw_tlora_t3s3_epaper.xml @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_tlora_t3s3_v1.xml b/app/src/main/res/drawable/hw_tlora_t3s3_v1.xml new file mode 100644 index 00000000..42e5695a --- /dev/null +++ b/app/src/main/res/drawable/hw_tlora_t3s3_v1.xml @@ -0,0 +1,932 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_tlora_v2_1_1_6.xml b/app/src/main/res/drawable/hw_tlora_v2_1_1_6.xml new file mode 100644 index 00000000..123a7838 --- /dev/null +++ b/app/src/main/res/drawable/hw_tlora_v2_1_1_6.xml @@ -0,0 +1,880 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_tlora_v2_1_1_8.xml b/app/src/main/res/drawable/hw_tlora_v2_1_1_8.xml new file mode 100644 index 00000000..123a7838 --- /dev/null +++ b/app/src/main/res/drawable/hw_tlora_v2_1_1_8.xml @@ -0,0 +1,880 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_tracker_t1000_e.xml b/app/src/main/res/drawable/hw_tracker_t1000_e.xml new file mode 100644 index 00000000..2efed467 --- /dev/null +++ b/app/src/main/res/drawable/hw_tracker_t1000_e.xml @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_unknown.xml b/app/src/main/res/drawable/hw_unknown.xml new file mode 100644 index 00000000..e12d55de --- /dev/null +++ b/app/src/main/res/drawable/hw_unknown.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_wio_tracker_wm1110.xml b/app/src/main/res/drawable/hw_wio_tracker_wm1110.xml new file mode 100644 index 00000000..27ac4e7d --- /dev/null +++ b/app/src/main/res/drawable/hw_wio_tracker_wm1110.xml @@ -0,0 +1,2178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/hw_wm1110_dev_kit.xml b/app/src/main/res/drawable/hw_wm1110_dev_kit.xml new file mode 100644 index 00000000..94c9bdf2 --- /dev/null +++ b/app/src/main/res/drawable/hw_wm1110_dev_kit.xml @@ -0,0 +1,3080 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +