[FL-3024] Locale settings (#2137)

* Locale settings
* Time/date format fix
* Locale: add docs, enums for HAL, cleanup.

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Nikolay Minaylov
2022-12-19 12:38:20 +03:00
committed by GitHub
parent 2dea6969fe
commit f10e82c64d
10 changed files with 636 additions and 19 deletions

View File

@@ -0,0 +1,11 @@
App(
appid="locale_test",
name="Locale Test",
apptype=FlipperAppType.DEBUG,
entry_point="locale_test_app",
cdefines=["APP_LOCALE"],
requires=["gui", "locale"],
stack_size=2 * 1024,
order=70,
fap_category="Debug",
)

View File

@@ -0,0 +1,102 @@
#include <furi.h>
#include <gui/gui.h>
#include <gui/elements.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/dialog_ex.h>
#include <locale/locale.h>
typedef struct {
Gui* gui;
ViewDispatcher* view_dispatcher;
View* view;
} LocaleTestApp;
static void locale_test_view_draw_callback(Canvas* canvas, void* _model) {
UNUSED(_model);
// Prepare canvas
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
FuriString* tmp_string = furi_string_alloc();
float temp = 25.3f;
LocaleMeasurementUnits units = locale_get_measurement_unit();
if(units == LocaleMeasurementUnitsMetric) {
furi_string_printf(tmp_string, "Temp: %5.1fC", (double)temp);
} else {
temp = locale_celsius_to_fahrenheit(temp);
furi_string_printf(tmp_string, "Temp: %5.1fF", (double)temp);
}
canvas_draw_str(canvas, 0, 10, furi_string_get_cstr(tmp_string));
FuriHalRtcDateTime datetime;
furi_hal_rtc_get_datetime(&datetime);
locale_format_time(tmp_string, &datetime, locale_get_time_format(), false);
canvas_draw_str(canvas, 0, 25, furi_string_get_cstr(tmp_string));
locale_format_date(tmp_string, &datetime, locale_get_date_format(), "/");
canvas_draw_str(canvas, 0, 40, furi_string_get_cstr(tmp_string));
furi_string_free(tmp_string);
}
static bool locale_test_view_input_callback(InputEvent* event, void* context) {
UNUSED(event);
UNUSED(context);
return false;
}
static uint32_t locale_test_exit(void* context) {
UNUSED(context);
return VIEW_NONE;
}
static LocaleTestApp* locale_test_alloc() {
LocaleTestApp* app = malloc(sizeof(LocaleTestApp));
// Gui
app->gui = furi_record_open(RECORD_GUI);
// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Views
app->view = view_alloc();
view_set_draw_callback(app->view, locale_test_view_draw_callback);
view_set_input_callback(app->view, locale_test_view_input_callback);
view_set_previous_callback(app->view, locale_test_exit);
view_dispatcher_add_view(app->view_dispatcher, 0, app->view);
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
return app;
}
static void locale_test_free(LocaleTestApp* app) {
furi_assert(app);
// Free views
view_dispatcher_remove_view(app->view_dispatcher, 0);
view_free(app->view);
view_dispatcher_free(app->view_dispatcher);
// Close gui record
furi_record_close(RECORD_GUI);
app->gui = NULL;
// Free rest
free(app);
}
int32_t locale_test_app(void* p) {
UNUSED(p);
LocaleTestApp* app = locale_test_alloc();
view_dispatcher_run(app->view_dispatcher);
locale_test_free(app);
return 0;
}

View File

@@ -0,0 +1,9 @@
App(
appid="locale",
name="LocaleSrv",
apptype=FlipperAppType.STARTUP,
entry_point="locale_on_system_start",
cdefines=["SRV_LOCALE"],
order=90,
sdk_headers=["locale.h"],
)

View File

@@ -0,0 +1,109 @@
#include "locale.h"
#define TAG "LocaleSrv"
LocaleMeasurementUnits locale_get_measurement_unit(void) {
return (LocaleMeasurementUnits)furi_hal_rtc_get_locale_units();
}
void locale_set_measurement_unit(LocaleMeasurementUnits format) {
furi_hal_rtc_set_locale_units((FuriHalRtcLocaleUnits)format);
}
LocaleTimeFormat locale_get_time_format(void) {
return (LocaleTimeFormat)furi_hal_rtc_get_locale_timeformat();
}
void locale_set_time_format(LocaleTimeFormat format) {
furi_hal_rtc_set_locale_timeformat((FuriHalRtcLocaleTimeFormat)format);
}
LocaleDateFormat locale_get_date_format(void) {
return (LocaleDateFormat)furi_hal_rtc_get_locale_dateformat();
}
void locale_set_date_format(LocaleDateFormat format) {
furi_hal_rtc_set_locale_dateformat((FuriHalRtcLocaleDateFormat)format);
}
float locale_fahrenheit_to_celsius(float temp_f) {
return (temp_f - 32.f) / 1.8f;
}
float locale_celsius_to_fahrenheit(float temp_c) {
return (temp_c * 1.8f + 32.f);
}
void locale_format_time(
FuriString* out_str,
const FuriHalRtcDateTime* datetime,
const LocaleTimeFormat format,
const bool show_seconds) {
furi_assert(out_str);
furi_assert(datetime);
uint8_t hours = datetime->hour;
uint8_t am_pm = 0;
if(format == LocaleTimeFormat12h) {
if(hours > 12) {
hours -= 12;
am_pm = 2;
} else {
am_pm = 1;
}
}
if(show_seconds) {
furi_string_printf(out_str, "%02u:%02u:%02u", hours, datetime->minute, datetime->second);
} else {
furi_string_printf(out_str, "%02u:%02u", hours, datetime->minute);
}
if(am_pm > 0) {
furi_string_cat_printf(out_str, " %s", (am_pm == 1) ? ("AM") : ("PM"));
}
}
void locale_format_date(
FuriString* out_str,
const FuriHalRtcDateTime* datetime,
const LocaleDateFormat format,
const char* separator) {
furi_assert(out_str);
furi_assert(datetime);
furi_assert(separator);
if(format == LocaleDateFormatDMY) {
furi_string_printf(
out_str,
"%02u%s%02u%s%04u",
datetime->day,
separator,
datetime->month,
separator,
datetime->year);
} else if(format == LocaleDateFormatMDY) {
furi_string_printf(
out_str,
"%02u%s%02u%s%04u",
datetime->month,
separator,
datetime->day,
separator,
datetime->year);
} else {
furi_string_printf(
out_str,
"%04u%s%02u%s%02u",
datetime->year,
separator,
datetime->month,
separator,
datetime->day);
}
}
int32_t locale_on_system_start(void* p) {
UNUSED(p);
return 0;
}

View File

@@ -0,0 +1,107 @@
#pragma once
#include <stdbool.h>
#include <furi.h>
#include <furi_hal.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
LocaleMeasurementUnitsMetric = 0, /**< Metric measurement units */
LocaleMeasurementUnitsImperial = 1, /**< Imperial measurement units */
} LocaleMeasurementUnits;
typedef enum {
LocaleTimeFormat24h = 0, /**< 24-hour format */
LocaleTimeFormat12h = 1, /**< 12-hour format */
} LocaleTimeFormat;
typedef enum {
LocaleDateFormatDMY = 0, /**< Day/Month/Year */
LocaleDateFormatMDY = 1, /**< Month/Day/Year */
LocaleDateFormatYMD = 2, /**< Year/Month/Day */
} LocaleDateFormat;
/** Get Locale measurement units
*
* @return The locale measurement units.
*/
LocaleMeasurementUnits locale_get_measurement_unit();
/** Set locale measurement units
*
* @param[in] format The locale measurements units
*/
void locale_set_measurement_unit(LocaleMeasurementUnits format);
/** Convert Fahrenheit to Celsius
*
* @param[in] temp_f The Temperature in Fahrenheit
*
* @return The Temperature in Celsius
*/
float locale_fahrenheit_to_celsius(float temp_f);
/** Convert Celsius to Fahrenheit
*
* @param[in] temp_c The Temperature in Celsius
*
* @return The Temperature in Fahrenheit
*/
float locale_celsius_to_fahrenheit(float temp_c);
/** Get Locale time format
*
* @return The locale time format.
*/
LocaleTimeFormat locale_get_time_format();
/** Set Locale Time Format
*
* @param[in] format The Locale Time Format
*/
void locale_set_time_format(LocaleTimeFormat format);
/** Format time to furi string
*
* @param[out] out_str The FuriString to store formatted time
* @param[in] datetime Pointer to the datetime
* @param[in] format The Locale Time Format
* @param[in] show_seconds The show seconds flag
*/
void locale_format_time(
FuriString* out_str,
const FuriHalRtcDateTime* datetime,
const LocaleTimeFormat format,
const bool show_seconds);
/** Get Locale DateFormat
*
* @return The Locale DateFormat.
*/
LocaleDateFormat locale_get_date_format();
/** Set Locale DateFormat
*
* @param[in] format The Locale DateFormat
*/
void locale_set_date_format(LocaleDateFormat format);
/** Format date to furi string
*
* @param[out] out_str The FuriString to store formatted date
* @param[in] datetime Pointer to the datetime
* @param[in] format The format
* @param[in] separator The separator
*/
void locale_format_date(
FuriString* out_str,
const FuriHalRtcDateTime* datetime,
const LocaleDateFormat format,
const char* separator);
#ifdef __cplusplus
}
#endif

View File

@@ -3,7 +3,7 @@ App(
name="System",
apptype=FlipperAppType.SETTINGS,
entry_point="system_settings_app",
requires=["gui"],
requires=["gui", "locale"],
stack_size=1 * 1024,
order=70,
)

View File

@@ -1,6 +1,7 @@
#include "system_settings.h"
#include <loader/loader.h>
#include <lib/toolbox/value_index.h>
#include <locale/locale.h>
const char* const log_level_text[] = {
"Default",
@@ -70,6 +71,59 @@ static void heap_trace_mode_changed(VariableItem* item) {
furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]);
}
const char* const mesurement_units_text[] = {
"Metric",
"Imperial",
};
const uint32_t mesurement_units_value[] = {
LocaleMeasurementUnitsMetric,
LocaleMeasurementUnitsImperial,
};
static void mesurement_units_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, mesurement_units_text[index]);
locale_set_measurement_unit(mesurement_units_value[index]);
}
const char* const time_format_text[] = {
"24h",
"12h",
};
const uint32_t time_format_value[] = {
LocaleTimeFormat24h,
LocaleTimeFormat12h,
};
static void time_format_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, time_format_text[index]);
locale_set_time_format(time_format_value[index]);
}
const char* const date_format_text[] = {
"D/M/Y",
"M/D/Y",
"Y/M/D",
};
const uint32_t date_format_value[] = {
LocaleDateFormatDMY,
LocaleDateFormatMDY,
LocaleDateFormatYMD,
};
static void date_format_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, date_format_text[index]);
locale_set_date_format(date_format_value[index]);
}
static uint32_t system_settings_exit(void* context) {
UNUSED(context);
return VIEW_NONE;
@@ -91,6 +145,31 @@ SystemSettings* system_settings_alloc() {
uint8_t value_index;
app->var_item_list = variable_item_list_alloc();
item = variable_item_list_add(
app->var_item_list,
"Units",
COUNT_OF(mesurement_units_text),
mesurement_units_changed,
app);
value_index = value_index_uint32(
locale_get_measurement_unit(), mesurement_units_value, COUNT_OF(mesurement_units_value));
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, mesurement_units_text[value_index]);
item = variable_item_list_add(
app->var_item_list, "Time Format", COUNT_OF(time_format_text), time_format_changed, app);
value_index = value_index_uint32(
locale_get_time_format(), time_format_value, COUNT_OF(time_format_value));
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, time_format_text[value_index]);
item = variable_item_list_add(
app->var_item_list, "Date Format", COUNT_OF(date_format_text), date_format_changed, app);
value_index = value_index_uint32(
locale_get_date_format(), date_format_value, COUNT_OF(date_format_value));
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, date_format_text[value_index]);
item = variable_item_list_add(
app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app);
value_index = value_index_uint32(