Przeglądaj źródła

[FL-1783] Power service refactoring (#718)

* settings power: introduce power settings app
* power: move power API to separate file
* settings power: implement reboot scene
* settings power: add power off scene
* assets: add crying dolphin, fix Subghz assets names
* settings power: fix power off scene GUI
* settings power: add battery info scene
* power: add cli to application on start hook
* power: remove power from main menu
* power: move to power service folder
* power service: rework power off logic
* power: add pubsub events
* bt: subscribe to battery level change, update characteristic
* application: change order of Settings applications
* gui: add bubble element
* power: gui improvements
* application: rename Notification -> LCD and notifications
* Applications: menu order according to documentation and add missing power cli init
* settings power: add disconnect USB scene
* power cli: notify user to disconnect USB after poweroff
* Power: update poweroff message in cli

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
gornekich 4 lat temu
rodzic
commit
d3b58f732f
35 zmienionych plików z 1073 dodań i 577 usunięć
  1. 21 9
      applications/applications.c
  2. 16 0
      applications/bt/bt_service/bt.c
  3. 3 1
      applications/bt/bt_service/bt_i.h
  4. 11 0
      applications/gui/elements.c
  5. 21 26
      applications/gui/elements.h
  6. 0 278
      applications/power/power.c
  7. 0 19
      applications/power/power.h
  8. 22 16
      applications/power/power_cli.c
  9. 1 4
      applications/power/power_cli.h
  10. 179 0
      applications/power/power_service/power.c
  11. 65 0
      applications/power/power_service/power.h
  12. 31 0
      applications/power/power_service/power_api.c
  13. 37 0
      applications/power/power_service/power_i.h
  14. 57 0
      applications/power/power_service/views/power_off.c
  15. 13 0
      applications/power/power_service/views/power_off.h
  16. 82 0
      applications/power/power_settings_app/power_settings_app.c
  17. 31 0
      applications/power/power_settings_app/power_settings_app.h
  18. 17 0
      applications/power/power_settings_app/scenes/power_settinfs_scene_usb_disconnect.c
  19. 30 0
      applications/power/power_settings_app/scenes/power_settings_scene.c
  20. 29 0
      applications/power/power_settings_app/scenes/power_settings_scene.h
  21. 34 0
      applications/power/power_settings_app/scenes/power_settings_scene_battery_info.c
  22. 5 0
      applications/power/power_settings_app/scenes/power_settings_scene_config.h
  23. 48 0
      applications/power/power_settings_app/scenes/power_settings_scene_power_off.c
  24. 52 0
      applications/power/power_settings_app/scenes/power_settings_scene_reboot.c
  25. 64 0
      applications/power/power_settings_app/scenes/power_settings_scene_start.c
  26. 126 0
      applications/power/power_settings_app/views/battery_info.c
  27. 22 0
      applications/power/power_settings_app/views/battery_info.h
  28. 0 131
      applications/power/power_views.c
  29. 0 38
      applications/power/power_views.h
  30. 0 0
      assets/compiled/assets_icons.c
  31. 56 55
      assets/compiled/assets_icons.h
  32. BIN
      assets/icons/Settings/Cry_dolph_55x52.png
  33. 0 0
      assets/icons/SubGhz/Lock_7x8.png
  34. 0 0
      assets/icons/SubGhz/Quest_7x8.png
  35. 0 0
      assets/icons/SubGhz/Unlock_7x8.png

+ 21 - 9
applications/applications.c

@@ -46,12 +46,14 @@ extern void lfrfid_cli_init();
 extern void nfc_cli_init();
 extern void storage_cli_init();
 extern void subghz_cli_init();
+extern void power_cli_init();
 
 // Settings
 extern int32_t notification_settings_app(void* p);
 extern int32_t storage_settings_app(void* p);
 extern int32_t bt_settings_app(void* p);
 extern int32_t about_settings_app(void* p);
+extern int32_t power_settings_app(void* p);
 
 const FlipperApplication FLIPPER_SERVICES[] = {
 /* Services */
@@ -143,18 +145,14 @@ const size_t FLIPPER_SERVICES_COUNT = sizeof(FLIPPER_SERVICES) / sizeof(FlipperA
 // Main menu APP
 const FlipperApplication FLIPPER_APPS[] = {
 
-#ifdef APP_IBUTTON
-    {.app = ibutton_app, .name = "iButton", .stack_size = 2048, .icon = &A_iButton_14},
+#ifdef APP_SUBGHZ
+    {.app = subghz_app, .name = "Sub-GHz", .stack_size = 2048, .icon = &A_Sub1ghz_14},
 #endif
 
 #ifdef APP_NFC
     {.app = nfc_app, .name = "NFC", .stack_size = 4096, .icon = &A_NFC_14},
 #endif
 
-#ifdef APP_SUBGHZ
-    {.app = subghz_app, .name = "Sub-GHz", .stack_size = 2048, .icon = &A_Sub1ghz_14},
-#endif
-
 #ifdef APP_LF_RFID
     {.app = lfrfid_app, .name = "125 kHz RFID", .stack_size = 2048, .icon = &A_125khz_14},
 #endif
@@ -163,6 +161,10 @@ const FlipperApplication FLIPPER_APPS[] = {
     {.app = irda_app, .name = "Infrared", .stack_size = 1024 * 3, .icon = &A_Infrared_14},
 #endif
 
+#ifdef APP_IBUTTON
+    {.app = ibutton_app, .name = "iButton", .stack_size = 2048, .icon = &A_iButton_14},
+#endif
+
 #ifdef APP_GPIO_TEST
     {.app = gpio_test_app, .name = "GPIO", .stack_size = 1024, .icon = &A_GPIO_14},
 #endif
@@ -192,6 +194,9 @@ const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[] = {
 #ifdef SRV_BT
     bt_cli_init,
 #endif
+#ifdef SRV_POWER
+    power_cli_init,
+#endif
 #ifdef SRV_STORAGE
     storage_cli_init,
 #endif
@@ -258,16 +263,23 @@ const FlipperApplication FLIPPER_ARCHIVE =
 
 // Settings menu
 const FlipperApplication FLIPPER_SETTINGS_APPS[] = {
+#ifdef SRV_BT
+    {.app = bt_settings_app, .name = "Bluetooth", .stack_size = 1024, .icon = NULL},
+#endif
+
 #ifdef SRV_NOTIFICATION
-    {.app = notification_settings_app, .name = "Notification", .stack_size = 1024, .icon = NULL},
+    {.app = notification_settings_app,
+     .name = "LCD and notifications",
+     .stack_size = 1024,
+     .icon = NULL},
 #endif
 
 #ifdef SRV_STORAGE
     {.app = storage_settings_app, .name = "Storage", .stack_size = 2048, .icon = NULL},
 #endif
 
-#ifdef SRV_BT
-    {.app = bt_settings_app, .name = "Bluetooth", .stack_size = 1024, .icon = NULL},
+#ifdef SRV_POWER
+    {.app = power_settings_app, .name = "Power", .stack_size = 1024, .icon = NULL},
 #endif
 
 #ifdef APP_ABOUT

+ 16 - 0
applications/bt/bt_service/bt.c

@@ -26,6 +26,17 @@ static void bt_pin_code_show_event_handler(Bt* bt, uint32_t pin) {
     string_clear(pin_str);
 }
 
+static void bt_battery_level_changed_callback(const void* _event, void* context) {
+    furi_assert(_event);
+    furi_assert(context);
+
+    Bt* bt = context;
+    const PowerEvent* event = _event;
+    if(event->type == PowerEventTypeBatteryLevelChanged) {
+        bt_update_battery_level(bt, event->data.battery_level);
+    }
+}
+
 Bt* bt_alloc() {
     Bt* bt = furi_alloc(sizeof(Bt));
     // Load settings
@@ -45,6 +56,11 @@ Bt* bt_alloc() {
     bt->dialogs = furi_record_open("dialogs");
     bt->dialog_message = dialog_message_alloc();
 
+    // Power
+    bt->power = furi_record_open("power");
+    PubSub* power_pubsub = power_get_pubsub(bt->power);
+    subscribe_pubsub(power_pubsub, bt_battery_level_changed_callback, bt);
+
     return bt;
 }
 

+ 3 - 1
applications/bt/bt_service/bt_i.h

@@ -9,7 +9,8 @@
 #include <gui/view_port.h>
 #include <gui/view.h>
 
-#include <applications/dialogs/dialogs.h>
+#include <dialogs/dialogs.h>
+#include <power/power_service/power.h>
 
 #include "../bt_settings.h"
 
@@ -36,4 +37,5 @@ struct Bt {
     ViewPort* statusbar_view_port;
     DialogsApp* dialogs;
     DialogMessage* dialog_message;
+    Power* power;
 };

+ 11 - 0
applications/gui/elements.c

@@ -327,6 +327,17 @@ void elements_slightly_rounded_box(
     canvas_draw_rbox(canvas, x, y, width, height, 1);
 }
 
+void elements_bubble(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
+    furi_assert(canvas);
+    canvas_draw_rframe(canvas, x + 4, y, width, height, 3);
+    uint8_t y_corner = y + height * 2 / 3;
+    canvas_draw_line(canvas, x, y_corner, x + 4, y_corner - 4);
+    canvas_draw_line(canvas, x, y_corner, x + 4, y_corner + 4);
+    canvas_set_color(canvas, ColorWhite);
+    canvas_draw_line(canvas, x + 4, y_corner - 3, x + 4, y_corner + 3);
+    canvas_set_color(canvas, ColorBlack);
+}
+
 void elements_string_fit_width(Canvas* canvas, string_t string, uint8_t width) {
     furi_assert(canvas);
     furi_assert(string);

+ 21 - 26
applications/gui/elements.h

@@ -8,8 +8,7 @@
 extern "C" {
 #endif
 
-/*
- * Draw progress bar.
+/** Draw progress bar.
  * @param x - progress bar position on X axis
  * @param y - progress bar position on Y axis
  * @param width - progress bar width
@@ -24,8 +23,7 @@ void elements_progress_bar(
     uint8_t progress,
     uint8_t total);
 
-/*
- * Draw scrollbar on canvas at specific position.
+/** Draw scrollbar on canvas at specific position.
  * @param x - scrollbar position on X axis
  * @param y - scrollbar position on Y axis
  * @param height - scrollbar height
@@ -40,41 +38,35 @@ void elements_scrollbar_pos(
     uint16_t pos,
     uint16_t total);
 
-/*
- * Draw scrollbar on canvas.
+/** Draw scrollbar on canvas.
  * width 3px, height equal to canvas height
  * @param pos - current element of total elements
  * @param total - total elements
  */
 void elements_scrollbar(Canvas* canvas, uint16_t pos, uint16_t total);
 
-/*
- * Draw rounded frame
+/** Draw rounded frame
  * @param x, y - top left corner coordinates
  * @param width, height - frame width and height
  */
 void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
 
-/*
- * Draw button in left corner
+/** Draw button in left corner
  * @param str - button text
  */
 void elements_button_left(Canvas* canvas, const char* str);
 
-/*
- * Draw button in right corner
+/** Draw button in right corner
  * @param str - button text
  */
 void elements_button_right(Canvas* canvas, const char* str);
 
-/*
- * Draw button in center
+/** Draw button in center
  * @param str - button text
  */
 void elements_button_center(Canvas* canvas, const char* str);
 
-/*
- * Draw aligned multiline text
+/** Draw aligned multiline text
  * @param x, y - coordinates based on align param
  * @param horizontal, vertical - aligment of multiline text
  * @param text - string (possible multiline)
@@ -87,22 +79,19 @@ void elements_multiline_text_aligned(
     Align vertical,
     const char* text);
 
-/*
- * Draw multiline text
+/** Draw multiline text
  * @param x, y - top left corner coordinates
  * @param text - string (possible multiline)
  */
 void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* text);
 
-/*
- * Draw framed multiline text
+/** Draw framed multiline text
  * @param x, y - top left corner coordinates
  * @param text - string (possible multiline)
  */
 void elements_multiline_text_framed(Canvas* canvas, uint8_t x, uint8_t y, const char* text);
 
-/*
- * Draw slightly rounded frame
+/** Draw slightly rounded frame
  * @param x, y - top left corner coordinates
  * @param width, height - size of frame
  */
@@ -113,8 +102,7 @@ void elements_slightly_rounded_frame(
     uint8_t width,
     uint8_t height);
 
-/*
- * Draw slightly rounded box
+/** Draw slightly rounded box
  * @param x, y - top left corner coordinates
  * @param width, height - size of box
  */
@@ -125,8 +113,15 @@ void elements_slightly_rounded_box(
     uint8_t width,
     uint8_t height);
 
-/*
- * Trim string buffer to fit width in pixels
+/** Draw bubble frame for text
+ * @param x - left x coordinates
+ * @param y - top y coordinate
+ * @param width - bubble width
+ * @param height - bubble height
+ */
+void elements_bubble(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
+
+/** Trim string buffer to fit width in pixels
  * @param string - string to trim
  * @param width - max width
  */

+ 0 - 278
applications/power/power.c

@@ -1,278 +0,0 @@
-#include "power.h"
-#include "power_cli.h"
-#include "power_views.h"
-
-#include <furi.h>
-#include <furi-hal.h>
-
-#include <menu/menu.h>
-#include <menu/menu_item.h>
-
-#include <gui/gui.h>
-#include <gui/icon_animation.h>
-#include <gui/view_port.h>
-#include <gui/view.h>
-#include <gui/view_dispatcher.h>
-#include <gui/modules/dialog.h>
-#include <assets_icons.h>
-#include <stm32wbxx.h>
-
-#include <notification/notification-messages.h>
-#include <applications/bt/bt_service/bt.h>
-
-#define POWER_OFF_TIMEOUT 30
-
-typedef enum {
-    PowerStateNotCharging,
-    PowerStateCharging,
-    PowerStateCharged,
-} PowerState;
-
-struct Power {
-    ViewDispatcher* view_dispatcher;
-    View* info_view;
-    View* off_view;
-    View* disconnect_view;
-
-    ViewPort* battery_view_port;
-
-    Dialog* dialog;
-
-    ValueMutex* menu_vm;
-    Cli* cli;
-    Bt* bt;
-    MenuItem* menu;
-
-    PowerState state;
-};
-
-void power_draw_battery_callback(Canvas* canvas, void* context) {
-    furi_assert(context);
-    Power* power = context;
-    canvas_draw_icon(canvas, 0, 0, &I_Battery_26x8);
-    with_view_model(
-        power->info_view, (PowerInfoModel * model) {
-            canvas_draw_box(canvas, 2, 2, (float)model->charge / 100 * 20, 4);
-            return false;
-        });
-}
-
-uint32_t power_info_back_callback(void* context) {
-    return VIEW_NONE;
-}
-
-void power_menu_off_callback(void* context) {
-    Power* power = context;
-    power_off(power);
-}
-
-void power_menu_reset_dialog_result(DialogResult result, void* context) {
-    Power* power = context;
-    if(result == DialogResultLeft) {
-        power_reboot(power, PowerBootModeDfu);
-    } else if(result == DialogResultRight) {
-        power_reboot(power, PowerBootModeNormal);
-    } else if(result == DialogResultBack) {
-        view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE);
-    }
-}
-
-void power_menu_reset_callback(void* context) {
-    Power* power = context;
-    dialog_set_result_callback(power->dialog, power_menu_reset_dialog_result);
-    dialog_set_header_text(power->dialog, "Reboot type");
-    dialog_set_text(power->dialog, "Reboot where?");
-    dialog_set_left_button_text(power->dialog, "DFU");
-    dialog_set_right_button_text(power->dialog, "OS");
-    view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewDialog);
-}
-
-void power_menu_enable_otg_callback(void* context) {
-    furi_hal_power_enable_otg();
-}
-
-void power_menu_disable_otg_callback(void* context) {
-    furi_hal_power_disable_otg();
-}
-
-void power_menu_info_callback(void* context) {
-    Power* power = context;
-    view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewInfo);
-}
-
-Power* power_alloc() {
-    Power* power = furi_alloc(sizeof(Power));
-
-    power->state = PowerStateNotCharging;
-
-    power->menu_vm = furi_record_open("menu");
-
-    power->cli = furi_record_open("cli");
-    power_cli_init(power->cli, power);
-
-    power->bt = furi_record_open("bt");
-
-    power->menu = menu_item_alloc_menu("Power", icon_animation_alloc(&A_Power_14));
-    menu_item_subitem_add(
-        power->menu, menu_item_alloc_function("Off", NULL, power_menu_off_callback, power));
-    menu_item_subitem_add(
-        power->menu, menu_item_alloc_function("Reboot", NULL, power_menu_reset_callback, power));
-    menu_item_subitem_add(
-        power->menu,
-        menu_item_alloc_function("Enable OTG", NULL, power_menu_enable_otg_callback, power));
-    menu_item_subitem_add(
-        power->menu,
-        menu_item_alloc_function("Disable OTG", NULL, power_menu_disable_otg_callback, power));
-    menu_item_subitem_add(
-        power->menu, menu_item_alloc_function("Info", NULL, power_menu_info_callback, power));
-
-    power->view_dispatcher = view_dispatcher_alloc();
-    power->info_view = view_alloc();
-    view_allocate_model(power->info_view, ViewModelTypeLockFree, sizeof(PowerInfoModel));
-    view_set_draw_callback(power->info_view, power_info_draw_callback);
-    view_set_previous_callback(power->info_view, power_info_back_callback);
-    view_dispatcher_add_view(power->view_dispatcher, PowerViewInfo, power->info_view);
-
-    power->off_view = view_alloc();
-    view_allocate_model(power->off_view, ViewModelTypeLockFree, sizeof(PowerOffModel));
-    view_set_draw_callback(power->off_view, power_off_draw_callback);
-    view_dispatcher_add_view(power->view_dispatcher, PowerViewOff, power->off_view);
-
-    power->disconnect_view = view_alloc();
-    view_set_draw_callback(power->disconnect_view, power_disconnect_draw_callback);
-    view_dispatcher_add_view(power->view_dispatcher, PowerViewDisconnect, power->disconnect_view);
-
-    power->dialog = dialog_alloc();
-    dialog_set_context(power->dialog, power);
-    view_dispatcher_add_view(
-        power->view_dispatcher, PowerViewDialog, dialog_get_view(power->dialog));
-
-    power->battery_view_port = view_port_alloc();
-
-    view_port_set_width(power->battery_view_port, icon_get_width(&I_Battery_26x8));
-    view_port_draw_callback_set(power->battery_view_port, power_draw_battery_callback, power);
-    return power;
-}
-
-void power_free(Power* power) {
-    furi_assert(power);
-    free(power);
-}
-
-void power_off(Power* power) {
-    furi_assert(power);
-    furi_hal_power_off();
-    view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewDisconnect);
-}
-
-void power_reboot(Power* power, PowerBootMode mode) {
-    if(mode == PowerBootModeNormal) {
-        furi_hal_boot_set_mode(FuriHalBootModeNormal);
-    } else if(mode == PowerBootModeDfu) {
-        furi_hal_boot_set_mode(FuriHalBootModeDFU);
-    }
-    furi_hal_power_reset();
-}
-
-static void power_charging_indication_handler(Power* power, NotificationApp* notifications) {
-    if(furi_hal_power_is_charging()) {
-        if(furi_hal_power_get_pct() == 100) {
-            if(power->state != PowerStateCharged) {
-                notification_internal_message(notifications, &sequence_charged);
-                power->state = PowerStateCharged;
-            }
-        } else {
-            if(power->state != PowerStateCharging) {
-                notification_internal_message(notifications, &sequence_charging);
-                power->state = PowerStateCharging;
-            }
-        }
-    }
-
-    if(!furi_hal_power_is_charging()) {
-        if(power->state != PowerStateNotCharging) {
-            notification_internal_message(notifications, &sequence_not_charging);
-            power->state = PowerStateNotCharging;
-        }
-    }
-}
-
-int32_t power_srv(void* p) {
-    (void)p;
-    Power* power = power_alloc();
-
-    NotificationApp* notifications = furi_record_open("notification");
-    Gui* gui = furi_record_open("gui");
-    gui_add_view_port(gui, power->battery_view_port, GuiLayerStatusBarRight);
-    view_dispatcher_attach_to_gui(power->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
-
-    with_value_mutex(
-        power->menu_vm, (Menu * menu) { menu_item_add(menu, power->menu); });
-
-    furi_record_create("power", power);
-    uint8_t battery_level = 0;
-    uint8_t battery_level_prev = 0;
-    while(1) {
-        bool battery_low = false;
-
-        with_view_model(
-            power->info_view, (PowerInfoModel * model) {
-                model->charge = furi_hal_power_get_pct();
-                battery_level = model->charge;
-                model->health = furi_hal_power_get_bat_health_pct();
-                model->capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
-                model->capacity_full = furi_hal_power_get_battery_full_capacity();
-                model->current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger);
-                model->current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge);
-                model->voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger);
-                model->voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge);
-                model->voltage_vbus = furi_hal_power_get_usb_voltage();
-                model->temperature_charger =
-                    furi_hal_power_get_battery_temperature(FuriHalPowerICCharger);
-                model->temperature_gauge =
-                    furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge);
-
-                if(model->charge == 0 && model->voltage_vbus < 4.0f) {
-                    battery_low = true;
-                }
-
-                return true;
-            });
-
-        with_view_model(
-            power->off_view, (PowerOffModel * model) {
-                if(battery_low) {
-                    if(model->poweroff_tick == 0) {
-                        model->poweroff_tick =
-                            osKernelGetTickCount() + osKernelGetTickFreq() * POWER_OFF_TIMEOUT;
-                    } else {
-                        if(osKernelGetTickCount() > model->poweroff_tick) {
-                            power_off(power);
-                        }
-                    }
-                } else {
-                    model->poweroff_tick = 0;
-                }
-
-                if(model->battery_low != battery_low) {
-                    model->battery_low = battery_low;
-                    view_dispatcher_switch_to_view(
-                        power->view_dispatcher, battery_low ? PowerViewOff : VIEW_NONE);
-                }
-                return true;
-            });
-
-        power_charging_indication_handler(power, notifications);
-
-        if(battery_level_prev != battery_level) {
-            battery_level_prev = battery_level;
-            bt_update_battery_level(power->bt, battery_level);
-        }
-
-        view_port_update(power->battery_view_port);
-
-        osDelay(1024);
-    }
-
-    return 0;
-}

+ 0 - 19
applications/power/power.h

@@ -1,19 +0,0 @@
-#pragma once
-
-typedef struct Power Power;
-
-typedef enum {
-    PowerBootModeNormal,
-    PowerBootModeDfu,
-} PowerBootMode;
-
-/** Power off device
- * @param power - Power instance
- */
-void power_off(Power* power);
-
-/** Reboot device
- * @param power - Power instance
- * @param mode - PowerBootMode
- */
-void power_reboot(Power* power, PowerBootMode mode);

+ 22 - 16
applications/power/power_cli.c

@@ -1,29 +1,31 @@
 #include "power_cli.h"
+
+#include <power/power_service/power.h>
+#include <cli/cli.h>
 #include <furi-hal.h>
 
 void power_cli_poweroff(Cli* cli, string_t args, void* context) {
-    Power* power = context;
-    power_off(power);
+    power_off();
+    printf("It's now safe to disconnect USB from your flipper\r\n");
+    while(cli_getc(cli)) {
+    }
 }
 
 void power_cli_reboot(Cli* cli, string_t args, void* context) {
-    Power* power = context;
-    power_reboot(power, PowerBootModeNormal);
+    power_reboot(PowerBootModeNormal);
 }
 
 void power_cli_dfu(Cli* cli, string_t args, void* context) {
-    Power* power = context;
-    power_reboot(power, PowerBootModeDfu);
+    power_reboot(PowerBootModeDfu);
 }
 
 void power_cli_factory_reset(Cli* cli, string_t args, void* context) {
-    Power* power = context;
     printf("All data will be lost. Are you sure (y/n)?\r\n");
     char c = cli_getc(cli);
     if(c == 'y' || c == 'Y') {
         printf("Data will be wiped after reboot.\r\n");
         furi_hal_boot_set_flags(FuriHalBootFlagFactoryReset);
-        power_reboot(power, PowerBootModeNormal);
+        power_reboot(PowerBootModeNormal);
     } else {
         printf("Safe choice.\r\n");
     }
@@ -53,13 +55,17 @@ void power_cli_ext(Cli* cli, string_t args, void* context) {
     }
 }
 
-void power_cli_init(Cli* cli, Power* power) {
-    cli_add_command(cli, "poweroff", CliCommandFlagParallelSafe, power_cli_poweroff, power);
-    cli_add_command(cli, "reboot", CliCommandFlagParallelSafe, power_cli_reboot, power);
+void power_cli_init() {
+    Cli* cli = furi_record_open("cli");
+
+    cli_add_command(cli, "poweroff", CliCommandFlagParallelSafe, power_cli_poweroff, NULL);
+    cli_add_command(cli, "reboot", CliCommandFlagParallelSafe, power_cli_reboot, NULL);
     cli_add_command(
-        cli, "factory_reset", CliCommandFlagParallelSafe, power_cli_factory_reset, power);
-    cli_add_command(cli, "dfu", CliCommandFlagParallelSafe, power_cli_dfu, power);
-    cli_add_command(cli, "power_info", CliCommandFlagParallelSafe, power_cli_info, power);
-    cli_add_command(cli, "power_otg", CliCommandFlagParallelSafe, power_cli_otg, power);
-    cli_add_command(cli, "power_ext", CliCommandFlagParallelSafe, power_cli_ext, power);
+        cli, "factory_reset", CliCommandFlagParallelSafe, power_cli_factory_reset, NULL);
+    cli_add_command(cli, "dfu", CliCommandFlagParallelSafe, power_cli_dfu, NULL);
+    cli_add_command(cli, "power_info", CliCommandFlagParallelSafe, power_cli_info, NULL);
+    cli_add_command(cli, "power_otg", CliCommandFlagParallelSafe, power_cli_otg, NULL);
+    cli_add_command(cli, "power_ext", CliCommandFlagParallelSafe, power_cli_ext, NULL);
+
+    furi_record_close("cli");
 }

+ 1 - 4
applications/power/power_cli.h

@@ -1,6 +1,3 @@
 #pragma once
 
-#include <cli/cli.h>
-#include "power.h"
-
-void power_cli_init(Cli* cli, Power* power);
+void power_cli_init();

+ 179 - 0
applications/power/power_service/power.c

@@ -0,0 +1,179 @@
+#include "power_i.h"
+#include "views/power_off.h"
+
+#include <furi.h>
+#include <furi-hal.h>
+#include <gui/view_port.h>
+#include <gui/view.h>
+
+#define POWER_OFF_TIMEOUT 90
+
+void power_draw_battery_callback(Canvas* canvas, void* context) {
+    furi_assert(context);
+    Power* power = context;
+    canvas_draw_icon(canvas, 0, 0, &I_Battery_26x8);
+    canvas_draw_box(canvas, 2, 2, power->info.charge / 5, 4);
+}
+
+static ViewPort* power_battery_view_port_alloc(Power* power) {
+    ViewPort* battery_view_port = view_port_alloc();
+    view_port_set_width(battery_view_port, icon_get_width(&I_Battery_26x8));
+    view_port_draw_callback_set(battery_view_port, power_draw_battery_callback, power);
+    gui_add_view_port(power->gui, battery_view_port, GuiLayerStatusBarRight);
+    return battery_view_port;
+}
+
+Power* power_alloc() {
+    Power* power = furi_alloc(sizeof(Power));
+
+    // Records
+    power->notification = furi_record_open("notification");
+    power->gui = furi_record_open("gui");
+
+    // Pubsub
+    init_pubsub(&power->event_pubsub);
+
+    // State initialization
+    power->state = PowerStateNotCharging;
+    power->battery_low = false;
+    power->power_off_timeout = POWER_OFF_TIMEOUT;
+    power->info_mtx = osMutexNew(NULL);
+
+    // Gui
+    power->view_dispatcher = view_dispatcher_alloc();
+    power->power_off = power_off_alloc();
+    view_dispatcher_add_view(
+        power->view_dispatcher, PowerViewOff, power_off_get_view(power->power_off));
+    view_dispatcher_attach_to_gui(
+        power->view_dispatcher, power->gui, ViewDispatcherTypeFullscreen);
+
+    // Battery view port
+    power->battery_view_port = power_battery_view_port_alloc(power);
+
+    return power;
+}
+
+void power_free(Power* power) {
+    furi_assert(power);
+
+    // Records
+    furi_record_close("notification");
+    furi_record_close("gui");
+
+    // Gui
+    view_dispatcher_remove_view(power->view_dispatcher, PowerViewOff);
+    power_off_free(power->power_off);
+    view_port_free(power->battery_view_port);
+
+    // State
+    osMutexDelete(power->info_mtx);
+    free(power);
+}
+
+static void power_check_charging_state(Power* power) {
+    if(furi_hal_power_is_charging()) {
+        if(power->info.charge == 100) {
+            if(power->state != PowerStateCharged) {
+                notification_internal_message(power->notification, &sequence_charged);
+                power->state = PowerStateCharged;
+                power->event.type = PowerEventTypeFullyCharged;
+                notify_pubsub(&power->event_pubsub, &power->event);
+            }
+        } else {
+            if(power->state != PowerStateCharging) {
+                notification_internal_message(power->notification, &sequence_charging);
+                power->state = PowerStateCharging;
+                power->event.type = PowerEventTypeStartCharging;
+                notify_pubsub(&power->event_pubsub, &power->event);
+            }
+        }
+    } else {
+        if(power->state != PowerStateNotCharging) {
+            notification_internal_message(power->notification, &sequence_not_charging);
+            power->state = PowerStateNotCharging;
+            power->event.type = PowerEventTypeStopCharging;
+            notify_pubsub(&power->event_pubsub, &power->event);
+        }
+    }
+}
+
+static void power_update_info(Power* power) {
+    osMutexAcquire(power->info_mtx, osWaitForever);
+    PowerInfo* info = &power->info;
+
+    info->charge = furi_hal_power_get_pct();
+    info->health = furi_hal_power_get_bat_health_pct();
+    info->capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
+    info->capacity_full = furi_hal_power_get_battery_full_capacity();
+    info->current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger);
+    info->current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge);
+    info->voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger);
+    info->voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge);
+    info->voltage_vbus = furi_hal_power_get_usb_voltage();
+    info->temperature_charger = furi_hal_power_get_battery_temperature(FuriHalPowerICCharger);
+    info->temperature_gauge = furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge);
+
+    osMutexRelease(power->info_mtx);
+}
+
+static void power_check_low_battery(Power* power) {
+    // Check battery charge and vbus voltage
+    if((power->info.charge == 0) && (power->info.voltage_vbus < 4.0f)) {
+        if(!power->battery_low) {
+            view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewOff);
+        }
+        power->battery_low = true;
+    } else {
+        if(power->battery_low) {
+            view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE);
+            power->power_off_timeout = POWER_OFF_TIMEOUT;
+        }
+        power->battery_low = false;
+    }
+    // If battery low, update view and switch off power after timeout
+    if(power->battery_low) {
+        if(power->power_off_timeout) {
+            power_off_set_time_left(power->power_off, power->power_off_timeout--);
+        } else {
+            power_off();
+        }
+    }
+}
+
+static void power_check_battery_level_change(Power* power) {
+    if(power->battery_level != power->info.charge) {
+        power->battery_level = power->info.charge;
+        power->event.type = PowerEventTypeBatteryLevelChanged;
+        power->event.data.battery_level = power->battery_level;
+        notify_pubsub(&power->event_pubsub, &power->event);
+    }
+}
+
+int32_t power_srv(void* p) {
+    (void)p;
+    Power* power = power_alloc();
+    furi_record_create("power", power);
+
+    while(1) {
+        // Update data from gauge and charger
+        power_update_info(power);
+
+        // Check low battery level
+        power_check_low_battery(power);
+
+        // Check and notify about charging state
+        power_check_charging_state(power);
+
+        // Check and notify about battery level change
+        power_check_battery_level_change(power);
+
+        // Update battery view port
+        view_port_update(power->battery_view_port);
+
+        osDelay(1000);
+    }
+
+    power_free(power);
+
+    return 0;
+}

+ 65 - 0
applications/power/power_service/power.h

@@ -0,0 +1,65 @@
+#pragma once
+
+#include <stdint.h>
+#include <furi/pubsub.h>
+
+typedef struct Power Power;
+
+typedef enum {
+    PowerBootModeNormal,
+    PowerBootModeDfu,
+} PowerBootMode;
+
+typedef enum {
+    PowerEventTypeStopCharging,
+    PowerEventTypeStartCharging,
+    PowerEventTypeFullyCharged,
+    PowerEventTypeBatteryLevelChanged,
+} PowerEventType;
+
+typedef union {
+    uint8_t battery_level;
+} PowerEventData;
+
+typedef struct {
+    PowerEventType type;
+    PowerEventData data;
+} PowerEvent;
+
+typedef struct {
+    float current_charger;
+    float current_gauge;
+
+    float voltage_charger;
+    float voltage_gauge;
+    float voltage_vbus;
+
+    uint32_t capacity_remaining;
+    uint32_t capacity_full;
+
+    float temperature_charger;
+    float temperature_gauge;
+
+    uint8_t charge;
+    uint8_t health;
+} PowerInfo;
+
+/** Power off device
+ */
+void power_off();
+
+/** Reboot device
+ * @param mode - PowerBootMode
+ */
+void power_reboot(PowerBootMode mode);
+
+/** Get power info
+ * @param power - Power instance
+ * @param info - PowerInfo instance
+ */
+void power_get_info(Power* power, PowerInfo* info);
+
+/** Get power event pubsub handler
+ * @param power - Power instance
+ */
+PubSub* power_get_pubsub(Power* power);

+ 31 - 0
applications/power/power_service/power_api.c

@@ -0,0 +1,31 @@
+#include "power_i.h"
+#include <furi.h>
+#include "furi-hal-power.h"
+#include "furi-hal-boot.h"
+
+void power_off() {
+    furi_hal_power_off();
+}
+
+void power_reboot(PowerBootMode mode) {
+    if(mode == PowerBootModeNormal) {
+        furi_hal_boot_set_mode(FuriHalBootModeNormal);
+    } else if(mode == PowerBootModeDfu) {
+        furi_hal_boot_set_mode(FuriHalBootModeDFU);
+    }
+    furi_hal_power_reset();
+}
+
+void power_get_info(Power* power, PowerInfo* info) {
+    furi_assert(power);
+    furi_assert(info);
+
+    osMutexAcquire(power->info_mtx, osWaitForever);
+    memcpy(info, &power->info, sizeof(power->info));
+    osMutexRelease(power->info_mtx);
+}
+
+PubSub* power_get_pubsub(Power* power) {
+    furi_assert(power);
+    return &power->event_pubsub;
+}

+ 37 - 0
applications/power/power_service/power_i.h

@@ -0,0 +1,37 @@
+#pragma once
+
+#include "power.h"
+
+#include <stdint.h>
+#include <gui/view_dispatcher.h>
+#include <gui/gui.h>
+#include "views/power_off.h"
+
+#include <notification/notification-messages.h>
+
+typedef enum {
+    PowerStateNotCharging,
+    PowerStateCharging,
+    PowerStateCharged,
+} PowerState;
+
+struct Power {
+    ViewDispatcher* view_dispatcher;
+    PowerOff* power_off;
+
+    ViewPort* battery_view_port;
+    Gui* gui;
+    NotificationApp* notification;
+    PubSub event_pubsub;
+    PowerEvent event;
+
+    PowerState state;
+    PowerInfo info;
+    osMutexId_t info_mtx;
+
+    bool battery_low;
+    uint8_t battery_level;
+    uint8_t power_off_timeout;
+};
+
+typedef enum { PowerViewOff } PowerView;

+ 57 - 0
applications/power/power_service/views/power_off.c

@@ -0,0 +1,57 @@
+#include "power_off.h"
+#include <furi.h>
+#include <gui/elements.h>
+
+struct PowerOff {
+    View* view;
+};
+
+typedef struct {
+    uint32_t time_left_sec;
+} PowerOffModel;
+
+static void power_off_draw_callback(Canvas* canvas, void* _model) {
+    furi_assert(_model);
+    PowerOffModel* model = _model;
+    char buff[32];
+
+    canvas_set_color(canvas, ColorBlack);
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str_aligned(canvas, 64, 1, AlignCenter, AlignTop, "Battery low!");
+    canvas_draw_icon(canvas, 0, 18, &I_BatteryBody_52x28);
+    canvas_draw_icon(canvas, 16, 25, &I_FaceNopower_29x14);
+    elements_bubble(canvas, 54, 17, 70, 30);
+    canvas_set_font(canvas, FontSecondary);
+    elements_multiline_text_aligned(
+        canvas, 70, 23, AlignLeft, AlignTop, "Connect me\n to charger.");
+    snprintf(buff, sizeof(buff), "Poweroff in %lds.", model->time_left_sec);
+    canvas_draw_str_aligned(canvas, 64, 60, AlignCenter, AlignBottom, buff);
+}
+
+PowerOff* power_off_alloc() {
+    PowerOff* power_off = furi_alloc(sizeof(PowerOff));
+    power_off->view = view_alloc();
+    view_allocate_model(power_off->view, ViewModelTypeLocking, sizeof(PowerOffModel));
+    view_set_draw_callback(power_off->view, power_off_draw_callback);
+    return power_off;
+}
+
+void power_off_free(PowerOff* power_off) {
+    furi_assert(power_off);
+    view_free(power_off->view);
+    free(power_off);
+}
+
+View* power_off_get_view(PowerOff* power_off) {
+    furi_assert(power_off);
+    return power_off->view;
+}
+
+void power_off_set_time_left(PowerOff* power_off, uint8_t time_left) {
+    furi_assert(power_off);
+    with_view_model(
+        power_off->view, (PowerOffModel * model) {
+            model->time_left_sec = time_left;
+            return true;
+        });
+}

+ 13 - 0
applications/power/power_service/views/power_off.h

@@ -0,0 +1,13 @@
+#pragma once
+
+typedef struct PowerOff PowerOff;
+
+#include <gui/view.h>
+
+PowerOff* power_off_alloc();
+
+void power_off_free(PowerOff* power_off);
+
+View* power_off_get_view(PowerOff* power_off);
+
+void power_off_set_time_left(PowerOff* power_off, uint8_t time_left);

+ 82 - 0
applications/power/power_settings_app/power_settings_app.c

@@ -0,0 +1,82 @@
+#include "power_settings_app.h"
+
+static bool power_settings_custom_event_callback(void* context, uint32_t event) {
+    furi_assert(context);
+    PowerSettingsApp* app = context;
+    return scene_manager_handle_custom_event(app->scene_manager, event);
+}
+
+static bool power_settings_back_event_callback(void* context) {
+    furi_assert(context);
+    PowerSettingsApp* app = context;
+    return scene_manager_handle_back_event(app->scene_manager);
+}
+
+static void power_settings_tick_event_callback(void* context) {
+    furi_assert(context);
+    PowerSettingsApp* app = context;
+    scene_manager_handle_tick_event(app->scene_manager);
+}
+
+PowerSettingsApp* power_settings_app_alloc() {
+    PowerSettingsApp* app = furi_alloc(sizeof(PowerSettingsApp));
+
+    // Records
+    app->gui = furi_record_open("gui");
+    app->power = furi_record_open("power");
+
+    // View dispatcher
+    app->view_dispatcher = view_dispatcher_alloc();
+    app->scene_manager = scene_manager_alloc(&power_settings_scene_handlers, app);
+    view_dispatcher_enable_queue(app->view_dispatcher);
+    view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
+    view_dispatcher_set_custom_event_callback(
+        app->view_dispatcher, power_settings_custom_event_callback);
+    view_dispatcher_set_navigation_event_callback(
+        app->view_dispatcher, power_settings_back_event_callback);
+    view_dispatcher_set_tick_event_callback(
+        app->view_dispatcher, power_settings_tick_event_callback, 2000);
+    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+
+    // Views
+    app->batery_info = battery_info_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher,
+        PowerSettingsAppViewBatteryInfo,
+        battery_info_get_view(app->batery_info));
+    app->submenu = submenu_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher, PowerSettingsAppViewSubmenu, submenu_get_view(app->submenu));
+    app->dialog = dialog_ex_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher, PowerSettingsAppViewDialog, dialog_ex_get_view(app->dialog));
+
+    // Set first scene
+    scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneStart);
+    return app;
+}
+
+void power_settings_app_free(PowerSettingsApp* app) {
+    furi_assert(app);
+    // Views
+    view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo);
+    battery_info_free(app->batery_info);
+    view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewSubmenu);
+    submenu_free(app->submenu);
+    view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewDialog);
+    dialog_ex_free(app->dialog);
+    // View dispatcher
+    view_dispatcher_free(app->view_dispatcher);
+    scene_manager_free(app->scene_manager);
+    // Records
+    furi_record_close("power");
+    furi_record_close("gui");
+    free(app);
+}
+
+extern int32_t power_settings_app(void* p) {
+    PowerSettingsApp* app = power_settings_app_alloc();
+    view_dispatcher_run(app->view_dispatcher);
+    power_settings_app_free(app);
+    return 0;
+}

+ 31 - 0
applications/power/power_settings_app/power_settings_app.h

@@ -0,0 +1,31 @@
+#pragma once
+
+#include <furi.h>
+#include <power/power_service/power.h>
+#include <gui/gui.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+#include <gui/scene_manager.h>
+
+#include "views/battery_info.h"
+#include <gui/modules/submenu.h>
+#include <gui/modules/dialog_ex.h>
+
+#include "scenes/power_settings_scene.h"
+
+typedef struct {
+    Power* power;
+    Gui* gui;
+    SceneManager* scene_manager;
+    ViewDispatcher* view_dispatcher;
+    BatteryInfo* batery_info;
+    Submenu* submenu;
+    DialogEx* dialog;
+    PowerInfo info;
+} PowerSettingsApp;
+
+typedef enum {
+    PowerSettingsAppViewBatteryInfo,
+    PowerSettingsAppViewSubmenu,
+    PowerSettingsAppViewDialog,
+} PowerSettingsAppView;

+ 17 - 0
applications/power/power_settings_app/scenes/power_settinfs_scene_usb_disconnect.c

@@ -0,0 +1,17 @@
+#include "../power_settings_app.h"
+
+void power_settings_scene_usb_disconnect_on_enter(void* context) {
+    PowerSettingsApp* app = context;
+
+    dialog_ex_set_header(
+        app->dialog, "Disconnect USB for safe\nshutdown", 64, 26, AlignCenter, AlignTop);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewDialog);
+}
+
+bool power_settings_scene_usb_disconnect_on_event(void* context, SceneManagerEvent event) {
+    return true;
+}
+
+void power_settings_scene_usb_disconnect_on_exit(void* context) {
+}

+ 30 - 0
applications/power/power_settings_app/scenes/power_settings_scene.c

@@ -0,0 +1,30 @@
+#include "power_settings_scene.h"
+
+// Generate scene on_enter handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
+void (*const power_settings_on_enter_handlers[])(void*) = {
+#include "power_settings_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_event handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
+bool (*const power_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = {
+#include "power_settings_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
+void (*const power_settings_on_exit_handlers[])(void* context) = {
+#include "power_settings_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Initialize scene handlers configuration structure
+const SceneManagerHandlers power_settings_scene_handlers = {
+    .on_enter_handlers = power_settings_on_enter_handlers,
+    .on_event_handlers = power_settings_on_event_handlers,
+    .on_exit_handlers = power_settings_on_exit_handlers,
+    .scene_num = PowerSettingsAppSceneNum,
+};

+ 29 - 0
applications/power/power_settings_app/scenes/power_settings_scene.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include <gui/scene_manager.h>
+
+// Generate scene id and total number
+#define ADD_SCENE(prefix, name, id) PowerSettingsAppScene##id,
+typedef enum {
+#include "power_settings_scene_config.h"
+    PowerSettingsAppSceneNum,
+} PowerSettingsAppScene;
+#undef ADD_SCENE
+
+extern const SceneManagerHandlers power_settings_scene_handlers;
+
+// Generate scene on_enter handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
+#include "power_settings_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_event handlers declaration
+#define ADD_SCENE(prefix, name, id) \
+    bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
+#include "power_settings_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
+#include "power_settings_scene_config.h"
+#undef ADD_SCENE

+ 34 - 0
applications/power/power_settings_app/scenes/power_settings_scene_battery_info.c

@@ -0,0 +1,34 @@
+#include "../power_settings_app.h"
+
+static void power_settings_scene_battery_info_update_model(PowerSettingsApp* app) {
+    power_get_info(app->power, &app->info);
+    BatteryInfoModel battery_info_data = {
+        .vbus_voltage = app->info.voltage_vbus,
+        .gauge_voltage = app->info.voltage_gauge,
+        .gauge_current = app->info.current_gauge,
+        .gauge_temperature = app->info.temperature_gauge,
+        .charge = app->info.charge,
+        .health = app->info.health,
+    };
+    battery_info_set_data(app->batery_info, &battery_info_data);
+}
+
+void power_settings_scene_battery_info_on_enter(void* context) {
+    PowerSettingsApp* app = context;
+    power_settings_scene_battery_info_update_model(app);
+    view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo);
+}
+
+bool power_settings_scene_battery_info_on_event(void* context, SceneManagerEvent event) {
+    PowerSettingsApp* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeTick) {
+        power_settings_scene_battery_info_update_model(app);
+        consumed = true;
+    }
+    return consumed;
+}
+
+void power_settings_scene_battery_info_on_exit(void* context) {
+}

+ 5 - 0
applications/power/power_settings_app/scenes/power_settings_scene_config.h

@@ -0,0 +1,5 @@
+ADD_SCENE(power_settings, start, Start)
+ADD_SCENE(power_settings, battery_info, BatteryInfo)
+ADD_SCENE(power_settings, reboot, Reboot)
+ADD_SCENE(power_settings, power_off, PowerOff)
+ADD_SCENE(power_settings, usb_disconnect, UsbDisconnect)

+ 48 - 0
applications/power/power_settings_app/scenes/power_settings_scene_power_off.c

@@ -0,0 +1,48 @@
+#include "../power_settings_app.h"
+
+void power_settings_scene_power_off_dialog_callback(DialogExResult result, void* context) {
+    furi_assert(context);
+    PowerSettingsApp* app = context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, result);
+}
+
+void power_settings_scene_power_off_on_enter(void* context) {
+    PowerSettingsApp* app = context;
+    DialogEx* dialog = app->dialog;
+
+    dialog_ex_set_header(dialog, "Turn off Device?", 64, 2, AlignCenter, AlignTop);
+    dialog_ex_set_text(
+        dialog, "   I will be\nwaiting for\n you here...", 78, 16, AlignLeft, AlignTop);
+    dialog_ex_set_icon(dialog, 21, 13, &I_Cry_dolph_55x52);
+    dialog_ex_set_left_button_text(dialog, "Back");
+    dialog_ex_set_right_button_text(dialog, "OFF");
+    dialog_ex_set_result_callback(dialog, power_settings_scene_power_off_dialog_callback);
+    dialog_ex_set_context(dialog, app);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewDialog);
+}
+
+bool power_settings_scene_power_off_on_event(void* context, SceneManagerEvent event) {
+    PowerSettingsApp* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == DialogExResultLeft) {
+            scene_manager_previous_scene(app->scene_manager);
+        } else if(event.event == DialogExResultRight) {
+            power_off();
+            // Check if USB is connected
+            power_get_info(app->power, &app->info);
+            if(app->info.voltage_vbus > 4.0f) {
+                scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneUsbDisconnect);
+            }
+        }
+        consumed = true;
+    }
+    return consumed;
+}
+
+void power_settings_scene_power_off_on_exit(void* context) {
+    PowerSettingsApp* app = context;
+    dialog_ex_clean(app->dialog);
+}

+ 52 - 0
applications/power/power_settings_app/scenes/power_settings_scene_reboot.c

@@ -0,0 +1,52 @@
+#include "../power_settings_app.h"
+
+enum PowerSettingsRebootSubmenuIndex {
+    PowerSettingsRebootSubmenuIndexDfu,
+    PowerSettingsRebootSubmenuIndexOs,
+};
+
+void power_settings_scene_reboot_submenu_callback(void* context, uint32_t index) {
+    furi_assert(context);
+    PowerSettingsApp* app = context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void power_settings_scene_reboot_on_enter(void* context) {
+    PowerSettingsApp* app = context;
+    Submenu* submenu = app->submenu;
+
+    submenu_set_header(submenu, "Reboot type");
+    submenu_add_item(
+        submenu,
+        "Firmware upgrade",
+        PowerSettingsRebootSubmenuIndexDfu,
+        power_settings_scene_reboot_submenu_callback,
+        app);
+    submenu_add_item(
+        submenu,
+        "Flipper OS",
+        PowerSettingsRebootSubmenuIndexOs,
+        power_settings_scene_reboot_submenu_callback,
+        app);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewSubmenu);
+}
+
+bool power_settings_scene_reboot_on_event(void* context, SceneManagerEvent event) {
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == PowerSettingsRebootSubmenuIndexDfu) {
+            power_reboot(PowerBootModeDfu);
+        } else if(event.event == PowerSettingsRebootSubmenuIndexOs) {
+            power_reboot(PowerBootModeNormal);
+        }
+        consumed = true;
+    }
+    return consumed;
+}
+
+void power_settings_scene_reboot_on_exit(void* context) {
+    PowerSettingsApp* app = context;
+    submenu_clean(app->submenu);
+}

+ 64 - 0
applications/power/power_settings_app/scenes/power_settings_scene_start.c

@@ -0,0 +1,64 @@
+#include "../power_settings_app.h"
+
+enum PowerSettingsSubmenuIndex {
+    PowerSettingsSubmenuIndexBatteryInfo,
+    PowerSettingsSubmenuIndexReboot,
+    PowerSettingsSubmenuIndexOff,
+};
+
+static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) {
+    furi_assert(context);
+    PowerSettingsApp* app = context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void power_settings_scene_start_on_enter(void* context) {
+    PowerSettingsApp* app = context;
+    Submenu* submenu = app->submenu;
+
+    submenu_add_item(
+        submenu,
+        "Battery info",
+        PowerSettingsSubmenuIndexBatteryInfo,
+        power_settings_scene_start_submenu_callback,
+        app);
+    submenu_add_item(
+        submenu,
+        "Reboot",
+        PowerSettingsSubmenuIndexReboot,
+        power_settings_scene_start_submenu_callback,
+        app);
+    submenu_add_item(
+        submenu,
+        "Power OFF",
+        PowerSettingsSubmenuIndexOff,
+        power_settings_scene_start_submenu_callback,
+        app);
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart));
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewSubmenu);
+}
+
+bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
+    PowerSettingsApp* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == PowerSettingsSubmenuIndexBatteryInfo) {
+            scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneBatteryInfo);
+        } else if(event.event == PowerSettingsSubmenuIndexReboot) {
+            scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneReboot);
+        } else if(event.event == PowerSettingsSubmenuIndexOff) {
+            scene_manager_next_scene(app->scene_manager, PowerSettingsAppScenePowerOff);
+        }
+        scene_manager_set_scene_state(app->scene_manager, PowerSettingsAppSceneStart, event.event);
+        consumed = true;
+    }
+    return consumed;
+}
+
+void power_settings_scene_start_on_exit(void* context) {
+    PowerSettingsApp* app = context;
+    submenu_clean(app->submenu);
+}

+ 126 - 0
applications/power/power_settings_app/views/battery_info.c

@@ -0,0 +1,126 @@
+#include "battery_info.h"
+#include <furi.h>
+#include <gui/elements.h>
+
+struct BatteryInfo {
+    View* view;
+};
+
+static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) {
+    canvas_draw_frame(canvas, x - 7, y + 7, 30, 13);
+    canvas_draw_icon(canvas, x, y, icon);
+    canvas_set_color(canvas, ColorWhite);
+    canvas_draw_box(canvas, x - 4, y + 16, 24, 6);
+    canvas_set_color(canvas, ColorBlack);
+    canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val);
+};
+
+static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
+    char emote[20] = {};
+    char header[20] = {};
+    char value[20] = {};
+
+    int32_t drain_current = data->gauge_current * (-1000);
+    uint32_t charge_current = data->gauge_current * 1000;
+
+    // Draw battery
+    canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28);
+    if(charge_current > 0) {
+        canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14);
+    } else if(drain_current > 100) {
+        canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14);
+    } else if(data->charge < 10) {
+        canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14);
+    } else {
+        canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNormal_29x14);
+    }
+
+    // Draw bubble
+    elements_bubble(canvas, 53, 0, 71, 39);
+
+    // Set text
+    if(charge_current > 0) {
+        snprintf(emote, sizeof(emote), "%s", "Yummy!");
+        snprintf(header, sizeof(header), "%s", "Charging at");
+        snprintf(
+            value,
+            sizeof(value),
+            "%ld.%ldV   %ldmA",
+            (uint32_t)(data->vbus_voltage),
+            (uint32_t)(data->vbus_voltage * 10) % 10,
+            charge_current);
+    } else if(drain_current > 0) {
+        snprintf(emote, sizeof(emote), "%s", drain_current > 100 ? "Oh no!" : "Om-nom-nom!");
+        snprintf(header, sizeof(header), "%s", "Consumption is");
+        snprintf(
+            value, sizeof(value), "%ld %s", drain_current, drain_current > 100 ? "mA!" : "mA");
+    } else if(charge_current != 0 || drain_current != 0) {
+        snprintf(header, 20, "...");
+    } else {
+        snprintf(header, sizeof(header), "Charged!");
+    }
+
+    canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote);
+    canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header);
+    canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value);
+};
+
+static void battery_info_draw_callback(Canvas* canvas, void* context) {
+    furi_assert(context);
+    BatteryInfoModel* model = context;
+
+    canvas_clear(canvas);
+    canvas_set_color(canvas, ColorBlack);
+    draw_battery(canvas, model, 0, 5);
+
+    char batt_level[10];
+    char temperature[10];
+    char voltage[10];
+    char health[10];
+
+    snprintf(batt_level, sizeof(batt_level), "%ld%%", (uint32_t)model->charge);
+    snprintf(temperature, sizeof(temperature), "%ld C", (uint32_t)model->gauge_temperature);
+    snprintf(
+        voltage,
+        sizeof(voltage),
+        "%ld.%01ld V",
+        (uint32_t)model->gauge_voltage,
+        (uint32_t)(model->gauge_voltage * 10) % 10);
+    snprintf(health, sizeof(health), "%d%%", model->health);
+
+    draw_stat(canvas, 8, 42, &I_Battery_16x16, batt_level);
+    draw_stat(canvas, 40, 42, &I_Temperature_16x16, temperature);
+    draw_stat(canvas, 72, 42, &I_Voltage_16x16, voltage);
+    draw_stat(canvas, 104, 42, &I_Health_16x16, health);
+}
+
+BatteryInfo* battery_info_alloc() {
+    BatteryInfo* battery_info = furi_alloc(sizeof(BatteryInfo));
+    battery_info->view = view_alloc();
+    view_set_context(battery_info->view, battery_info);
+    view_allocate_model(battery_info->view, ViewModelTypeLocking, sizeof(BatteryInfoModel));
+    view_set_draw_callback(battery_info->view, battery_info_draw_callback);
+
+    return battery_info;
+}
+
+void battery_info_free(BatteryInfo* battery_info) {
+    furi_assert(battery_info);
+    view_free(battery_info->view);
+    free(battery_info);
+}
+
+View* battery_info_get_view(BatteryInfo* battery_info) {
+    furi_assert(battery_info);
+    return battery_info->view;
+}
+
+void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data) {
+    furi_assert(battery_info);
+    furi_assert(data);
+    with_view_model(
+        battery_info->view, (BatteryInfoModel * model) {
+            memcpy(model, data, sizeof(BatteryInfoModel));
+            return true;
+        });
+}

+ 22 - 0
applications/power/power_settings_app/views/battery_info.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <gui/view.h>
+
+typedef struct BatteryInfo BatteryInfo;
+
+typedef struct {
+    float vbus_voltage;
+    float gauge_voltage;
+    float gauge_current;
+    float gauge_temperature;
+    uint8_t charge;
+    uint8_t health;
+} BatteryInfoModel;
+
+BatteryInfo* battery_info_alloc();
+
+void battery_info_free(BatteryInfo* battery_info);
+
+View* battery_info_get_view(BatteryInfo* battery_info);
+
+void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data);

+ 0 - 131
applications/power/power_views.c

@@ -1,131 +0,0 @@
-#include "power_views.h"
-#include <gui/elements.h>
-
-static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) {
-    canvas_draw_frame(canvas, x - 7, y + 7, 30, 13);
-    canvas_draw_icon(canvas, x, y, icon);
-    canvas_set_color(canvas, ColorWhite);
-    canvas_draw_box(canvas, x - 4, y + 16, 24, 6);
-    canvas_set_color(canvas, ColorBlack);
-    canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val);
-};
-
-static void draw_battery(Canvas* canvas, PowerInfoModel* data, int x, int y) {
-    char emote[20];
-    char header[20];
-    char value[20];
-
-    int32_t drain_current = -data->current_gauge * 1000;
-    uint32_t charge_current = data->current_gauge * 1000;
-    // battery
-    canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28);
-    if(charge_current > 0) {
-        canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14);
-    } else if(drain_current > 100) {
-        canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14);
-    } else if(data->charge < 10) {
-        canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14);
-    } else {
-        canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNormal_29x14);
-    }
-
-    //bubble
-    canvas_draw_frame(canvas, 57, 0, 71, 39);
-    canvas_draw_line(canvas, 53, 23, 57, 19);
-    canvas_draw_line(canvas, 53, 23, 57, 27);
-    canvas_set_color(canvas, ColorWhite);
-    canvas_draw_box(canvas, 57, 0, 2, 2);
-    canvas_draw_box(canvas, 57, 37, 2, 2);
-    canvas_draw_box(canvas, 126, 0, 2, 2);
-    canvas_draw_box(canvas, 126, 37, 2, 2);
-    canvas_draw_line(canvas, 57, 20, 57, 26);
-    canvas_set_color(canvas, ColorBlack);
-    canvas_draw_dot(canvas, 58, 1);
-    canvas_draw_dot(canvas, 58, 37);
-    canvas_draw_dot(canvas, 126, 1);
-    canvas_draw_dot(canvas, 126, 37);
-
-    // text
-    if(charge_current > 0) {
-        snprintf(emote, sizeof(emote), "%s", "Yummy!");
-        snprintf(header, sizeof(header), "%s", "Charging at");
-        snprintf(
-            value,
-            sizeof(value),
-            "%ld.%ldV   %ldmA",
-            (uint32_t)(data->voltage_vbus),
-            (uint32_t)(data->voltage_vbus * 10) % 10,
-            charge_current);
-    } else if(drain_current > 0) {
-        snprintf(emote, sizeof(emote), "%s", drain_current > 100 ? "Oh no!" : "Om-nom-nom!");
-        snprintf(header, sizeof(header), "%s", "Consumption is");
-        snprintf(
-            value, sizeof(value), "%ld %s", drain_current, drain_current > 100 ? "mA!" : "mA");
-    } else if(charge_current != 0 || drain_current != 0) {
-        snprintf(header, 20, "%s", "...");
-        memset(value, 0, sizeof(value));
-        memset(emote, 0, sizeof(emote));
-    } else {
-        snprintf(header, sizeof(header), "%s", "Charged!");
-        memset(value, 0, sizeof(value));
-        memset(emote, 0, sizeof(emote));
-    }
-
-    canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote);
-    canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header);
-    canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value);
-};
-
-void power_info_draw_callback(Canvas* canvas, void* context) {
-    furi_assert(context);
-    PowerInfoModel* data = context;
-
-    canvas_clear(canvas);
-    canvas_set_color(canvas, ColorBlack);
-    draw_battery(canvas, data, 0, 5);
-
-    char batt_level[10];
-    char temperature[10];
-    char voltage[10];
-    char health[10];
-
-    snprintf(batt_level, sizeof(batt_level), "%ld%s", (uint32_t)data->charge, "%");
-    snprintf(temperature, sizeof(temperature), "%ld %s", (uint32_t)data->temperature_gauge, "C");
-    snprintf(
-        voltage,
-        sizeof(voltage),
-        "%ld.%01ld V",
-        (uint32_t)data->voltage_gauge,
-        (uint32_t)(data->voltage_gauge * 10) % 10);
-    snprintf(health, sizeof(health), "%d%s", data->health, "%");
-
-    draw_stat(canvas, 8, 42, &I_Battery_16x16, batt_level);
-    draw_stat(canvas, 40, 42, &I_Temperature_16x16, temperature);
-    draw_stat(canvas, 72, 42, &I_Voltage_16x16, voltage);
-    draw_stat(canvas, 104, 42, &I_Health_16x16, health);
-}
-
-void power_off_draw_callback(Canvas* canvas, void* context) {
-    furi_assert(context);
-    PowerOffModel* model = context;
-
-    canvas_set_color(canvas, ColorBlack);
-    canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str(canvas, 2, 15, "!!! Low Battery !!!");
-
-    char buffer[64];
-    canvas_set_font(canvas, FontSecondary);
-    canvas_draw_str(canvas, 5, 30, "Connect to charger");
-    snprintf(
-        buffer,
-        64,
-        "Or poweroff in %lds",
-        (model->poweroff_tick - osKernelGetTickCount()) / osKernelGetTickFreq());
-    canvas_draw_str(canvas, 5, 42, buffer);
-}
-
-void power_disconnect_draw_callback(Canvas* canvas, void* context) {
-    canvas_set_font(canvas, FontPrimary);
-    elements_multiline_text_aligned(
-        canvas, 64, 32, AlignCenter, AlignCenter, "It's now safe to turn off\nyour flipper");
-}

+ 0 - 38
applications/power/power_views.h

@@ -1,38 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <furi.h>
-#include <gui/canvas.h>
-#include <gui/view.h>
-
-typedef enum { PowerViewInfo, PowerViewDialog, PowerViewOff, PowerViewDisconnect } PowerView;
-
-typedef struct {
-    float current_charger;
-    float current_gauge;
-
-    float voltage_charger;
-    float voltage_gauge;
-    float voltage_vbus;
-
-    uint32_t capacity_remaining;
-    uint32_t capacity_full;
-
-    float temperature_charger;
-    float temperature_gauge;
-
-    uint8_t charge;
-    uint8_t health;
-} PowerInfoModel;
-
-typedef struct {
-    uint32_t poweroff_tick;
-    bool battery_low;
-} PowerOffModel;
-
-void power_info_draw_callback(Canvas* canvas, void* context);
-
-void power_off_draw_callback(Canvas* canvas, void* context);
-
-void power_disconnect_draw_callback(Canvas* canvas, void* context);

Plik diff jest za duży
+ 0 - 0
assets/compiled/assets_icons.c


+ 56 - 55
assets/compiled/assets_icons.h

@@ -5,64 +5,64 @@ extern const Icon I_Certification1_103x23;
 extern const Icon I_Certification2_119x30;
 extern const Icon A_WatchingTV_128x64;
 extern const Icon A_Wink_128x64;
-extern const Icon I_125_10px;
-extern const Icon I_ble_10px;
 extern const Icon I_dir_10px;
-extern const Icon I_ibutt_10px;
-extern const Icon I_ir_10px;
 extern const Icon I_Nfc_10px;
 extern const Icon I_sub1_10px;
+extern const Icon I_ir_10px;
+extern const Icon I_ibutt_10px;
 extern const Icon I_unknown_10px;
-extern const Icon I_ButtonCenter_7x7;
-extern const Icon I_ButtonLeftSmall_3x5;
-extern const Icon I_ButtonLeft_4x7;
+extern const Icon I_ble_10px;
+extern const Icon I_125_10px;
 extern const Icon I_ButtonRightSmall_3x5;
-extern const Icon I_ButtonRight_4x7;
+extern const Icon I_ButtonLeft_4x7;
+extern const Icon I_ButtonLeftSmall_3x5;
 extern const Icon I_DFU_128x50;
 extern const Icon I_Warning_30x23;
-extern const Icon I_DolphinFirstStart0_70x53;
-extern const Icon I_DolphinFirstStart1_59x53;
-extern const Icon I_DolphinFirstStart2_59x51;
-extern const Icon I_DolphinFirstStart3_57x48;
+extern const Icon I_ButtonRight_4x7;
+extern const Icon I_ButtonCenter_7x7;
+extern const Icon I_DolphinOkay_41x43;
 extern const Icon I_DolphinFirstStart4_67x53;
+extern const Icon I_DolphinFirstStart2_59x51;
 extern const Icon I_DolphinFirstStart5_54x49;
+extern const Icon I_DolphinFirstStart0_70x53;
 extern const Icon I_DolphinFirstStart6_58x54;
-extern const Icon I_DolphinFirstStart7_61x51;
+extern const Icon I_DolphinFirstStart1_59x53;
 extern const Icon I_DolphinFirstStart8_56x51;
-extern const Icon I_DolphinOkay_41x43;
+extern const Icon I_DolphinFirstStart7_61x51;
 extern const Icon I_Flipper_young_80x60;
-extern const Icon I_DoorLeft_70x55;
+extern const Icon I_DolphinFirstStart3_57x48;
+extern const Icon I_PassportBottom_128x17;
 extern const Icon I_DoorLeft_8x56;
 extern const Icon I_DoorLocked_10x56;
-extern const Icon I_DoorRight_70x55;
 extern const Icon I_DoorRight_8x56;
-extern const Icon I_LockPopup_100x49;
-extern const Icon I_PassportBottom_128x17;
+extern const Icon I_DoorLeft_70x55;
 extern const Icon I_PassportLeft_6x47;
-extern const Icon I_Back_15x10;
-extern const Icon I_Down_25x27;
-extern const Icon I_Down_hvr_25x27;
-extern const Icon I_Fill_marker_7x7;
-extern const Icon I_IrdaArrowDown_4x8;
-extern const Icon I_IrdaArrowUp_4x8;
-extern const Icon I_IrdaLearnShort_128x31;
-extern const Icon I_IrdaLearn_128x64;
-extern const Icon I_IrdaSendShort_128x34;
-extern const Icon I_IrdaSend_128x64;
+extern const Icon I_DoorRight_70x55;
+extern const Icon I_LockPopup_100x49;
 extern const Icon I_Mute_25x27;
-extern const Icon I_Mute_hvr_25x27;
-extern const Icon I_Power_25x27;
-extern const Icon I_Power_hvr_25x27;
-extern const Icon I_Up_25x27;
+extern const Icon I_IrdaArrowUp_4x8;
 extern const Icon I_Up_hvr_25x27;
+extern const Icon I_Mute_hvr_25x27;
 extern const Icon I_Vol_down_25x27;
+extern const Icon I_Down_25x27;
+extern const Icon I_Power_hvr_25x27;
+extern const Icon I_IrdaLearnShort_128x31;
+extern const Icon I_IrdaArrowDown_4x8;
 extern const Icon I_Vol_down_hvr_25x27;
+extern const Icon I_IrdaLearn_128x64;
+extern const Icon I_Down_hvr_25x27;
+extern const Icon I_Fill_marker_7x7;
+extern const Icon I_Power_25x27;
 extern const Icon I_Vol_up_25x27;
+extern const Icon I_Up_25x27;
+extern const Icon I_Back_15x10;
+extern const Icon I_IrdaSend_128x64;
+extern const Icon I_IrdaSendShort_128x34;
 extern const Icon I_Vol_up_hvr_25x27;
+extern const Icon I_KeySave_24x11;
 extern const Icon I_KeyBackspaceSelected_16x9;
-extern const Icon I_KeyBackspace_16x9;
 extern const Icon I_KeySaveSelected_24x11;
-extern const Icon I_KeySave_24x11;
+extern const Icon I_KeyBackspace_16x9;
 extern const Icon A_125khz_14;
 extern const Icon A_Bluetooth_14;
 extern const Icon A_Debug_14;
@@ -81,41 +81,42 @@ extern const Icon A_U2F_14;
 extern const Icon A_iButton_14;
 extern const Icon I_Detailed_chip_17x13;
 extern const Icon I_Medium_chip_22x21;
-extern const Icon I_BatteryBody_52x28;
-extern const Icon I_Battery_16x16;
+extern const Icon I_Health_16x16;
 extern const Icon I_FaceCharging_29x14;
-extern const Icon I_FaceConfused_29x14;
+extern const Icon I_BatteryBody_52x28;
+extern const Icon I_Voltage_16x16;
+extern const Icon I_Temperature_16x16;
 extern const Icon I_FaceNopower_29x14;
 extern const Icon I_FaceNormal_29x14;
-extern const Icon I_Health_16x16;
-extern const Icon I_Temperature_16x16;
-extern const Icon I_Voltage_16x16;
+extern const Icon I_Battery_16x16;
+extern const Icon I_FaceConfused_29x14;
+extern const Icon I_RFIDDolphinSuccess_108x57;
 extern const Icon I_RFIDBigChip_37x36;
-extern const Icon I_RFIDDolphinReceive_97x61;
 extern const Icon I_RFIDDolphinSend_97x61;
-extern const Icon I_RFIDDolphinSuccess_108x57;
-extern const Icon I_SDError_43x35;
+extern const Icon I_RFIDDolphinReceive_97x61;
 extern const Icon I_SDQuestion_35x43;
-extern const Icon I_Background_128x11;
-extern const Icon I_Background_128x8;
+extern const Icon I_SDError_43x35;
+extern const Icon I_Cry_dolph_55x52;
 extern const Icon I_BadUsb_9x8;
-extern const Icon I_Battery_19x8;
-extern const Icon I_Battery_26x8;
-extern const Icon I_Bluetooth_5x8;
+extern const Icon I_PlaceholderR_30x13;
+extern const Icon I_Background_128x8;
 extern const Icon I_Lock_8x8;
+extern const Icon I_Battery_26x8;
 extern const Icon I_PlaceholderL_11x13;
-extern const Icon I_PlaceholderR_30x13;
-extern const Icon I_SDcardFail_11x8;
+extern const Icon I_Battery_19x8;
 extern const Icon I_SDcardMounted_11x8;
+extern const Icon I_SDcardFail_11x8;
 extern const Icon I_USBConnected_15x8;
-extern const Icon I_Lock_7x8;
-extern const Icon I_Quest_7x8;
+extern const Icon I_Bluetooth_5x8;
+extern const Icon I_Background_128x11;
 extern const Icon I_Scanning_123x52;
+extern const Icon I_Quest_7x8;
 extern const Icon I_Unlock_7x8;
-extern const Icon I_DolphinExcited_64x63;
+extern const Icon I_Lock_7x8;
 extern const Icon I_DolphinMafia_115x62;
-extern const Icon I_DolphinNice_96x59;
-extern const Icon I_DolphinWait_61x59;
+extern const Icon I_DolphinExcited_64x63;
 extern const Icon I_iButtonDolphinSuccess_109x60;
 extern const Icon I_iButtonDolphinVerySuccess_108x52;
 extern const Icon I_iButtonKey_49x44;
+extern const Icon I_DolphinNice_96x59;
+extern const Icon I_DolphinWait_61x59;

BIN
assets/icons/Settings/Cry_dolph_55x52.png


+ 0 - 0
assets/icons/SubGhz/lock_7x8.png → assets/icons/SubGhz/Lock_7x8.png


+ 0 - 0
assets/icons/SubGhz/quest_7x8.png → assets/icons/SubGhz/Quest_7x8.png


+ 0 - 0
assets/icons/SubGhz/unlock_7x8.png → assets/icons/SubGhz/Unlock_7x8.png


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików