UI: Clock on Desktop (#2891)
* Clock on desktop * Gui: gui_active_view_port_count * Gui: move gui_active_view_port_count to private header, update docs * Desktop: simplify desktop clock code * Desktop: refactor clock * Desktop: optimize clock code * Desktop: 3rd cleanup round * Desktop: 4th cleanup round, missing bits and pieces Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									498aee20a2
								
							
						
					
					
						commit
						f75fcd4e34
					
				@ -1,6 +1,7 @@
 | 
			
		||||
#include <storage/storage.h>
 | 
			
		||||
#include <assets_icons.h>
 | 
			
		||||
#include <gui/gui.h>
 | 
			
		||||
#include <gui/gui_i.h>
 | 
			
		||||
#include <gui/view_stack.h>
 | 
			
		||||
#include <notification/notification.h>
 | 
			
		||||
#include <notification/notification_messages.h>
 | 
			
		||||
@ -8,6 +9,7 @@
 | 
			
		||||
#include <furi_hal.h>
 | 
			
		||||
#include <cli/cli.h>
 | 
			
		||||
#include <cli/cli_vcp.h>
 | 
			
		||||
#include <locale/locale.h>
 | 
			
		||||
 | 
			
		||||
#include "animations/animation_manager.h"
 | 
			
		||||
#include "desktop/scenes/desktop_scene.h"
 | 
			
		||||
@ -36,7 +38,6 @@ static void desktop_loader_callback(const void* message, void* context) {
 | 
			
		||||
        view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) {
 | 
			
		||||
    UNUSED(context);
 | 
			
		||||
    furi_assert(canvas);
 | 
			
		||||
@ -49,6 +50,65 @@ static void desktop_dummy_mode_icon_draw_callback(Canvas* canvas, void* context)
 | 
			
		||||
    canvas_draw_icon(canvas, 0, 0, &I_GameMode_11x8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void desktop_clock_update(Desktop* desktop) {
 | 
			
		||||
    furi_assert(desktop);
 | 
			
		||||
 | 
			
		||||
    FuriHalRtcDateTime curr_dt;
 | 
			
		||||
    furi_hal_rtc_get_datetime(&curr_dt);
 | 
			
		||||
    bool time_format_12 = locale_get_time_format() == LocaleTimeFormat12h;
 | 
			
		||||
 | 
			
		||||
    if(desktop->time_hour != curr_dt.hour || desktop->time_minute != curr_dt.minute ||
 | 
			
		||||
       desktop->time_format_12 != time_format_12) {
 | 
			
		||||
        desktop->time_format_12 = time_format_12;
 | 
			
		||||
        desktop->time_hour = curr_dt.hour;
 | 
			
		||||
        desktop->time_minute = curr_dt.minute;
 | 
			
		||||
        view_port_update(desktop->clock_viewport);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void desktop_clock_reconfigure(Desktop* desktop) {
 | 
			
		||||
    furi_assert(desktop);
 | 
			
		||||
 | 
			
		||||
    desktop_clock_update(desktop);
 | 
			
		||||
 | 
			
		||||
    if(desktop->settings.display_clock) {
 | 
			
		||||
        furi_timer_start(desktop->update_clock_timer, furi_ms_to_ticks(1000));
 | 
			
		||||
    } else {
 | 
			
		||||
        furi_timer_stop(desktop->update_clock_timer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    view_port_enabled_set(desktop->clock_viewport, desktop->settings.display_clock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void desktop_clock_draw_callback(Canvas* canvas, void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    furi_assert(canvas);
 | 
			
		||||
 | 
			
		||||
    Desktop* desktop = context;
 | 
			
		||||
 | 
			
		||||
    canvas_set_font(canvas, FontPrimary);
 | 
			
		||||
 | 
			
		||||
    uint8_t hour = desktop->time_hour;
 | 
			
		||||
    if(desktop->time_format_12) {
 | 
			
		||||
        if(hour > 12) {
 | 
			
		||||
            hour -= 12;
 | 
			
		||||
        }
 | 
			
		||||
        if(hour == 0) {
 | 
			
		||||
            hour = 12;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char buffer[20];
 | 
			
		||||
    snprintf(buffer, sizeof(buffer), "%02u:%02u", hour, desktop->time_minute);
 | 
			
		||||
 | 
			
		||||
    // ToDo: never do that, may cause visual glitches
 | 
			
		||||
    view_port_set_width(
 | 
			
		||||
        desktop->clock_viewport,
 | 
			
		||||
        canvas_string_width(canvas, buffer) - 1 + (desktop->time_minute % 10 == 1));
 | 
			
		||||
 | 
			
		||||
    canvas_draw_str_aligned(canvas, 0, 8, AlignLeft, AlignBottom, buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void desktop_stealth_mode_icon_draw_callback(Canvas* canvas, void* context) {
 | 
			
		||||
    UNUSED(context);
 | 
			
		||||
    furi_assert(canvas);
 | 
			
		||||
@ -69,6 +129,9 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) {
 | 
			
		||||
        // TODO: Implement a message mechanism for loading settings and (optionally)
 | 
			
		||||
        // locking and unlocking
 | 
			
		||||
        DESKTOP_SETTINGS_LOAD(&desktop->settings);
 | 
			
		||||
 | 
			
		||||
        desktop_clock_reconfigure(desktop);
 | 
			
		||||
 | 
			
		||||
        desktop_auto_lock_arm(desktop);
 | 
			
		||||
        return true;
 | 
			
		||||
    case DesktopGlobalAutoLock:
 | 
			
		||||
@ -134,6 +197,19 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void desktop_clock_timer_callback(void* context) {
 | 
			
		||||
    furi_assert(context);
 | 
			
		||||
    Desktop* desktop = context;
 | 
			
		||||
 | 
			
		||||
    if(gui_active_view_port_count(desktop->gui, GuiLayerStatusBarLeft) < 6) {
 | 
			
		||||
        desktop_clock_update(desktop);
 | 
			
		||||
 | 
			
		||||
        view_port_enabled_set(desktop->clock_viewport, true);
 | 
			
		||||
    } else {
 | 
			
		||||
        view_port_enabled_set(desktop->clock_viewport, false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void desktop_lock(Desktop* desktop) {
 | 
			
		||||
    furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
 | 
			
		||||
 | 
			
		||||
@ -286,6 +362,13 @@ Desktop* desktop_alloc() {
 | 
			
		||||
    view_port_enabled_set(desktop->dummy_mode_icon_viewport, false);
 | 
			
		||||
    gui_add_view_port(desktop->gui, desktop->dummy_mode_icon_viewport, GuiLayerStatusBarLeft);
 | 
			
		||||
 | 
			
		||||
    // Clock
 | 
			
		||||
    desktop->clock_viewport = view_port_alloc();
 | 
			
		||||
    view_port_set_width(desktop->clock_viewport, 25);
 | 
			
		||||
    view_port_draw_callback_set(desktop->clock_viewport, desktop_clock_draw_callback, desktop);
 | 
			
		||||
    view_port_enabled_set(desktop->clock_viewport, false);
 | 
			
		||||
    gui_add_view_port(desktop->gui, desktop->clock_viewport, GuiLayerStatusBarRight);
 | 
			
		||||
 | 
			
		||||
    // Stealth mode icon
 | 
			
		||||
    desktop->stealth_mode_icon_viewport = view_port_alloc();
 | 
			
		||||
    view_port_set_width(desktop->stealth_mode_icon_viewport, icon_get_width(&I_Muted_8x8));
 | 
			
		||||
@ -317,6 +400,9 @@ Desktop* desktop_alloc() {
 | 
			
		||||
 | 
			
		||||
    desktop->status_pubsub = furi_pubsub_alloc();
 | 
			
		||||
 | 
			
		||||
    desktop->update_clock_timer =
 | 
			
		||||
        furi_timer_alloc(desktop_clock_timer_callback, FuriTimerTypePeriodic, desktop);
 | 
			
		||||
 | 
			
		||||
    furi_record_create(RECORD_DESKTOP, desktop);
 | 
			
		||||
 | 
			
		||||
    return desktop;
 | 
			
		||||
@ -362,6 +448,9 @@ int32_t desktop_srv(void* p) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode);
 | 
			
		||||
 | 
			
		||||
    desktop_clock_reconfigure(desktop);
 | 
			
		||||
 | 
			
		||||
    desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode);
 | 
			
		||||
    animation_manager_set_dummy_mode_state(
 | 
			
		||||
        desktop->animation_manager, desktop->settings.dummy_mode);
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,7 @@ struct Desktop {
 | 
			
		||||
 | 
			
		||||
    ViewPort* lock_icon_viewport;
 | 
			
		||||
    ViewPort* dummy_mode_icon_viewport;
 | 
			
		||||
    ViewPort* clock_viewport;
 | 
			
		||||
    ViewPort* stealth_mode_icon_viewport;
 | 
			
		||||
 | 
			
		||||
    AnimationManager* animation_manager;
 | 
			
		||||
@ -70,10 +71,15 @@ struct Desktop {
 | 
			
		||||
    FuriPubSub* input_events_pubsub;
 | 
			
		||||
    FuriPubSubSubscription* input_events_subscription;
 | 
			
		||||
    FuriTimer* auto_lock_timer;
 | 
			
		||||
    FuriTimer* update_clock_timer;
 | 
			
		||||
 | 
			
		||||
    FuriPubSub* status_pubsub;
 | 
			
		||||
 | 
			
		||||
    bool in_transition;
 | 
			
		||||
    uint8_t time_hour;
 | 
			
		||||
    uint8_t time_minute;
 | 
			
		||||
    bool time_format_12 : 1; // 1 - 12 hour, 0 - 24H
 | 
			
		||||
 | 
			
		||||
    bool in_transition : 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Desktop* desktop_alloc();
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
#include <toolbox/saved_struct.h>
 | 
			
		||||
#include <storage/storage.h>
 | 
			
		||||
 | 
			
		||||
#define DESKTOP_SETTINGS_VER (8)
 | 
			
		||||
#define DESKTOP_SETTINGS_VER (9)
 | 
			
		||||
 | 
			
		||||
#define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME)
 | 
			
		||||
#define DESKTOP_SETTINGS_MAGIC (0x17)
 | 
			
		||||
@ -51,4 +51,5 @@ typedef struct {
 | 
			
		||||
    PinCode pin_code;
 | 
			
		||||
    uint32_t auto_lock_delay_ms;
 | 
			
		||||
    uint8_t dummy_mode;
 | 
			
		||||
    uint8_t display_clock;
 | 
			
		||||
} DesktopSettings;
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,26 @@ ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t gui_active_view_port_count(Gui* gui, GuiLayer layer) {
 | 
			
		||||
    furi_assert(gui);
 | 
			
		||||
    furi_check(layer < GuiLayerMAX);
 | 
			
		||||
    size_t ret = 0;
 | 
			
		||||
 | 
			
		||||
    gui_lock(gui);
 | 
			
		||||
    ViewPortArray_it_t it;
 | 
			
		||||
    ViewPortArray_it_last(it, gui->layers[layer]);
 | 
			
		||||
    while(!ViewPortArray_end_p(it)) {
 | 
			
		||||
        ViewPort* view_port = *ViewPortArray_ref(it);
 | 
			
		||||
        if(view_port_is_enabled(view_port)) {
 | 
			
		||||
            ret++;
 | 
			
		||||
        }
 | 
			
		||||
        ViewPortArray_previous(it);
 | 
			
		||||
    }
 | 
			
		||||
    gui_unlock(gui);
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gui_update(Gui* gui) {
 | 
			
		||||
    furi_assert(gui);
 | 
			
		||||
    if(!gui->direct_draw) furi_thread_flags_set(gui->thread_id, GUI_THREAD_FLAG_DRAW);
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,12 @@ struct Gui {
 | 
			
		||||
    ViewPort* ongoing_input_view_port;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Find enabled ViewPort in ViewPortArray
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  array  The ViewPortArray instance
 | 
			
		||||
 *
 | 
			
		||||
 * @return     ViewPort instance or NULL
 | 
			
		||||
 */
 | 
			
		||||
ViewPort* gui_view_port_find_enabled(ViewPortArray_t array);
 | 
			
		||||
 | 
			
		||||
/** Update GUI, request redraw
 | 
			
		||||
@ -83,8 +89,30 @@ ViewPort* gui_view_port_find_enabled(ViewPortArray_t array);
 | 
			
		||||
 */
 | 
			
		||||
void gui_update(Gui* gui);
 | 
			
		||||
 | 
			
		||||
/** Input event callback
 | 
			
		||||
 * 
 | 
			
		||||
 * Used to receive input from input service or to inject new input events
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  value  The value pointer (InputEvent*)
 | 
			
		||||
 * @param      ctx    The context (Gui instance)
 | 
			
		||||
 */
 | 
			
		||||
void gui_input_events_callback(const void* value, void* ctx);
 | 
			
		||||
 | 
			
		||||
/** Get count of view ports in layer
 | 
			
		||||
 *
 | 
			
		||||
 * @param      gui        The Gui instance
 | 
			
		||||
 * @param[in]  layer      GuiLayer that we want to get count of view ports
 | 
			
		||||
 */
 | 
			
		||||
size_t gui_active_view_port_count(Gui* gui, GuiLayer layer);
 | 
			
		||||
 | 
			
		||||
/** Lock GUI
 | 
			
		||||
 *
 | 
			
		||||
 * @param      gui   The Gui instance
 | 
			
		||||
 */
 | 
			
		||||
void gui_lock(Gui* gui);
 | 
			
		||||
 | 
			
		||||
/** Unlock GUI
 | 
			
		||||
 *
 | 
			
		||||
 * @param      gui   The Gui instance
 | 
			
		||||
 */
 | 
			
		||||
void gui_unlock(Gui* gui);
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@
 | 
			
		||||
#define SCENE_EVENT_SELECT_FAVORITE_SECONDARY 1
 | 
			
		||||
#define SCENE_EVENT_SELECT_PIN_SETUP 2
 | 
			
		||||
#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 3
 | 
			
		||||
#define SCENE_EVENT_SELECT_CLOCK_DISPLAY 4
 | 
			
		||||
 | 
			
		||||
#define AUTO_LOCK_DELAY_COUNT 6
 | 
			
		||||
const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
 | 
			
		||||
@ -22,11 +23,27 @@ const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
 | 
			
		||||
const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] =
 | 
			
		||||
    {0, 30000, 60000, 120000, 300000, 600000};
 | 
			
		||||
 | 
			
		||||
#define CLOCK_ENABLE_COUNT 2
 | 
			
		||||
const char* const clock_enable_text[CLOCK_ENABLE_COUNT] = {
 | 
			
		||||
    "OFF",
 | 
			
		||||
    "ON",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const uint32_t clock_enable_value[CLOCK_ENABLE_COUNT] = {0, 1};
 | 
			
		||||
 | 
			
		||||
static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
 | 
			
		||||
    DesktopSettingsApp* app = context;
 | 
			
		||||
    view_dispatcher_send_custom_event(app->view_dispatcher, index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void desktop_settings_scene_start_clock_enable_changed(VariableItem* item) {
 | 
			
		||||
    DesktopSettingsApp* app = variable_item_get_context(item);
 | 
			
		||||
    uint8_t index = variable_item_get_current_value_index(item);
 | 
			
		||||
 | 
			
		||||
    variable_item_set_current_value_text(item, clock_enable_text[index]);
 | 
			
		||||
    app->settings.display_clock = index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) {
 | 
			
		||||
    DesktopSettingsApp* app = variable_item_get_context(item);
 | 
			
		||||
    uint8_t index = variable_item_get_current_value_index(item);
 | 
			
		||||
@ -62,6 +79,18 @@ void desktop_settings_scene_start_on_enter(void* context) {
 | 
			
		||||
    variable_item_set_current_value_index(item, value_index);
 | 
			
		||||
    variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]);
 | 
			
		||||
 | 
			
		||||
    item = variable_item_list_add(
 | 
			
		||||
        variable_item_list,
 | 
			
		||||
        "Show Clock",
 | 
			
		||||
        CLOCK_ENABLE_COUNT,
 | 
			
		||||
        desktop_settings_scene_start_clock_enable_changed, //
 | 
			
		||||
        app);
 | 
			
		||||
 | 
			
		||||
    value_index =
 | 
			
		||||
        value_index_uint32(app->settings.display_clock, clock_enable_value, CLOCK_ENABLE_COUNT);
 | 
			
		||||
    variable_item_set_current_value_index(item, value_index);
 | 
			
		||||
    variable_item_set_current_value_text(item, clock_enable_text[value_index]);
 | 
			
		||||
 | 
			
		||||
    view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -86,6 +115,7 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
 | 
			
		||||
            consumed = true;
 | 
			
		||||
            break;
 | 
			
		||||
        case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY:
 | 
			
		||||
        case SCENE_EVENT_SELECT_CLOCK_DISPLAY:
 | 
			
		||||
            consumed = true;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1471,6 +1471,7 @@ Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, voi
 | 
			
		||||
Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer"
 | 
			
		||||
Function,+,gui_direct_draw_acquire,Canvas*,Gui*
 | 
			
		||||
Function,+,gui_direct_draw_release,void,Gui*
 | 
			
		||||
Function,-,gui_active_view_port_count,size_t,"Gui*, GuiLayer"
 | 
			
		||||
Function,+,gui_get_framebuffer_size,size_t,const Gui*
 | 
			
		||||
Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*"
 | 
			
		||||
Function,+,gui_remove_view_port,void,"Gui*, ViewPort*"
 | 
			
		||||
 | 
			
		||||
		
		
			
  | 
@ -1642,6 +1642,7 @@ Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, voi
 | 
			
		||||
Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer"
 | 
			
		||||
Function,+,gui_direct_draw_acquire,Canvas*,Gui*
 | 
			
		||||
Function,+,gui_direct_draw_release,void,Gui*
 | 
			
		||||
Function,-,gui_active_view_port_count,size_t,"Gui*, GuiLayer"
 | 
			
		||||
Function,+,gui_get_framebuffer_size,size_t,const Gui*
 | 
			
		||||
Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*"
 | 
			
		||||
Function,+,gui_remove_view_port,void,"Gui*, ViewPort*"
 | 
			
		||||
 | 
			
		||||
		
		
			
  | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user