Merge branch 'release-candidate' into release
This commit is contained in:
commit
f8c8e63adf
@ -11,8 +11,8 @@ volatile int WIEGAND::_bitCount = 0;
|
||||
int WIEGAND::_wiegandType = 0;
|
||||
|
||||
constexpr uint32_t clocks_in_ms = 64 * 1000;
|
||||
const GpioPin* pinD0 = &gpio_ext_pa4;
|
||||
const GpioPin* pinD1 = &gpio_ext_pa7;
|
||||
const GpioPin* const pinD0 = &gpio_ext_pa4;
|
||||
const GpioPin* const pinD1 = &gpio_ext_pa7;
|
||||
|
||||
WIEGAND::WIEGAND() {
|
||||
}
|
||||
@ -31,9 +31,9 @@ int WIEGAND::getWiegandType() {
|
||||
|
||||
bool WIEGAND::available() {
|
||||
bool ret;
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
ret = DoWiegandConversion();
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -221,4 +221,4 @@ bool WIEGAND::DoWiegandConversion() {
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ bool AccessorSceneStart::on_event(AccessorApp* app, AccessorEvent* event) {
|
||||
data[i] = wiegand->getCodeHigh() >> ((i - 4) * 8);
|
||||
}
|
||||
} else {
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
if(onewire->reset()) {
|
||||
type = 255;
|
||||
onewire->write(0x33);
|
||||
@ -49,7 +49,7 @@ bool AccessorSceneStart::on_event(AccessorApp* app, AccessorEvent* event) {
|
||||
data[i] = data[i + 1];
|
||||
}
|
||||
}
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
if(type > 0) {
|
||||
@ -85,4 +85,4 @@ void AccessorSceneStart::on_exit(AccessorApp* app) {
|
||||
Popup* popup = app->get_view_manager()->get_popup();
|
||||
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +39,10 @@ ArchiveApp* archive_alloc() {
|
||||
view_dispatcher_add_view(
|
||||
archive->view_dispatcher, ArchiveViewTextInput, text_input_get_view(archive->text_input));
|
||||
|
||||
archive->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
archive->view_dispatcher, ArchiveViewWidget, widget_get_view(archive->widget));
|
||||
|
||||
return archive;
|
||||
}
|
||||
|
||||
@ -47,6 +51,8 @@ void archive_free(ArchiveApp* archive) {
|
||||
|
||||
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewBrowser);
|
||||
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput);
|
||||
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewWidget);
|
||||
widget_free(archive->widget);
|
||||
view_dispatcher_free(archive->view_dispatcher);
|
||||
scene_manager_free(archive->scene_manager);
|
||||
browser_free(archive->browser);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <loader/loader.h>
|
||||
|
||||
#include "views/archive_browser_view.h"
|
||||
@ -15,6 +16,7 @@
|
||||
typedef enum {
|
||||
ArchiveViewBrowser,
|
||||
ArchiveViewTextInput,
|
||||
ArchiveViewWidget,
|
||||
ArchiveViewTotal,
|
||||
} ArchiveViewEnum;
|
||||
|
||||
@ -24,6 +26,7 @@ struct ArchiveApp {
|
||||
SceneManager* scene_manager;
|
||||
ArchiveBrowserView* browser;
|
||||
TextInput* text_input;
|
||||
Widget* widget;
|
||||
char text_store[MAX_NAME_LEN];
|
||||
char file_extension[MAX_EXT_LEN + 1];
|
||||
};
|
||||
|
||||
74
applications/archive/helpers/archive_apps.c
Normal file
74
applications/archive/helpers/archive_apps.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include "archive_files.h"
|
||||
#include "archive_apps.h"
|
||||
#include "archive_browser.h"
|
||||
|
||||
static const char* known_apps[] = {
|
||||
[ArchiveAppTypeU2f] = "u2f",
|
||||
};
|
||||
|
||||
ArchiveAppTypeEnum archive_get_app_type(const char* path) {
|
||||
for(size_t i = 0; i < SIZEOF_ARRAY(known_apps); i++) {
|
||||
if(strncmp(path, known_apps[i], strlen(known_apps[i])) != STRING_FAILURE) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return ArchiveAppTypeUnknown;
|
||||
}
|
||||
|
||||
bool archive_app_is_available(void* context, const char* path) {
|
||||
furi_assert(path);
|
||||
|
||||
ArchiveAppTypeEnum app = archive_get_app_type(path);
|
||||
|
||||
if(app == ArchiveAppTypeU2f) {
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, "/any/u2f/key.u2f", &file_exists);
|
||||
if(file_exists) {
|
||||
file_worker_is_file_exist(file_worker, "/any/u2f/cnt.u2f", &file_exists);
|
||||
}
|
||||
file_worker_free(file_worker);
|
||||
return file_exists;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool archive_app_read_dir(void* context, const char* path) {
|
||||
furi_assert(context);
|
||||
furi_assert(path);
|
||||
ArchiveBrowserView* browser = context;
|
||||
|
||||
ArchiveAppTypeEnum app = archive_get_app_type(path);
|
||||
|
||||
if(app == ArchiveAppTypeU2f) {
|
||||
archive_add_app_item(browser, "/app:u2f/U2F Token");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void archive_app_delete_file(void* context, const char* path) {
|
||||
furi_assert(context);
|
||||
furi_assert(path);
|
||||
ArchiveBrowserView* browser = context;
|
||||
|
||||
ArchiveAppTypeEnum app = archive_get_app_type(path);
|
||||
bool res = false;
|
||||
|
||||
if(app == ArchiveAppTypeU2f) {
|
||||
FileWorker* file_worker = file_worker_alloc(true);
|
||||
res = file_worker_remove(file_worker, "/any/u2f/key.u2f");
|
||||
res |= file_worker_remove(file_worker, "/any/u2f/cnt.u2f");
|
||||
file_worker_free(file_worker);
|
||||
|
||||
if(archive_is_favorite("/app:u2f/U2F Token")) {
|
||||
archive_favorites_delete("/app:u2f/U2F Token");
|
||||
}
|
||||
}
|
||||
|
||||
if(res) {
|
||||
archive_file_array_rm_selected(browser);
|
||||
}
|
||||
}
|
||||
21
applications/archive/helpers/archive_apps.h
Normal file
21
applications/archive/helpers/archive_apps.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
ArchiveAppTypeU2f,
|
||||
ArchiveAppTypeUnknown,
|
||||
ArchiveAppsTotal,
|
||||
} ArchiveAppTypeEnum;
|
||||
|
||||
static const ArchiveFileTypeEnum app_file_types[] = {
|
||||
[ArchiveAppTypeU2f] = ArchiveFileTypeU2f,
|
||||
[ArchiveAppTypeUnknown] = ArchiveFileTypeUnknown,
|
||||
};
|
||||
|
||||
static inline const ArchiveFileTypeEnum archive_get_app_filetype(ArchiveAppTypeEnum app) {
|
||||
return app_file_types[app];
|
||||
}
|
||||
|
||||
ArchiveAppTypeEnum archive_get_app_type(const char* path);
|
||||
bool archive_app_is_available(void* context, const char* path);
|
||||
bool archive_app_read_dir(void* context, const char* path);
|
||||
void archive_app_delete_file(void* context, const char* path);
|
||||
@ -1,5 +1,7 @@
|
||||
#include "archive_files.h"
|
||||
#include "archive_apps.h"
|
||||
#include "archive_browser.h"
|
||||
#include "math.h"
|
||||
#include <math.h>
|
||||
|
||||
void archive_update_offset(ArchiveBrowserView* browser) {
|
||||
furi_assert(browser);
|
||||
@ -177,24 +179,53 @@ void archive_set_last_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) {
|
||||
});
|
||||
}
|
||||
|
||||
void archive_add_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name) {
|
||||
void archive_add_app_item(ArchiveBrowserView* browser, const char* name) {
|
||||
furi_assert(browser);
|
||||
furi_assert(name);
|
||||
|
||||
ArchiveFile_t item;
|
||||
|
||||
string_t full_name;
|
||||
|
||||
string_init_set(full_name, browser->path);
|
||||
string_cat_printf(full_name, "/%s", name);
|
||||
|
||||
char* app_name = strchr(string_get_cstr(full_name), ':');
|
||||
if(app_name == NULL) {
|
||||
string_clear(full_name);
|
||||
return;
|
||||
}
|
||||
|
||||
ArchiveFile_t_init(&item);
|
||||
string_init_set_str(item.name, name);
|
||||
set_file_type(&item, NULL, app_name + 1, true);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
files_array_push_back(model->files, item);
|
||||
return false;
|
||||
});
|
||||
ArchiveFile_t_clear(&item);
|
||||
string_clear(full_name);
|
||||
}
|
||||
|
||||
void archive_add_file_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name) {
|
||||
furi_assert(browser);
|
||||
furi_assert(file_info);
|
||||
furi_assert(name);
|
||||
|
||||
ArchiveFile_t item;
|
||||
|
||||
if(filter_by_extension(file_info, get_tab_ext(archive_get_tab(browser)), name)) {
|
||||
if(filter_by_extension(file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) {
|
||||
ArchiveFile_t_init(&item);
|
||||
string_init_set_str(item.name, name);
|
||||
set_file_type(&item, file_info);
|
||||
set_file_type(&item, file_info, archive_get_path(browser), false);
|
||||
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
files_array_push_back(model->files, item);
|
||||
return false;
|
||||
});
|
||||
|
||||
ArchiveFile_t_clear(&item);
|
||||
}
|
||||
}
|
||||
@ -208,8 +239,7 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
|
||||
|
||||
if(show) {
|
||||
ArchiveFile_t* selected = files_array_get(model->files, model->idx);
|
||||
selected->fav = archive_is_favorite(
|
||||
"%s/%s", string_get_cstr(browser->path), string_get_cstr(selected->name));
|
||||
selected->fav = archive_is_favorite("%s", string_get_cstr(selected->name));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -245,12 +275,18 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
||||
|
||||
archive_set_tab(browser, tab);
|
||||
|
||||
if((tab != ArchiveTabFavorites &&
|
||||
!archive_dir_empty(browser, archive_get_default_path(tab))) ||
|
||||
(tab == ArchiveTabFavorites && !archive_favorites_count(browser))) {
|
||||
if(tab != ArchiveTabBrowser) {
|
||||
archive_switch_tab(browser, key);
|
||||
}
|
||||
const char* path = archive_get_default_path(tab);
|
||||
bool tab_empty = true;
|
||||
if(tab == ArchiveTabFavorites) {
|
||||
if(archive_favorites_count(browser) > 0) tab_empty = false;
|
||||
} else if(strncmp(path, "/app:", 5) == 0) {
|
||||
if(archive_app_is_available(browser, path)) tab_empty = false;
|
||||
} else {
|
||||
if(archive_dir_not_empty(browser, archive_get_default_path(tab))) tab_empty = false;
|
||||
}
|
||||
|
||||
if((tab_empty) && (tab != ArchiveTabBrowser)) {
|
||||
archive_switch_tab(browser, key);
|
||||
} else {
|
||||
with_view_model(
|
||||
browser->view, (ArchiveBrowserViewModel * model) {
|
||||
@ -277,8 +313,7 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) {
|
||||
return false;
|
||||
});
|
||||
|
||||
string_cat(browser->path, "/");
|
||||
string_cat(browser->path, name);
|
||||
string_set(browser->path, name);
|
||||
|
||||
archive_switch_dir(browser, string_get_cstr(browser->path));
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ static const char* tab_default_paths[] = {
|
||||
[ArchiveTabSubGhz] = "/any/subghz",
|
||||
[ArchiveTabLFRFID] = "/any/lfrfid",
|
||||
[ArchiveTabIrda] = "/any/irda",
|
||||
[ArchiveTabBadUsb] = "/any/badusb",
|
||||
[ArchiveTabU2f] = "/app:u2f",
|
||||
[ArchiveTabBrowser] = "/any",
|
||||
};
|
||||
|
||||
@ -20,30 +22,37 @@ static const char* known_ext[] = {
|
||||
[ArchiveFileTypeSubGhz] = ".sub",
|
||||
[ArchiveFileTypeLFRFID] = ".rfid",
|
||||
[ArchiveFileTypeIrda] = ".ir",
|
||||
[ArchiveFileTypeBadUsb] = ".txt",
|
||||
[ArchiveFileTypeU2f] = "?",
|
||||
[ArchiveFileTypeFolder] = "?",
|
||||
[ArchiveFileTypeUnknown] = "*",
|
||||
};
|
||||
|
||||
static inline const char* get_tab_ext(ArchiveTabEnum tab) {
|
||||
switch(tab) {
|
||||
case ArchiveTabIButton:
|
||||
return known_ext[ArchiveFileTypeIButton];
|
||||
case ArchiveTabNFC:
|
||||
return known_ext[ArchiveFileTypeNFC];
|
||||
case ArchiveTabSubGhz:
|
||||
return known_ext[ArchiveFileTypeSubGhz];
|
||||
case ArchiveTabLFRFID:
|
||||
return known_ext[ArchiveFileTypeLFRFID];
|
||||
case ArchiveTabIrda:
|
||||
return known_ext[ArchiveFileTypeIrda];
|
||||
default:
|
||||
return "*";
|
||||
}
|
||||
static const ArchiveFileTypeEnum known_type[] = {
|
||||
[ArchiveTabFavorites] = ArchiveFileTypeUnknown,
|
||||
[ArchiveTabIButton] = ArchiveFileTypeIButton,
|
||||
[ArchiveTabNFC] = ArchiveFileTypeNFC,
|
||||
[ArchiveTabSubGhz] = ArchiveFileTypeSubGhz,
|
||||
[ArchiveTabLFRFID] = ArchiveFileTypeLFRFID,
|
||||
[ArchiveTabIrda] = ArchiveFileTypeIrda,
|
||||
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
|
||||
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
||||
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
||||
};
|
||||
|
||||
static inline const ArchiveFileTypeEnum archive_get_tab_filetype(ArchiveTabEnum tab) {
|
||||
return known_type[tab];
|
||||
}
|
||||
|
||||
static inline const char* archive_get_tab_ext(ArchiveTabEnum tab) {
|
||||
return known_ext[archive_get_tab_filetype(tab)];
|
||||
}
|
||||
|
||||
static inline const char* archive_get_default_path(ArchiveTabEnum tab) {
|
||||
return tab_default_paths[tab];
|
||||
}
|
||||
|
||||
inline bool is_known_app(ArchiveFileTypeEnum type) {
|
||||
inline bool archive_is_known_app(ArchiveFileTypeEnum type) {
|
||||
return (type != ArchiveFileTypeFolder && type != ArchiveFileTypeUnknown);
|
||||
}
|
||||
|
||||
@ -62,7 +71,8 @@ uint8_t archive_get_depth(ArchiveBrowserView* browser);
|
||||
const char* archive_get_path(ArchiveBrowserView* browser);
|
||||
const char* archive_get_name(ArchiveBrowserView* browser);
|
||||
|
||||
void archive_add_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name);
|
||||
void archive_add_app_item(ArchiveBrowserView* browser, const char* name);
|
||||
void archive_add_file_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name);
|
||||
void archive_show_file_menu(ArchiveBrowserView* browser, bool show);
|
||||
void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active);
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
|
||||
#include "archive_favorites.h"
|
||||
#include "archive_files.h"
|
||||
#include "archive_apps.h"
|
||||
#include "archive_browser.h"
|
||||
|
||||
uint16_t archive_favorites_count(void* context) {
|
||||
@ -46,10 +48,16 @@ static bool archive_favourites_rescan() {
|
||||
break;
|
||||
}
|
||||
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
|
||||
if(file_exists) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
if(string_search(buffer, "/app:") == 0) {
|
||||
if(archive_app_is_available(NULL, string_get_cstr(buffer))) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
}
|
||||
} else {
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
|
||||
if(file_exists) {
|
||||
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,13 +96,22 @@ bool archive_favorites_read(void* context) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
|
||||
if(string_search(buffer, "/app:") == 0) {
|
||||
if(archive_app_is_available(browser, string_get_cstr(buffer))) {
|
||||
archive_add_app_item(browser, string_get_cstr(buffer));
|
||||
} else {
|
||||
need_refresh = true;
|
||||
}
|
||||
} else {
|
||||
bool file_exists = false;
|
||||
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
|
||||
|
||||
if(file_exists)
|
||||
archive_add_file_item(browser, &file_info, string_get_cstr(buffer));
|
||||
else
|
||||
need_refresh = true;
|
||||
}
|
||||
|
||||
if(file_exists)
|
||||
archive_add_item(browser, &file_info, string_get_cstr(buffer));
|
||||
else
|
||||
need_refresh = true;
|
||||
string_reset(buffer);
|
||||
}
|
||||
}
|
||||
@ -185,8 +202,7 @@ bool archive_is_favorite(const char* format, ...) {
|
||||
return found;
|
||||
}
|
||||
|
||||
bool archive_favorites_rename(const char* file_path, const char* src, const char* dst) {
|
||||
furi_assert(file_path);
|
||||
bool archive_favorites_rename(const char* src, const char* dst) {
|
||||
furi_assert(src);
|
||||
furi_assert(dst);
|
||||
|
||||
@ -198,7 +214,7 @@ bool archive_favorites_rename(const char* file_path, const char* src, const char
|
||||
string_init(buffer);
|
||||
string_init(path);
|
||||
|
||||
string_printf(path, "%s/%s", file_path, src);
|
||||
string_printf(path, "%s", src);
|
||||
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
|
||||
if(result) {
|
||||
|
||||
@ -8,6 +8,6 @@ uint16_t archive_favorites_count(void* context);
|
||||
bool archive_favorites_read(void* context);
|
||||
bool archive_favorites_delete(const char* format, ...);
|
||||
bool archive_is_favorite(const char* format, ...);
|
||||
bool archive_favorites_rename(const char* file_path, const char* src, const char* dst);
|
||||
bool archive_favorites_rename(const char* src, const char* dst);
|
||||
void archive_add_to_favorites(const char* file_path);
|
||||
void archive_favorites_save(void* context);
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
#include "archive_files.h"
|
||||
#include "archive_apps.h"
|
||||
#include "archive_browser.h"
|
||||
|
||||
#define TAG "Archive"
|
||||
|
||||
#define ASSETS_DIR "assets"
|
||||
|
||||
bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) {
|
||||
furi_assert(file_info);
|
||||
furi_assert(tab_ext);
|
||||
@ -15,7 +18,11 @@ bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* n
|
||||
} else if(strstr(name, tab_ext) != NULL) {
|
||||
result = true;
|
||||
} else if(file_info->flags & FSF_DIRECTORY) {
|
||||
result = true;
|
||||
if(strstr(name, ASSETS_DIR) != NULL) {
|
||||
result = false; // Skip assets folder in all tabs except browser
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -38,21 +45,36 @@ void archive_get_file_extension(char* name, char* ext) {
|
||||
strncpy(ext, dot, MAX_EXT_LEN);
|
||||
}
|
||||
|
||||
void set_file_type(ArchiveFile_t* file, FileInfo* file_info) {
|
||||
void set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app) {
|
||||
furi_assert(file);
|
||||
furi_assert(file_info);
|
||||
|
||||
for(size_t i = 0; i < SIZEOF_ARRAY(known_ext); i++) {
|
||||
if(string_search_str(file->name, known_ext[i], 0) != STRING_FAILURE) {
|
||||
file->type = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(file_info->flags & FSF_DIRECTORY) {
|
||||
file->type = ArchiveFileTypeFolder;
|
||||
file->is_app = is_app;
|
||||
if(is_app) {
|
||||
file->type = archive_get_app_filetype(archive_get_app_type(path));
|
||||
} else {
|
||||
file->type = ArchiveFileTypeUnknown;
|
||||
furi_assert(file_info);
|
||||
|
||||
for(size_t i = 0; i < SIZEOF_ARRAY(known_ext); i++) {
|
||||
if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue;
|
||||
if(string_search_str(file->name, known_ext[i], 0) != STRING_FAILURE) {
|
||||
if(i == ArchiveFileTypeBadUsb) {
|
||||
if(string_search_str(file->name, archive_get_default_path(ArchiveTabBadUsb)) ==
|
||||
0) {
|
||||
file->type = i;
|
||||
return; // *.txt file is a BadUSB script only if it is in BadUSB folder
|
||||
}
|
||||
} else {
|
||||
file->type = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(file_info->flags & FSF_DIRECTORY) {
|
||||
file->type = ArchiveFileTypeFolder;
|
||||
} else {
|
||||
file->type = ArchiveFileTypeUnknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,17 +85,21 @@ bool archive_get_filenames(void* context, const char* path) {
|
||||
ArchiveBrowserView* browser = context;
|
||||
archive_file_array_rm_all(browser);
|
||||
|
||||
if(archive_get_tab(browser) != ArchiveTabFavorites) {
|
||||
res = archive_read_dir(browser, path);
|
||||
} else {
|
||||
if(archive_get_tab(browser) == ArchiveTabFavorites) {
|
||||
res = archive_favorites_read(browser);
|
||||
} else if(strncmp(path, "/app:", 5) == 0) {
|
||||
res = archive_app_read_dir(browser, path);
|
||||
} else {
|
||||
res = archive_read_dir(browser, path);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool archive_dir_empty(void* context, const char* path) { // can be simpler?
|
||||
bool archive_dir_not_empty(void* context, const char* path) { // can be simpler?
|
||||
furi_assert(context);
|
||||
|
||||
ArchiveBrowserView* browser = context;
|
||||
|
||||
FileInfo file_info;
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* directory = storage_file_alloc(fs_api);
|
||||
@ -92,8 +118,11 @@ bool archive_dir_empty(void* context, const char* path) { // can be simpler?
|
||||
}
|
||||
if(files_found) {
|
||||
break;
|
||||
} else if(storage_file_get_error(directory) == FSE_OK) {
|
||||
files_found = name[0];
|
||||
} else if((storage_file_get_error(directory) == FSE_OK) && (name[0])) {
|
||||
if(filter_by_extension(
|
||||
&file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) {
|
||||
files_found = true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -114,6 +143,8 @@ bool archive_read_dir(void* context, const char* path) {
|
||||
Storage* fs_api = furi_record_open("storage");
|
||||
File* directory = storage_file_alloc(fs_api);
|
||||
char name[MAX_NAME_LEN];
|
||||
snprintf(name, MAX_NAME_LEN, "%s/", path);
|
||||
size_t path_len = strlen(name);
|
||||
size_t files_cnt = 0;
|
||||
|
||||
if(!storage_dir_open(directory, path)) {
|
||||
@ -123,13 +154,14 @@ bool archive_read_dir(void* context, const char* path) {
|
||||
}
|
||||
|
||||
while(1) {
|
||||
if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) {
|
||||
if(!storage_dir_read(directory, &file_info, &name[path_len], MAX_NAME_LEN - path_len)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(files_cnt > MAX_FILES) {
|
||||
break;
|
||||
} else if(storage_file_get_error(directory) == FSE_OK) {
|
||||
archive_add_item(browser, &file_info, name);
|
||||
archive_add_file_item(browser, &file_info, name);
|
||||
++files_cnt;
|
||||
} else {
|
||||
storage_dir_close(directory);
|
||||
|
||||
@ -9,29 +9,38 @@ typedef enum {
|
||||
ArchiveFileTypeSubGhz,
|
||||
ArchiveFileTypeLFRFID,
|
||||
ArchiveFileTypeIrda,
|
||||
ArchiveFileTypeBadUsb,
|
||||
ArchiveFileTypeU2f,
|
||||
ArchiveFileTypeFolder,
|
||||
ArchiveFileTypeUnknown,
|
||||
AppIdTotal,
|
||||
ArchiveFileTypesTotal,
|
||||
} ArchiveFileTypeEnum;
|
||||
|
||||
typedef struct {
|
||||
string_t name;
|
||||
ArchiveFileTypeEnum type;
|
||||
bool fav;
|
||||
bool is_app;
|
||||
} ArchiveFile_t;
|
||||
|
||||
static void ArchiveFile_t_init(ArchiveFile_t* obj) {
|
||||
obj->type = ArchiveFileTypeUnknown;
|
||||
obj->is_app = false;
|
||||
obj->fav = false;
|
||||
string_init(obj->name);
|
||||
}
|
||||
|
||||
static void ArchiveFile_t_init_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
|
||||
obj->type = src->type;
|
||||
obj->is_app = src->is_app;
|
||||
obj->fav = src->fav;
|
||||
string_init_set(obj->name, src->name);
|
||||
}
|
||||
|
||||
static void ArchiveFile_t_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
|
||||
obj->type = src->type;
|
||||
obj->is_app = src->is_app;
|
||||
obj->fav = src->fav;
|
||||
string_set(obj->name, src->name);
|
||||
}
|
||||
|
||||
@ -48,11 +57,11 @@ ARRAY_DEF(
|
||||
CLEAR(API_2(ArchiveFile_t_clear))))
|
||||
|
||||
bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name);
|
||||
void set_file_type(ArchiveFile_t* file, FileInfo* file_info);
|
||||
void set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app);
|
||||
void archive_trim_file_path(char* name, bool ext);
|
||||
void archive_get_file_extension(char* name, char* ext);
|
||||
bool archive_get_filenames(void* context, const char* path);
|
||||
bool archive_dir_empty(void* context, const char* path);
|
||||
bool archive_dir_not_empty(void* context, const char* path);
|
||||
bool archive_read_dir(void* context, const char* path);
|
||||
void archive_file_append(const char* path, const char* format, ...);
|
||||
void archive_delete_file(void* context, const char* format, ...);
|
||||
@ -1,33 +1,41 @@
|
||||
#include "../archive_i.h"
|
||||
#include "../helpers/archive_files.h"
|
||||
#include "../helpers/archive_apps.h"
|
||||
#include "../helpers/archive_favorites.h"
|
||||
#include "../helpers/archive_browser.h"
|
||||
#include "../views/archive_browser_view.h"
|
||||
|
||||
#define TAG "ArchiveSceneBrowser"
|
||||
|
||||
static const char* flipper_app_name[] = {
|
||||
[ArchiveFileTypeIButton] = "iButton",
|
||||
[ArchiveFileTypeNFC] = "NFC",
|
||||
[ArchiveFileTypeSubGhz] = "Sub-GHz",
|
||||
[ArchiveFileTypeLFRFID] = "125 kHz RFID",
|
||||
[ArchiveFileTypeIrda] = "Infrared",
|
||||
[ArchiveFileTypeBadUsb] = "Bad USB",
|
||||
[ArchiveFileTypeU2f] = "U2F",
|
||||
};
|
||||
|
||||
static void archive_run_in_app(
|
||||
ArchiveBrowserView* browser,
|
||||
ArchiveFile_t* selected,
|
||||
bool full_path_provided) {
|
||||
static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected) {
|
||||
Loader* loader = furi_record_open("loader");
|
||||
|
||||
string_t full_path;
|
||||
if(!full_path_provided) {
|
||||
string_init_printf(
|
||||
full_path, "%s/%s", string_get_cstr(browser->path), string_get_cstr(selected->name));
|
||||
LoaderStatus status;
|
||||
if(selected->is_app) {
|
||||
char* param = strrchr(string_get_cstr(selected->name), '/');
|
||||
if(param != NULL) {
|
||||
param++;
|
||||
}
|
||||
status = loader_start(loader, flipper_app_name[selected->type], param);
|
||||
} else {
|
||||
string_init_set(full_path, selected->name);
|
||||
status = loader_start(
|
||||
loader, flipper_app_name[selected->type], string_get_cstr(selected->name));
|
||||
}
|
||||
|
||||
if(status != LoaderStatusOk) {
|
||||
FURI_LOG_E(TAG, "loader_start failed: %d", status);
|
||||
}
|
||||
loader_start(loader, flipper_app_name[selected->type], string_get_cstr(full_path));
|
||||
|
||||
string_clear(full_path);
|
||||
furi_record_close("loader");
|
||||
}
|
||||
|
||||
@ -50,9 +58,8 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
ArchiveBrowserView* browser = archive->browser;
|
||||
ArchiveFile_t* selected = archive_get_current_file(browser);
|
||||
|
||||
const char* path = archive_get_path(browser);
|
||||
const char* name = archive_get_name(browser);
|
||||
bool known_app = is_known_app(selected->type);
|
||||
bool known_app = archive_is_known_app(selected->type);
|
||||
bool favorites = archive_get_tab(browser) == ArchiveTabFavorites;
|
||||
bool consumed = false;
|
||||
|
||||
@ -68,7 +75,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
break;
|
||||
case ArchiveBrowserEventFileMenuRun:
|
||||
if(known_app) {
|
||||
archive_run_in_app(browser, selected, favorites);
|
||||
archive_run_in_app(browser, selected);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
@ -78,10 +85,10 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
archive_file_array_rm_selected(browser);
|
||||
archive_show_file_menu(browser, false);
|
||||
} else if(known_app) {
|
||||
if(archive_is_favorite("%s/%s", path, name)) {
|
||||
archive_favorites_delete("%s/%s", path, name);
|
||||
if(archive_is_favorite("%s", name)) {
|
||||
archive_favorites_delete("%s", name);
|
||||
} else {
|
||||
archive_file_append(ARCHIVE_FAV_PATH, "%s/%s\n", path, name);
|
||||
archive_file_append(ARCHIVE_FAV_PATH, "%s\n", name);
|
||||
}
|
||||
archive_show_file_menu(browser, false);
|
||||
}
|
||||
@ -91,18 +98,13 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
||||
case ArchiveBrowserEventFileMenuAction:
|
||||
if(favorites) {
|
||||
browser->callback(ArchiveBrowserEventEnterFavMove, browser->context);
|
||||
} else if(known_app) {
|
||||
} else if((known_app) && (selected->is_app == false)) {
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneRename);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventFileMenuDelete:
|
||||
if(favorites) {
|
||||
archive_delete_file(browser, "%s", name);
|
||||
} else {
|
||||
archive_delete_file(browser, "%s/%s", path, name);
|
||||
}
|
||||
archive_show_file_menu(browser, false);
|
||||
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete);
|
||||
consumed = true;
|
||||
break;
|
||||
case ArchiveBrowserEventEnterDir:
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
ADD_SCENE(archive, browser, Browser)
|
||||
ADD_SCENE(archive, rename, Rename)
|
||||
ADD_SCENE(archive, delete, Delete)
|
||||
|
||||
70
applications/archive/scenes/archive_scene_delete.c
Normal file
70
applications/archive/scenes/archive_scene_delete.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include "../archive_i.h"
|
||||
#include "../helpers/archive_favorites.h"
|
||||
#include "../helpers/archive_files.h"
|
||||
#include "../helpers/archive_apps.h"
|
||||
#include "../helpers/archive_browser.h"
|
||||
|
||||
#define SCENE_DELETE_CUSTOM_EVENT (0UL)
|
||||
#define MAX_TEXT_INPUT_LEN 22
|
||||
|
||||
void archive_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* app = (ArchiveApp*)context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void archive_scene_delete_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* app = (ArchiveApp*)context;
|
||||
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Back", archive_scene_delete_widget_callback, app);
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app);
|
||||
|
||||
ArchiveFile_t* current = archive_get_current_file(app->browser);
|
||||
strlcpy(app->text_store, string_get_cstr(current->name), MAX_NAME_LEN);
|
||||
char* name = strrchr(app->text_store, '/');
|
||||
if(name != NULL) {
|
||||
name++;
|
||||
}
|
||||
|
||||
char delete_str[64];
|
||||
snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", name);
|
||||
widget_add_text_box_element(app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget);
|
||||
}
|
||||
|
||||
bool archive_scene_delete_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* app = (ArchiveApp*)context;
|
||||
|
||||
ArchiveBrowserView* browser = app->browser;
|
||||
ArchiveFile_t* selected = archive_get_current_file(browser);
|
||||
const char* name = archive_get_name(browser);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeRight) {
|
||||
if(selected->is_app) {
|
||||
archive_app_delete_file(browser, name);
|
||||
} else {
|
||||
archive_delete_file(browser, "%s", name);
|
||||
}
|
||||
archive_show_file_menu(browser, false);
|
||||
return scene_manager_previous_scene(app->scene_manager);
|
||||
} else if(event.event == GuiButtonTypeLeft) {
|
||||
return scene_manager_previous_scene(app->scene_manager);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void archive_scene_delete_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
ArchiveApp* app = (ArchiveApp*)context;
|
||||
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@ -52,7 +52,8 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
|
||||
const char* path = archive_get_path(archive->browser);
|
||||
const char* name = archive_get_name(archive->browser);
|
||||
|
||||
string_init_printf(buffer_src, "%s/%s", path, name);
|
||||
string_init_printf(buffer_src, "%s", name);
|
||||
//TODO: take path from src name
|
||||
string_init_printf(buffer_dst, "%s/%s", path, archive->text_store);
|
||||
|
||||
// append extension
|
||||
@ -64,7 +65,7 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_record_close("storage");
|
||||
|
||||
if(file->fav) {
|
||||
archive_favorites_rename(path, name, string_get_cstr(buffer_dst));
|
||||
archive_favorites_rename(name, string_get_cstr(buffer_dst));
|
||||
}
|
||||
|
||||
string_clear(buffer_src);
|
||||
|
||||
@ -10,6 +10,8 @@ static const char* ArchiveTabNames[] = {
|
||||
[ArchiveTabSubGhz] = "Sub-GHz",
|
||||
[ArchiveTabLFRFID] = "RFID LF",
|
||||
[ArchiveTabIrda] = "Infrared",
|
||||
[ArchiveTabBadUsb] = "Bad USB",
|
||||
[ArchiveTabU2f] = "U2F",
|
||||
[ArchiveTabBrowser] = "Browser"};
|
||||
|
||||
static const Icon* ArchiveItemIcons[] = {
|
||||
@ -18,6 +20,8 @@ static const Icon* ArchiveItemIcons[] = {
|
||||
[ArchiveFileTypeSubGhz] = &I_sub1_10px,
|
||||
[ArchiveFileTypeLFRFID] = &I_125_10px,
|
||||
[ArchiveFileTypeIrda] = &I_ir_10px,
|
||||
[ArchiveFileTypeBadUsb] = &I_badusb_10px,
|
||||
[ArchiveFileTypeU2f] = &I_u2f_10px,
|
||||
[ArchiveFileTypeFolder] = &I_dir_10px,
|
||||
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
||||
};
|
||||
@ -47,15 +51,20 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
|
||||
ArchiveFile_t* selected = files_array_get(model->files, model->idx);
|
||||
|
||||
if(!is_known_app(selected->type)) {
|
||||
if(!archive_is_known_app(selected->type)) {
|
||||
string_set_str(menu[0], "---");
|
||||
string_set_str(menu[1], "---");
|
||||
string_set_str(menu[2], "---");
|
||||
} else if(selected->fav) {
|
||||
} else {
|
||||
if(model->tab_idx == ArchiveTabFavorites) {
|
||||
string_set_str(menu[2], "Move");
|
||||
} else if(selected->is_app) {
|
||||
string_set_str(menu[2], "---");
|
||||
}
|
||||
}
|
||||
|
||||
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
|
||||
string_set_str(menu[1], "Unpin");
|
||||
} else if(model->tab_idx == ArchiveTabFavorites) {
|
||||
string_set_str(menu[1], "Unpin");
|
||||
string_set_str(menu[2], "Move");
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < MENU_ITEMS; i++) {
|
||||
@ -102,7 +111,7 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
||||
ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0));
|
||||
|
||||
strlcpy(cstr_buff, string_get_cstr(file->name), string_size(file->name) + 1);
|
||||
archive_trim_file_path(cstr_buff, is_known_app(file->type));
|
||||
archive_trim_file_path(cstr_buff, archive_is_known_app(file->type));
|
||||
string_init_set_str(str_buff, cstr_buff);
|
||||
elements_string_fit_width(
|
||||
canvas, str_buff, (scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX) - x_offset);
|
||||
|
||||
@ -24,6 +24,8 @@ typedef enum {
|
||||
ArchiveTabNFC,
|
||||
ArchiveTabIrda,
|
||||
ArchiveTabIButton,
|
||||
ArchiveTabBadUsb,
|
||||
ArchiveTabU2f,
|
||||
ArchiveTabBrowser,
|
||||
ArchiveTabTotal,
|
||||
} ArchiveTabEnum;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <storage/storage.h>
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
@ -39,27 +40,34 @@ static bool bad_usb_check_assets() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
BadUsbApp* bad_usb_app_alloc() {
|
||||
BadUsbApp* bad_usb_app_alloc(char* arg) {
|
||||
BadUsbApp* app = furi_alloc(sizeof(BadUsbApp));
|
||||
|
||||
if(arg != NULL) {
|
||||
string_t filename;
|
||||
string_init(filename);
|
||||
path_extract_filename_no_ext(arg, filename);
|
||||
strncpy(app->file_name, string_get_cstr(filename), BAD_USB_FILE_NAME_LEN);
|
||||
string_clear(filename);
|
||||
}
|
||||
|
||||
app->gui = furi_record_open("gui");
|
||||
app->notifications = furi_record_open("notification");
|
||||
app->dialogs = furi_record_open("dialogs");
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&bad_usb_scene_handlers, app);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
|
||||
app->scene_manager = scene_manager_alloc(&bad_usb_scene_handlers, app);
|
||||
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, bad_usb_app_tick_event_callback, 500);
|
||||
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, bad_usb_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, bad_usb_app_back_event_callback);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Custom Widget
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
@ -69,7 +77,11 @@ BadUsbApp* bad_usb_app_alloc() {
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view));
|
||||
|
||||
if(bad_usb_check_assets()) {
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
if(*app->file_name != '\0') {
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneWork);
|
||||
} else if(bad_usb_check_assets()) {
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect);
|
||||
} else {
|
||||
scene_manager_next_scene(app->scene_manager, BadUsbSceneError);
|
||||
@ -106,7 +118,7 @@ int32_t bad_usb_app(void* p) {
|
||||
FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
|
||||
furi_hal_usb_set_config(&usb_hid);
|
||||
|
||||
BadUsbApp* bad_usb_app = bad_usb_app_alloc();
|
||||
BadUsbApp* bad_usb_app = bad_usb_app_alloc((char*)p);
|
||||
|
||||
view_dispatcher_run(bad_usb_app->view_dispatcher);
|
||||
|
||||
|
||||
@ -144,7 +144,7 @@ void bad_usb_set_ok_callback(BadUsb* bad_usb, BadUsbOkCallback callback, void* c
|
||||
bad_usb->view, (BadUsbModel * model) {
|
||||
bad_usb->callback = callback;
|
||||
bad_usb->context = context;
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ void bad_usb_set_file_name(BadUsb* bad_usb, char* name) {
|
||||
with_view_model(
|
||||
bad_usb->view, (BadUsbModel * model) {
|
||||
model->file_name = name;
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -163,6 +163,6 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
|
||||
bad_usb->view, (BadUsbModel * model) {
|
||||
memcpy(&(model->state), st, sizeof(BadUsbState));
|
||||
model->anim_frame ^= 1;
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -16,9 +16,9 @@ static void bt_draw_statusbar_callback(Canvas* canvas, void* context) {
|
||||
|
||||
Bt* bt = context;
|
||||
if(bt->status == BtStatusAdvertising) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Bluetooth_5x8);
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Bluetooth_Idle_5x8);
|
||||
} else if(bt->status == BtStatusConnected) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_BT_Pair_9x8);
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Bluetooth_Connected_16x8);
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,13 +199,18 @@ static bool bt_on_gap_event_callback(GapEvent event, void* context) {
|
||||
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
if(bt->profile == BtProfileSerial) {
|
||||
// Open RPC session
|
||||
FURI_LOG_I(TAG, "Open RPC connection");
|
||||
bt->rpc_session = rpc_session_open(bt->rpc);
|
||||
rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback);
|
||||
rpc_session_set_buffer_is_empty_callback(
|
||||
bt->rpc_session, furi_hal_bt_serial_notify_buffer_is_empty);
|
||||
rpc_session_set_context(bt->rpc_session, bt);
|
||||
furi_hal_bt_serial_set_event_callback(RPC_BUFFER_SIZE, bt_serial_event_callback, bt);
|
||||
if(bt->rpc_session) {
|
||||
FURI_LOG_I(TAG, "Open RPC connection");
|
||||
rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback);
|
||||
rpc_session_set_buffer_is_empty_callback(
|
||||
bt->rpc_session, furi_hal_bt_serial_notify_buffer_is_empty);
|
||||
rpc_session_set_context(bt->rpc_session, bt);
|
||||
furi_hal_bt_serial_set_event_callback(
|
||||
RPC_BUFFER_SIZE, bt_serial_event_callback, bt);
|
||||
} else {
|
||||
FURI_LOG_W(TAG, "RPC is busy, failed to open new session");
|
||||
}
|
||||
}
|
||||
// Update battery level
|
||||
PowerInfo info;
|
||||
@ -257,10 +262,10 @@ static void bt_on_key_storage_change_callback(uint8_t* addr, uint16_t size, void
|
||||
|
||||
static void bt_statusbar_update(Bt* bt) {
|
||||
if(bt->status == BtStatusAdvertising) {
|
||||
view_port_set_width(bt->statusbar_view_port, icon_get_width(&I_Bluetooth_5x8));
|
||||
view_port_set_width(bt->statusbar_view_port, icon_get_width(&I_Bluetooth_Idle_5x8));
|
||||
view_port_enabled_set(bt->statusbar_view_port, true);
|
||||
} else if(bt->status == BtStatusConnected) {
|
||||
view_port_set_width(bt->statusbar_view_port, icon_get_width(&I_BT_Pair_9x8));
|
||||
view_port_set_width(bt->statusbar_view_port, icon_get_width(&I_Bluetooth_Connected_16x8));
|
||||
view_port_enabled_set(bt->statusbar_view_port, true);
|
||||
} else {
|
||||
view_port_enabled_set(bt->statusbar_view_port, false);
|
||||
|
||||
@ -43,10 +43,11 @@ bool bt_save_key_storage(Bt* bt) {
|
||||
bool bt_delete_key_storage(Bt* bt) {
|
||||
furi_assert(bt);
|
||||
bool delete_succeed = false;
|
||||
bool bt_is_active = furi_hal_bt_is_active();
|
||||
|
||||
furi_hal_bt_stop_advertising();
|
||||
delete_succeed = furi_hal_bt_clear_white_list();
|
||||
if(bt->bt_settings.enabled) {
|
||||
if(bt_is_active) {
|
||||
furi_hal_bt_start_advertising();
|
||||
}
|
||||
|
||||
|
||||
@ -89,7 +89,7 @@ static void view_display_test_draw_callback_move(Canvas* canvas, void* _model) {
|
||||
canvas_draw_box(canvas, x, y, block, block);
|
||||
}
|
||||
|
||||
ViewDrawCallback view_display_test_tests[] = {
|
||||
const ViewDrawCallback view_display_test_tests[] = {
|
||||
view_display_test_draw_callback_intro,
|
||||
view_display_test_draw_callback_fill,
|
||||
view_display_test_draw_callback_hstripe,
|
||||
|
||||
@ -408,6 +408,11 @@ static StorageAnimation*
|
||||
return selected;
|
||||
}
|
||||
|
||||
bool animation_manager_is_animation_loaded(AnimationManager* animation_manager) {
|
||||
furi_assert(animation_manager);
|
||||
return animation_manager->current_animation;
|
||||
}
|
||||
|
||||
void animation_manager_unload_and_stall_animation(AnimationManager* animation_manager) {
|
||||
furi_assert(animation_manager);
|
||||
furi_assert(animation_manager->current_animation);
|
||||
|
||||
@ -133,6 +133,12 @@ void animation_manager_set_interact_callback(
|
||||
*/
|
||||
void animation_manager_interact_process(AnimationManager* animation_manager);
|
||||
|
||||
/** Check if animation loaded
|
||||
*
|
||||
* @animation_manager instance
|
||||
*/
|
||||
bool animation_manager_is_animation_loaded(AnimationManager* animation_manager);
|
||||
|
||||
/**
|
||||
* Unload and Stall animation actions. Draw callback in view
|
||||
* paints first frame of current animation until
|
||||
|
||||
@ -261,7 +261,7 @@ static void animation_storage_free_frames(BubbleAnimation* animation) {
|
||||
}
|
||||
}
|
||||
|
||||
free(icon->frames);
|
||||
free((void*)icon->frames);
|
||||
}
|
||||
|
||||
static bool animation_storage_load_frames(
|
||||
@ -317,7 +317,7 @@ static bool animation_storage_load_frames(
|
||||
break;
|
||||
}
|
||||
|
||||
icon->frames[i] = furi_alloc(file_info.size);
|
||||
FURI_CONST_ASSIGN_PTR(icon->frames[i], furi_alloc(file_info.size));
|
||||
if(storage_file_read(file, (void*)icon->frames[i], file_info.size) != file_info.size) {
|
||||
FURI_LOG_E(TAG, "Read failed: \'%s\'", string_get_cstr(filename));
|
||||
break;
|
||||
|
||||
@ -266,7 +266,7 @@ static Icon* bubble_animation_clone_first_frame(const Icon* icon_orig) {
|
||||
* for compressed header
|
||||
*/
|
||||
size_t max_bitmap_size = ROUND_UP_TO(icon_orig->width, 8) * icon_orig->height + 1;
|
||||
icon_clone->frames[0] = furi_alloc(max_bitmap_size);
|
||||
FURI_CONST_ASSIGN_PTR(icon_clone->frames[0], furi_alloc(max_bitmap_size));
|
||||
memcpy((void*)icon_clone->frames[0], icon_orig->frames[0], max_bitmap_size);
|
||||
FURI_CONST_ASSIGN(icon_clone->frame_count, 1);
|
||||
|
||||
@ -278,7 +278,7 @@ static void bubble_animation_release_frame(Icon** icon) {
|
||||
furi_assert(*icon);
|
||||
|
||||
free((void*)(*icon)->frames[0]);
|
||||
free((*icon)->frames);
|
||||
free((void*)(*icon)->frames);
|
||||
free(*icon);
|
||||
*icon = NULL;
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ OneShotView* one_shot_view_alloc(void) {
|
||||
OneShotView* view = furi_alloc(sizeof(OneShotView));
|
||||
view->view = view_alloc();
|
||||
view->update_timer =
|
||||
xTimerCreate("Update timer", 1000, pdTRUE, view, one_shot_view_update_timer_callback);
|
||||
xTimerCreate(NULL, 1000, pdTRUE, view, one_shot_view_update_timer_callback);
|
||||
|
||||
view_allocate_model(view->view, ViewModelTypeLocking, sizeof(OneShotViewModel));
|
||||
view_set_context(view->view, view);
|
||||
|
||||
@ -1,34 +1,43 @@
|
||||
#include "animations/animation_manager.h"
|
||||
#include "desktop/scenes/desktop_scene.h"
|
||||
#include "desktop/scenes/desktop_scene_i.h"
|
||||
#include "desktop/views/desktop_locked.h"
|
||||
#include "desktop_i.h"
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <assets_icons.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <portmacro.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <loader/loader.h>
|
||||
|
||||
#include "animations/animation_manager.h"
|
||||
#include "desktop/scenes/desktop_scene.h"
|
||||
#include "desktop/scenes/desktop_scene_i.h"
|
||||
#include "desktop/views/desktop_view_locked.h"
|
||||
#include "desktop/views/desktop_view_pin_input.h"
|
||||
#include "desktop/views/desktop_view_pin_timeout.h"
|
||||
#include "desktop_i.h"
|
||||
#include "desktop_helpers.h"
|
||||
|
||||
static void desktop_lock_icon_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(canvas);
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Lock_8x8);
|
||||
}
|
||||
|
||||
bool desktop_custom_event_callback(void* context, uint32_t event) {
|
||||
static bool desktop_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
return scene_manager_handle_custom_event(desktop->scene_manager, event);
|
||||
}
|
||||
|
||||
bool desktop_back_event_callback(void* context) {
|
||||
static bool desktop_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
return scene_manager_handle_back_event(desktop->scene_manager);
|
||||
}
|
||||
|
||||
static void desktop_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Desktop* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
Desktop* desktop_alloc() {
|
||||
Desktop* desktop = furi_alloc(sizeof(Desktop));
|
||||
|
||||
@ -42,6 +51,8 @@ Desktop* desktop_alloc() {
|
||||
view_dispatcher_enable_queue(desktop->view_dispatcher);
|
||||
view_dispatcher_attach_to_gui(
|
||||
desktop->view_dispatcher, desktop->gui, ViewDispatcherTypeDesktop);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
desktop->view_dispatcher, desktop_tick_event_callback, 500);
|
||||
|
||||
view_dispatcher_set_event_callback_context(desktop->view_dispatcher, desktop);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
@ -49,37 +60,60 @@ Desktop* desktop_alloc() {
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
desktop->view_dispatcher, desktop_back_event_callback);
|
||||
|
||||
desktop->locked_view = desktop_locked_alloc();
|
||||
desktop->lock_menu = desktop_lock_menu_alloc();
|
||||
desktop->debug_view = desktop_debug_alloc();
|
||||
desktop->first_start_view = desktop_first_start_alloc();
|
||||
desktop->hw_mismatch_popup = popup_alloc();
|
||||
desktop->code_input = code_input_alloc();
|
||||
desktop->locked_view = desktop_view_locked_alloc();
|
||||
desktop->pin_input_view = desktop_view_pin_input_alloc();
|
||||
desktop->pin_timeout_view = desktop_view_pin_timeout_alloc();
|
||||
|
||||
desktop->main_view_stack = view_stack_alloc();
|
||||
desktop->main_view = desktop_main_alloc();
|
||||
View* dolphin_view = animation_manager_get_animation_view(desktop->animation_manager);
|
||||
view_stack_add_view(desktop->main_view_stack, desktop_main_get_view(desktop->main_view));
|
||||
view_stack_add_view(desktop->main_view_stack, dolphin_view);
|
||||
view_stack_add_view(desktop->main_view_stack, desktop_locked_get_view(desktop->locked_view));
|
||||
view_stack_add_view(
|
||||
desktop->main_view_stack, desktop_view_locked_get_view(desktop->locked_view));
|
||||
|
||||
/* locked view (as animation view) attends in 2 scenes: main & locked,
|
||||
* because it has to draw "Unlocked" label on main scene */
|
||||
desktop->locked_view_stack = view_stack_alloc();
|
||||
view_stack_add_view(desktop->locked_view_stack, dolphin_view);
|
||||
view_stack_add_view(
|
||||
desktop->locked_view_stack, desktop_view_locked_get_view(desktop->locked_view));
|
||||
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher, DesktopViewMain, view_stack_get_view(desktop->main_view_stack));
|
||||
desktop->view_dispatcher,
|
||||
DesktopViewIdMain,
|
||||
view_stack_get_view(desktop->main_view_stack));
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher,
|
||||
DesktopViewLockMenu,
|
||||
DesktopViewIdLocked,
|
||||
view_stack_get_view(desktop->locked_view_stack));
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher,
|
||||
DesktopViewIdLockMenu,
|
||||
desktop_lock_menu_get_view(desktop->lock_menu));
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher, DesktopViewDebug, desktop_debug_get_view(desktop->debug_view));
|
||||
desktop->view_dispatcher, DesktopViewIdDebug, desktop_debug_get_view(desktop->debug_view));
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher,
|
||||
DesktopViewFirstStart,
|
||||
DesktopViewIdFirstStart,
|
||||
desktop_first_start_get_view(desktop->first_start_view));
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher,
|
||||
DesktopViewHwMismatch,
|
||||
DesktopViewIdHwMismatch,
|
||||
popup_get_view(desktop->hw_mismatch_popup));
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher, DesktopViewPinSetup, code_input_get_view(desktop->code_input));
|
||||
desktop->view_dispatcher,
|
||||
DesktopViewIdPinTimeout,
|
||||
desktop_view_pin_timeout_get_view(desktop->pin_timeout_view));
|
||||
view_dispatcher_add_view(
|
||||
desktop->view_dispatcher,
|
||||
DesktopViewIdPinInput,
|
||||
desktop_view_pin_input_get_view(desktop->pin_input_view));
|
||||
|
||||
// Lock icon
|
||||
desktop->lock_viewport = view_port_alloc();
|
||||
view_port_set_width(desktop->lock_viewport, icon_get_width(&I_Lock_8x8));
|
||||
@ -87,33 +121,43 @@ Desktop* desktop_alloc() {
|
||||
view_port_enabled_set(desktop->lock_viewport, false);
|
||||
gui_add_view_port(desktop->gui, desktop->lock_viewport, GuiLayerStatusBarLeft);
|
||||
|
||||
// Special case: autostart application is already running
|
||||
Loader* loader = furi_record_open("loader");
|
||||
if(loader_is_locked(loader) &&
|
||||
animation_manager_is_animation_loaded(desktop->animation_manager)) {
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
}
|
||||
furi_record_close("loader");
|
||||
|
||||
return desktop;
|
||||
}
|
||||
|
||||
void desktop_free(Desktop* desktop) {
|
||||
furi_assert(desktop);
|
||||
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewMain);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewLockMenu);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewLocked);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewDebug);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewFirstStart);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewHwMismatch);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewPinSetup);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLocked);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdDebug);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdFirstStart);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdHwMismatch);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinInput);
|
||||
view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinTimeout);
|
||||
|
||||
view_dispatcher_free(desktop->view_dispatcher);
|
||||
scene_manager_free(desktop->scene_manager);
|
||||
|
||||
animation_manager_free(desktop->animation_manager);
|
||||
view_stack_free(desktop->main_view_stack);
|
||||
view_stack_free(desktop->locked_view_stack);
|
||||
desktop_main_free(desktop->main_view);
|
||||
view_stack_free(desktop->locked_view_stack);
|
||||
desktop_view_locked_free(desktop->locked_view);
|
||||
desktop_lock_menu_free(desktop->lock_menu);
|
||||
desktop_locked_free(desktop->locked_view);
|
||||
desktop_view_locked_free(desktop->locked_view);
|
||||
desktop_debug_free(desktop->debug_view);
|
||||
desktop_first_start_free(desktop->first_start_view);
|
||||
popup_free(desktop->hw_mismatch_popup);
|
||||
code_input_free(desktop->code_input);
|
||||
desktop_view_pin_timeout_free(desktop->pin_timeout_view);
|
||||
|
||||
osSemaphoreDelete(desktop->unload_animation_semaphore);
|
||||
|
||||
@ -145,14 +189,18 @@ int32_t desktop_srv(void* p) {
|
||||
SAVE_DESKTOP_SETTINGS(&desktop->settings);
|
||||
}
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
furi_hal_usb_disable();
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedWithPin);
|
||||
}
|
||||
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
if(desktop->settings.pin_code.length > 0) {
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
} else {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||
}
|
||||
}
|
||||
|
||||
if(desktop_is_first_start()) {
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart);
|
||||
}
|
||||
|
||||
82
applications/desktop/desktop_helpers.c
Normal file
82
applications/desktop/desktop_helpers.c
Normal file
@ -0,0 +1,82 @@
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <stddef.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
|
||||
#include "desktop_helpers.h"
|
||||
#include "desktop_i.h"
|
||||
|
||||
static const NotificationSequence sequence_pin_fail = {
|
||||
&message_display_on,
|
||||
|
||||
&message_red_255,
|
||||
&message_vibro_on,
|
||||
&message_delay_100,
|
||||
&message_vibro_off,
|
||||
&message_red_0,
|
||||
|
||||
&message_delay_250,
|
||||
|
||||
&message_red_255,
|
||||
&message_vibro_on,
|
||||
&message_delay_100,
|
||||
&message_vibro_off,
|
||||
&message_red_0,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const uint8_t desktop_helpers_fails_timeout[] = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
30,
|
||||
60,
|
||||
90,
|
||||
120,
|
||||
150,
|
||||
180,
|
||||
/* +60 for every next fail */
|
||||
};
|
||||
|
||||
void desktop_helpers_emit_error_notification() {
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &sequence_pin_fail);
|
||||
furi_record_close("notification");
|
||||
}
|
||||
|
||||
void desktop_helpers_lock_system(Desktop* desktop, bool hard_lock) {
|
||||
view_port_enabled_set(desktop->lock_viewport, true);
|
||||
if(hard_lock) {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
||||
furi_hal_usb_disable();
|
||||
}
|
||||
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_set_lockdown(gui, true);
|
||||
furi_record_close("gui");
|
||||
}
|
||||
|
||||
void desktop_helpers_unlock_system(Desktop* desktop) {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||
furi_hal_usb_enable();
|
||||
view_port_enabled_set(desktop->lock_viewport, false);
|
||||
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_set_lockdown(gui, false);
|
||||
furi_record_close("gui");
|
||||
}
|
||||
|
||||
uint32_t desktop_helpers_get_pin_fail_timeout(uint32_t pin_fails) {
|
||||
uint32_t pin_timeout = 0;
|
||||
uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1;
|
||||
if(pin_fails <= max_index) {
|
||||
pin_timeout = desktop_helpers_fails_timeout[pin_fails];
|
||||
} else {
|
||||
pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60;
|
||||
}
|
||||
|
||||
return pin_timeout;
|
||||
}
|
||||
9
applications/desktop/desktop_helpers.h
Normal file
9
applications/desktop/desktop_helpers.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "desktop.h"
|
||||
|
||||
void desktop_helpers_emit_error_notification();
|
||||
void desktop_helpers_lock_system(Desktop* desktop, bool hard_lock);
|
||||
void desktop_helpers_unlock_system(Desktop* desktop);
|
||||
uint32_t desktop_helpers_get_pin_fail_timeout(uint32_t pin_fails);
|
||||
@ -2,11 +2,13 @@
|
||||
|
||||
#include "desktop.h"
|
||||
#include "animations/animation_manager.h"
|
||||
#include "views/desktop_main.h"
|
||||
#include "views/desktop_first_start.h"
|
||||
#include "views/desktop_lock_menu.h"
|
||||
#include "views/desktop_locked.h"
|
||||
#include "views/desktop_debug.h"
|
||||
#include "views/desktop_view_pin_timeout.h"
|
||||
#include "views/desktop_view_pin_input.h"
|
||||
#include "views/desktop_view_locked.h"
|
||||
#include "views/desktop_view_main.h"
|
||||
#include "views/desktop_view_first_start.h"
|
||||
#include "views/desktop_view_lock_menu.h"
|
||||
#include "views/desktop_view_debug.h"
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
|
||||
#include <furi.h>
|
||||
@ -14,21 +16,21 @@
|
||||
#include <gui/view_stack.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/modules/code_input.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#define STATUS_BAR_Y_SHIFT 13
|
||||
|
||||
typedef enum {
|
||||
DesktopViewMain,
|
||||
DesktopViewLockMenu,
|
||||
DesktopViewLocked,
|
||||
DesktopViewDebug,
|
||||
DesktopViewFirstStart,
|
||||
DesktopViewHwMismatch,
|
||||
DesktopViewPinSetup,
|
||||
DesktopViewTotal,
|
||||
} DesktopViewEnum;
|
||||
DesktopViewIdMain,
|
||||
DesktopViewIdLockMenu,
|
||||
DesktopViewIdLocked,
|
||||
DesktopViewIdDebug,
|
||||
DesktopViewIdFirstStart,
|
||||
DesktopViewIdHwMismatch,
|
||||
DesktopViewIdPinInput,
|
||||
DesktopViewIdPinTimeout,
|
||||
DesktopViewIdTotal,
|
||||
} DesktopViewId;
|
||||
|
||||
struct Desktop {
|
||||
// Scene
|
||||
@ -42,16 +44,15 @@ struct Desktop {
|
||||
Popup* hw_mismatch_popup;
|
||||
DesktopLockMenuView* lock_menu;
|
||||
DesktopDebugView* debug_view;
|
||||
CodeInput* code_input;
|
||||
|
||||
DesktopViewLocked* locked_view;
|
||||
DesktopMainView* main_view;
|
||||
DesktopLockedView* locked_view;
|
||||
DesktopViewPinTimeout* pin_timeout_view;
|
||||
|
||||
ViewStack* main_view_stack;
|
||||
ViewStack* locked_view_stack;
|
||||
|
||||
DesktopSettings settings;
|
||||
PinCode pincode_buffer;
|
||||
DesktopViewPinInput* pin_input_view;
|
||||
|
||||
ViewPort* lock_viewport;
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi_hal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <toolbox/saved_struct.h>
|
||||
@ -9,6 +10,8 @@
|
||||
#define DESKTOP_SETTINGS_MAGIC (0x17)
|
||||
#define PIN_MAX_LENGTH 12
|
||||
|
||||
#define DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG "run_pin_setup"
|
||||
|
||||
#define SAVE_DESKTOP_SETTINGS(x) \
|
||||
saved_struct_save( \
|
||||
DESKTOP_SETTINGS_PATH, \
|
||||
@ -25,12 +28,27 @@
|
||||
DESKTOP_SETTINGS_MAGIC, \
|
||||
DESKTOP_SETTINGS_VER)
|
||||
|
||||
#define MAX_PIN_SIZE 10
|
||||
#define MIN_PIN_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
InputKey data[MAX_PIN_SIZE];
|
||||
uint8_t length;
|
||||
uint8_t data[PIN_MAX_LENGTH];
|
||||
} PinCode;
|
||||
|
||||
typedef struct {
|
||||
uint16_t favorite;
|
||||
PinCode pincode;
|
||||
PinCode pin_code;
|
||||
} DesktopSettings;
|
||||
|
||||
static inline bool pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) {
|
||||
furi_assert(pin_code1);
|
||||
furi_assert(pin_code2);
|
||||
bool result = false;
|
||||
|
||||
if(pin_code1->length == pin_code2->length) {
|
||||
result = !memcmp(pin_code1->data, pin_code2->data, pin_code1->length);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
#include "desktop_settings_app.h"
|
||||
#include <furi.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include "desktop_settings_app.h"
|
||||
#include "scenes/desktop_settings_scene.h"
|
||||
#include "../views/desktop_view_pin_input.h"
|
||||
|
||||
static bool desktop_settings_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
@ -30,17 +34,28 @@ DesktopSettingsApp* desktop_settings_app_alloc() {
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
app->popup = popup_alloc();
|
||||
app->submenu = submenu_alloc();
|
||||
app->pin_input_view = desktop_view_pin_input_alloc();
|
||||
app->pin_setup_howto_view = desktop_settings_view_pin_setup_howto_alloc();
|
||||
app->pin_setup_howto2_view = desktop_settings_view_pin_setup_howto2_alloc();
|
||||
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu));
|
||||
|
||||
app->code_input = code_input_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DesktopSettingsAppViewPincodeInput,
|
||||
code_input_get_view(app->code_input));
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart);
|
||||
DesktopSettingsAppViewIdPinInput,
|
||||
desktop_view_pin_input_get_view(app->pin_input_view));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DesktopSettingsAppViewIdPinSetupHowto,
|
||||
desktop_settings_view_pin_setup_howto_get_view(app->pin_setup_howto_view));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DesktopSettingsAppViewIdPinSetupHowto2,
|
||||
desktop_settings_view_pin_setup_howto2_get_view(app->pin_setup_howto2_view));
|
||||
return app;
|
||||
}
|
||||
|
||||
@ -48,9 +63,15 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
|
||||
furi_assert(app);
|
||||
// Variable item list
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
|
||||
submenu_free(app->submenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewPincodeInput);
|
||||
code_input_free(app->code_input);
|
||||
popup_free(app->popup);
|
||||
desktop_view_pin_input_free(app->pin_input_view);
|
||||
desktop_settings_view_pin_setup_howto_free(app->pin_setup_howto_view);
|
||||
desktop_settings_view_pin_setup_howto2_free(app->pin_setup_howto2_view);
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
@ -62,6 +83,12 @@ void desktop_settings_app_free(DesktopSettingsApp* app) {
|
||||
extern int32_t desktop_settings_app(void* p) {
|
||||
DesktopSettingsApp* app = desktop_settings_app_alloc();
|
||||
LOAD_DESKTOP_SETTINGS(&app->settings);
|
||||
if(!strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG)) {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
|
||||
} else {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart);
|
||||
}
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
desktop_settings_app_free(app);
|
||||
return 0;
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/code_input.h>
|
||||
|
||||
#include "desktop_settings.h"
|
||||
|
||||
typedef enum {
|
||||
CodeEventsSetPin,
|
||||
CodeEventsChangePin,
|
||||
CodeEventsDisablePin,
|
||||
} CodeEventsEnum;
|
||||
#include "desktop/views/desktop_view_pin_input.h"
|
||||
#include "views/desktop_settings_view_pin_setup_howto.h"
|
||||
#include "views/desktop_settings_view_pin_setup_howto2.h"
|
||||
|
||||
typedef enum {
|
||||
DesktopSettingsAppViewMenu,
|
||||
DesktopSettingsAppViewPincodeInput,
|
||||
DesktopSettingsAppViewIdPopup,
|
||||
DesktopSettingsAppViewIdPinInput,
|
||||
DesktopSettingsAppViewIdPinSetupHowto,
|
||||
DesktopSettingsAppViewIdPinSetupHowto2,
|
||||
} DesktopSettingsAppView;
|
||||
|
||||
typedef struct {
|
||||
@ -26,7 +26,13 @@ typedef struct {
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Submenu* submenu;
|
||||
CodeInput* code_input;
|
||||
Popup* popup;
|
||||
DesktopViewPinInput* pin_input_view;
|
||||
DesktopSettingsViewPinSetupHowto* pin_setup_howto_view;
|
||||
DesktopSettingsViewPinSetupHowto2* pin_setup_howto2_view;
|
||||
|
||||
PinCode pincode_buffer;
|
||||
bool pincode_buffer_filled;
|
||||
|
||||
uint8_t menu_idx;
|
||||
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
ADD_SCENE(desktop_settings, start, Start)
|
||||
ADD_SCENE(desktop_settings, favorite, Favorite)
|
||||
ADD_SCENE(desktop_settings, pincode_menu, PinCodeMenu)
|
||||
ADD_SCENE(desktop_settings, pincode_input, PinCodeInput)
|
||||
ADD_SCENE(desktop_settings, pin_menu, PinMenu)
|
||||
|
||||
ADD_SCENE(desktop_settings, pin_auth, PinAuth)
|
||||
ADD_SCENE(desktop_settings, pin_error, PinError)
|
||||
ADD_SCENE(desktop_settings, pin_disable, PinDisable)
|
||||
ADD_SCENE(desktop_settings, pin_setup, PinSetup)
|
||||
ADD_SCENE(desktop_settings, pin_setup_howto, PinSetupHowto)
|
||||
ADD_SCENE(desktop_settings, pin_setup_howto2, PinSetupHowto2)
|
||||
ADD_SCENE(desktop_settings, pin_setup_done, PinSetupDone)
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define SCENE_STATE_PIN_AUTH_DISABLE (0)
|
||||
#define SCENE_STATE_PIN_AUTH_CHANGE_PIN (1)
|
||||
|
||||
#define SCENE_STATE_PIN_ERROR_MISMATCH (0)
|
||||
#define SCENE_STATE_PIN_ERROR_WRONG (1)
|
||||
@ -0,0 +1,95 @@
|
||||
#include <stdint.h>
|
||||
#include <furi/check.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
#include "desktop/views/desktop_view_pin_input.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "desktop_settings_scene_i.h"
|
||||
|
||||
#define SCENE_EVENT_EXIT (0U)
|
||||
#define SCENE_EVENT_PINS_EQUAL (1U)
|
||||
#define SCENE_EVENT_PINS_DIFFERENT (2U)
|
||||
|
||||
static void pin_auth_done_callback(const PinCode* pin_code, void* context) {
|
||||
furi_assert(pin_code);
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
app->pincode_buffer = *pin_code;
|
||||
if(pins_are_equal(&app->settings.pin_code, pin_code)) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL);
|
||||
} else {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT);
|
||||
}
|
||||
}
|
||||
|
||||
static void pin_auth_back_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_auth_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
LOAD_DESKTOP_SETTINGS(&app->settings);
|
||||
furi_assert(app->settings.pin_code.length > 0);
|
||||
|
||||
desktop_view_pin_input_set_context(app->pin_input_view, app);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_auth_back_callback);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_auth_done_callback);
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "OK");
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL);
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
app->pin_input_view, 0, 8, "Enter your current PIN:");
|
||||
desktop_view_pin_input_reset_pin(app->pin_input_view);
|
||||
desktop_view_pin_input_unlock_input(app->pin_input_view);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_auth_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_PINS_DIFFERENT:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, DesktopSettingsAppScenePinError, SCENE_STATE_PIN_ERROR_WRONG);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinError);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_PINS_EQUAL: {
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinAuth);
|
||||
if(state == SCENE_STATE_PIN_AUTH_CHANGE_PIN) {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
|
||||
} else if(state == SCENE_STATE_PIN_AUTH_DISABLE) {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinDisable);
|
||||
} else {
|
||||
furi_assert(0);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
case SCENE_EVENT_EXIT:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_auth_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL);
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
#include <stdint.h>
|
||||
#include <furi/check.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "../desktop_settings.h"
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
#define SCENE_EVENT_EXIT (0U)
|
||||
|
||||
static void pin_disable_back_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_disable_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
app->settings.pin_code.length = 0;
|
||||
memset(app->settings.pin_code.data, '0', sizeof(app->settings.pin_code.data));
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
|
||||
popup_set_context(app->popup, app);
|
||||
popup_set_callback(app->popup, pin_disable_back_callback);
|
||||
popup_set_icon(app->popup, 0, 2, &I_DolphinMafia_115x62);
|
||||
popup_set_header(app->popup, "PIN\ndeleted!", 95, 9, AlignCenter, AlignCenter);
|
||||
popup_set_timeout(app->popup, 1500);
|
||||
popup_enable_timeout(app->popup);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_disable_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_EXIT:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_disable_on_exit(void* context) {
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
#include <stdint.h>
|
||||
#include <furi/check.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
#include "desktop/views/desktop_view_pin_input.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "desktop_settings_scene_i.h"
|
||||
#include "../../desktop_helpers.h"
|
||||
#include "../desktop_settings_app.h"
|
||||
|
||||
#define SCENE_EVENT_EXIT (0U)
|
||||
|
||||
static void pin_error_back_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
static void pin_error_done_callback(const PinCode* pin_code, void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_error_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_helpers_emit_error_notification();
|
||||
|
||||
desktop_view_pin_input_set_context(app->pin_input_view, app);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_error_back_callback);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_error_done_callback);
|
||||
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinError);
|
||||
if(state == SCENE_STATE_PIN_ERROR_MISMATCH) {
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN mismatch!");
|
||||
} else if(state == SCENE_STATE_PIN_ERROR_WRONG) {
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 35, 8, "Wrong PIN!");
|
||||
} else {
|
||||
furi_assert(0);
|
||||
}
|
||||
desktop_view_pin_input_set_label_secondary(app->pin_input_view, 0, 8, NULL);
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "Retry");
|
||||
desktop_view_pin_input_lock_input(app->pin_input_view);
|
||||
desktop_view_pin_input_set_pin(app->pin_input_view, &app->pincode_buffer);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_error_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_EXIT:
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_error_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_view_pin_input_unlock_input(app->pin_input_view);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL);
|
||||
}
|
||||
@ -1,38 +1,45 @@
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "applications.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
#include <gui/scene_manager.h>
|
||||
#include <applications.h>
|
||||
|
||||
static void desktop_settings_scene_pincode_menu_submenu_callback(void* context, uint32_t index) {
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "desktop_settings_scene_i.h"
|
||||
|
||||
#define SCENE_EVENT_SET_PIN 0
|
||||
#define SCENE_EVENT_CHANGE_PIN 1
|
||||
#define SCENE_EVENT_DISABLE_PIN 2
|
||||
|
||||
static void desktop_settings_scene_pin_menu_submenu_callback(void* context, uint32_t index) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pincode_menu_on_enter(void* context) {
|
||||
void desktop_settings_scene_pin_menu_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
submenu_reset(submenu);
|
||||
|
||||
if(!app->settings.pincode.length) {
|
||||
if(!app->settings.pin_code.length) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Set Pin",
|
||||
CodeEventsSetPin,
|
||||
desktop_settings_scene_pincode_menu_submenu_callback,
|
||||
SCENE_EVENT_SET_PIN,
|
||||
desktop_settings_scene_pin_menu_submenu_callback,
|
||||
app);
|
||||
|
||||
} else {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Change Pin",
|
||||
CodeEventsChangePin,
|
||||
desktop_settings_scene_pincode_menu_submenu_callback,
|
||||
SCENE_EVENT_CHANGE_PIN,
|
||||
desktop_settings_scene_pin_menu_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Disable",
|
||||
CodeEventsDisablePin,
|
||||
desktop_settings_scene_pincode_menu_submenu_callback,
|
||||
SCENE_EVENT_DISABLE_PIN,
|
||||
desktop_settings_scene_pin_menu_submenu_callback,
|
||||
app);
|
||||
}
|
||||
|
||||
@ -41,28 +48,28 @@ void desktop_settings_scene_pincode_menu_on_enter(void* context) {
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pincode_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
bool desktop_settings_scene_pin_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case CodeEventsSetPin:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput);
|
||||
case SCENE_EVENT_SET_PIN:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
|
||||
consumed = true;
|
||||
break;
|
||||
case CodeEventsChangePin:
|
||||
case SCENE_EVENT_CHANGE_PIN:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput);
|
||||
app->scene_manager,
|
||||
DesktopSettingsAppScenePinAuth,
|
||||
SCENE_STATE_PIN_AUTH_CHANGE_PIN);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinAuth);
|
||||
consumed = true;
|
||||
break;
|
||||
case CodeEventsDisablePin:
|
||||
case SCENE_EVENT_DISABLE_PIN:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput);
|
||||
app->scene_manager, DesktopSettingsAppScenePinAuth, SCENE_STATE_PIN_AUTH_DISABLE);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinAuth);
|
||||
consumed = true;
|
||||
break;
|
||||
default:
|
||||
@ -73,7 +80,7 @@ bool desktop_settings_scene_pincode_menu_on_event(void* context, SceneManagerEve
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pincode_menu_on_exit(void* context) {
|
||||
void desktop_settings_scene_pin_menu_on_exit(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
#include <stdint.h>
|
||||
#include <furi/check.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
#include "desktop/views/desktop_view_pin_input.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "desktop_settings_scene_i.h"
|
||||
|
||||
#define SCENE_EVENT_EXIT (0U)
|
||||
#define SCENE_EVENT_1ST_PIN_ENTERED (1U)
|
||||
#define SCENE_EVENT_PINS_EQUAL (2U)
|
||||
#define SCENE_EVENT_PINS_DIFFERENT (3U)
|
||||
|
||||
static void pin_setup_done_callback(const PinCode* pin_code, void* context) {
|
||||
furi_assert(pin_code);
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
if(!app->pincode_buffer_filled) {
|
||||
app->pincode_buffer = *pin_code;
|
||||
app->pincode_buffer_filled = true;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_1ST_PIN_ENTERED);
|
||||
} else {
|
||||
app->pincode_buffer_filled = false;
|
||||
if(pins_are_equal(&app->pincode_buffer, pin_code)) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL);
|
||||
} else {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pin_setup_back_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
app->pincode_buffer_filled = false;
|
||||
desktop_view_pin_input_set_context(app->pin_input_view, app);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_setup_back_callback);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback);
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "OK");
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL);
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
app->pin_input_view, 0, 8, "Enter from 4 to 10 arrows:");
|
||||
desktop_view_pin_input_reset_pin(app->pin_input_view);
|
||||
desktop_view_pin_input_unlock_input(app->pin_input_view);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_setup_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_1ST_PIN_ENTERED:
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "OK");
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL);
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
app->pin_input_view, 0, 8, "Confirm your PIN:");
|
||||
desktop_view_pin_input_reset_pin(app->pin_input_view);
|
||||
desktop_view_pin_input_unlock_input(app->pin_input_view);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_PINS_DIFFERENT:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
DesktopSettingsAppScenePinError,
|
||||
SCENE_STATE_PIN_ERROR_MISMATCH);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinError);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_PINS_EQUAL:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto2);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_EXIT: {
|
||||
uint32_t scene_found;
|
||||
scene_found = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
if(!scene_found) {
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL);
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
#include <furi.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <stdint.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
#include "desktop/views/desktop_view_pin_input.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
#define SCENE_EVENT_DONE (0U)
|
||||
|
||||
static void pin_setup_done_callback(const PinCode* pin_code, void* context) {
|
||||
furi_assert(pin_code);
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_DONE);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_done_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
app->settings.pin_code = app->pincode_buffer;
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
NotificationApp* notification = furi_record_open("notification");
|
||||
notification_message(notification, &sequence_single_vibro);
|
||||
furi_record_close("notification");
|
||||
|
||||
desktop_view_pin_input_set_context(app->pin_input_view, app);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback);
|
||||
desktop_view_pin_input_set_pin(app->pin_input_view, &app->settings.pin_code);
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "Done");
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN activated!");
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
app->pin_input_view, 7, 45, "Remember or write it down");
|
||||
desktop_view_pin_input_lock_input(app->pin_input_view);
|
||||
desktop_view_pin_input_set_pin_position(app->pin_input_view, 64, 24);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_setup_done_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_DONE: {
|
||||
bool scene_found = false;
|
||||
scene_found = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
if(!scene_found) {
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_done_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_view_pin_input_set_pin_position(app->pin_input_view, 64, 32);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL);
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
#include <furi.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "../views/desktop_settings_view_pin_setup_howto.h"
|
||||
|
||||
#define SCENE_EXIT_EVENT (0U)
|
||||
|
||||
static void desktop_settings_scene_pin_lock_done_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_howto_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
desktop_settings_view_pin_setup_howto_set_callback(
|
||||
app->pin_setup_howto_view, desktop_settings_scene_pin_lock_done_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_setup_howto_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EXIT_EVENT:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetup);
|
||||
consumed = true;
|
||||
break;
|
||||
default:
|
||||
furi_assert(0);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_howto_on_exit(void* context) {
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
#include <furi.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "../views/desktop_settings_view_pin_setup_howto2.h"
|
||||
|
||||
#define SCENE_EXIT_EVENT (0U)
|
||||
#define SCENE_DONE_EVENT (1U)
|
||||
|
||||
static void desktop_settings_scene_pin_setup_howto2_done_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_DONE_EVENT);
|
||||
}
|
||||
|
||||
static void desktop_settings_scene_pin_setup_howto2_exit_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_howto2_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
desktop_settings_view_pin_setup_howto2_set_context(app->pin_setup_howto2_view, app);
|
||||
desktop_settings_view_pin_setup_howto2_set_ok_callback(
|
||||
app->pin_setup_howto2_view, desktop_settings_scene_pin_setup_howto2_done_callback);
|
||||
desktop_settings_view_pin_setup_howto2_set_cancel_callback(
|
||||
app->pin_setup_howto2_view, desktop_settings_scene_pin_setup_howto2_exit_callback);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_setup_howto2_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_DONE_EVENT: {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupDone);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
case SCENE_EXIT_EVENT: {
|
||||
bool scene_found = false;
|
||||
scene_found = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
if(!scene_found) {
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
furi_assert(0);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_howto2_on_exit(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_settings_view_pin_setup_howto2_set_ok_callback(app->pin_setup_howto2_view, NULL);
|
||||
desktop_settings_view_pin_setup_howto2_set_cancel_callback(app->pin_setup_howto2_view, NULL);
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
#define SCENE_EXIT_EVENT (0U)
|
||||
|
||||
void desktop_settings_scene_ok_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinCodeInput);
|
||||
|
||||
if(state == CodeEventsDisablePin) {
|
||||
memset(app->settings.pincode.data, 0, app->settings.pincode.length * sizeof(uint8_t));
|
||||
app->settings.pincode.length = 0;
|
||||
}
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pincode_input_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
CodeInput* code_input = app->code_input;
|
||||
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinCodeInput);
|
||||
bool update = state != CodeEventsDisablePin;
|
||||
|
||||
code_input_set_header_text(code_input, "PIN Code Setup");
|
||||
code_input_set_result_callback(
|
||||
code_input,
|
||||
desktop_settings_scene_ok_callback,
|
||||
NULL,
|
||||
app,
|
||||
app->settings.pincode.data,
|
||||
&app->settings.pincode.length,
|
||||
update);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewPincodeInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pincode_input_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EXIT_EVENT:
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pincode_input_on_exit(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
code_input_set_result_callback(app->code_input, NULL, NULL, NULL, NULL, NULL, 0);
|
||||
code_input_set_header_text(app->code_input, "");
|
||||
}
|
||||
@ -1,11 +1,10 @@
|
||||
#include <applications.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "applications.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
enum DesktopSettingsStartSubmenuIndex {
|
||||
DesktopSettingsStartSubmenuIndexFavorite,
|
||||
DesktopSettingsStartSubmenuIndexPinSetup,
|
||||
};
|
||||
#define SCENE_EVENT_SELECT_FAVORITE 0
|
||||
#define SCENE_EVENT_SELECT_PIN_SETUP 1
|
||||
|
||||
static void desktop_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
DesktopSettingsApp* app = context;
|
||||
@ -19,14 +18,14 @@ void desktop_settings_scene_start_on_enter(void* context) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Favorite App",
|
||||
DesktopSettingsStartSubmenuIndexFavorite,
|
||||
SCENE_EVENT_SELECT_FAVORITE,
|
||||
desktop_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"PIN Setup",
|
||||
DesktopSettingsStartSubmenuIndexPinSetup,
|
||||
SCENE_EVENT_SELECT_PIN_SETUP,
|
||||
desktop_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
|
||||
@ -39,12 +38,12 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DesktopSettingsStartSubmenuIndexFavorite:
|
||||
case SCENE_EVENT_SELECT_FAVORITE:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopSettingsStartSubmenuIndexPinSetup:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeMenu);
|
||||
case SCENE_EVENT_SELECT_PIN_SETUP:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <toolbox/version.h>
|
||||
#include <assets_icons.h>
|
||||
#include <dolphin/helpers/dolphin_state.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "desktop_settings_view_pin_setup_howto.h"
|
||||
|
||||
struct DesktopSettingsViewPinSetupHowto {
|
||||
View* view;
|
||||
DesktopSettingsViewPinSetupHowtoDoneCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
static void desktop_settings_view_pin_setup_howto_draw(Canvas* canvas, void* model) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(model);
|
||||
|
||||
canvas_draw_icon(canvas, 16, 18, &I_Pin_attention_dpad_29x29);
|
||||
elements_button_right(canvas, "Next");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "Setting up PIN");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text(canvas, 58, 24, "Prepare to use\narrows as\nPIN symbols");
|
||||
}
|
||||
|
||||
static bool desktop_settings_view_pin_setup_howto_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
DesktopSettingsViewPinSetupHowto* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if((event->key == InputKeyRight) && (event->type == InputTypeShort)) {
|
||||
instance->callback(instance->context);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto_set_callback(
|
||||
DesktopSettingsViewPinSetupHowto* instance,
|
||||
DesktopSettingsViewPinSetupHowtoDoneCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
DesktopSettingsViewPinSetupHowto* desktop_settings_view_pin_setup_howto_alloc() {
|
||||
DesktopSettingsViewPinSetupHowto* view = furi_alloc(sizeof(DesktopSettingsViewPinSetupHowto));
|
||||
view->view = view_alloc();
|
||||
view_allocate_model(view->view, ViewModelTypeLockFree, 1);
|
||||
view_set_context(view->view, view);
|
||||
view_set_draw_callback(view->view, desktop_settings_view_pin_setup_howto_draw);
|
||||
view_set_input_callback(view->view, desktop_settings_view_pin_setup_howto_input);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto_free(DesktopSettingsViewPinSetupHowto* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* desktop_settings_view_pin_setup_howto_get_view(DesktopSettingsViewPinSetupHowto* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->view;
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct DesktopSettingsViewPinSetupHowto DesktopSettingsViewPinSetupHowto;
|
||||
|
||||
typedef void (*DesktopSettingsViewPinSetupHowtoDoneCallback)(void*);
|
||||
|
||||
void desktop_settings_view_pin_setup_howto_set_callback(
|
||||
DesktopSettingsViewPinSetupHowto* instance,
|
||||
DesktopSettingsViewPinSetupHowtoDoneCallback callback,
|
||||
void* context);
|
||||
DesktopSettingsViewPinSetupHowto* desktop_settings_view_pin_setup_howto_alloc();
|
||||
void desktop_settings_view_pin_setup_howto_free(DesktopSettingsViewPinSetupHowto* instance);
|
||||
View* desktop_settings_view_pin_setup_howto_get_view(DesktopSettingsViewPinSetupHowto* instance);
|
||||
@ -0,0 +1,101 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <toolbox/version.h>
|
||||
#include <assets_icons.h>
|
||||
#include <dolphin/helpers/dolphin_state.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "desktop_settings_view_pin_setup_howto2.h"
|
||||
|
||||
struct DesktopSettingsViewPinSetupHowto2 {
|
||||
View* view;
|
||||
DesktopSettingsViewPinSetupHowto2Callback cancel_callback;
|
||||
DesktopSettingsViewPinSetupHowto2Callback ok_callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
static void desktop_settings_view_pin_setup_howto2_draw(Canvas* canvas, void* model) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(model);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
"Forgotten PIN can only be\n"
|
||||
"reset with entire device.\n"
|
||||
"Read docs How to reset PIN.");
|
||||
|
||||
elements_button_right(canvas, "OK");
|
||||
elements_button_left(canvas, "Cancel");
|
||||
}
|
||||
|
||||
static bool desktop_settings_view_pin_setup_howto2_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
DesktopSettingsViewPinSetupHowto2* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyRight) {
|
||||
instance->ok_callback(instance->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
instance->cancel_callback(instance->context);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto2_set_context(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto2_set_cancel_callback(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
DesktopSettingsViewPinSetupHowto2Callback callback) {
|
||||
furi_assert(instance);
|
||||
instance->cancel_callback = callback;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto2_set_ok_callback(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
DesktopSettingsViewPinSetupHowto2Callback callback) {
|
||||
furi_assert(instance);
|
||||
instance->ok_callback = callback;
|
||||
}
|
||||
|
||||
DesktopSettingsViewPinSetupHowto2* desktop_settings_view_pin_setup_howto2_alloc() {
|
||||
DesktopSettingsViewPinSetupHowto2* view =
|
||||
furi_alloc(sizeof(DesktopSettingsViewPinSetupHowto2));
|
||||
view->view = view_alloc();
|
||||
view_allocate_model(view->view, ViewModelTypeLockFree, 1);
|
||||
view_set_context(view->view, view);
|
||||
view_set_draw_callback(view->view, desktop_settings_view_pin_setup_howto2_draw);
|
||||
view_set_input_callback(view->view, desktop_settings_view_pin_setup_howto2_input);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto2_free(DesktopSettingsViewPinSetupHowto2* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* desktop_settings_view_pin_setup_howto2_get_view(DesktopSettingsViewPinSetupHowto2* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->view;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct DesktopSettingsViewPinSetupHowto2 DesktopSettingsViewPinSetupHowto2;
|
||||
|
||||
typedef void (*DesktopSettingsViewPinSetupHowto2Callback)(void*);
|
||||
|
||||
DesktopSettingsViewPinSetupHowto2* desktop_settings_view_pin_setup_howto2_alloc();
|
||||
void desktop_settings_view_pin_setup_howto2_free(DesktopSettingsViewPinSetupHowto2* instance);
|
||||
View* desktop_settings_view_pin_setup_howto2_get_view(DesktopSettingsViewPinSetupHowto2* instance);
|
||||
void desktop_settings_view_pin_setup_howto2_set_context(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
void* context);
|
||||
void desktop_settings_view_pin_setup_howto2_set_cancel_callback(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
DesktopSettingsViewPinSetupHowto2Callback callback);
|
||||
void desktop_settings_view_pin_setup_howto2_set_ok_callback(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
DesktopSettingsViewPinSetupHowto2Callback callback);
|
||||
@ -3,5 +3,7 @@ ADD_SCENE(desktop, lock_menu, LockMenu)
|
||||
ADD_SCENE(desktop, debug, Debug)
|
||||
ADD_SCENE(desktop, first_start, FirstStart)
|
||||
ADD_SCENE(desktop, hw_mismatch, HwMismatch)
|
||||
ADD_SCENE(desktop, pinsetup, PinSetup)
|
||||
ADD_SCENE(desktop, fault, Fault)
|
||||
ADD_SCENE(desktop, locked, Locked)
|
||||
ADD_SCENE(desktop, pin_input, PinInput)
|
||||
ADD_SCENE(desktop, pin_timeout, PinTimeout)
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include <dolphin/helpers/dolphin_deed.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "../views/desktop_debug.h"
|
||||
#include "../views/desktop_view_debug.h"
|
||||
#include "desktop_scene.h"
|
||||
|
||||
void desktop_scene_debug_callback(DesktopEvent event, void* context) {
|
||||
@ -17,7 +17,7 @@ void desktop_scene_debug_on_enter(void* context) {
|
||||
desktop_debug_get_dolphin_data(desktop->debug_view);
|
||||
|
||||
desktop_debug_set_callback(desktop->debug_view, desktop_scene_debug_callback, desktop);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewDebug);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdDebug);
|
||||
}
|
||||
|
||||
bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@ -25,7 +25,7 @@ void desktop_scene_fault_on_enter(void* context) {
|
||||
char* message = (char*)furi_hal_rtc_get_fault_data();
|
||||
popup_set_text(popup, message, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter);
|
||||
popup_set_callback(popup, desktop_scene_fault_callback);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewHwMismatch);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdHwMismatch);
|
||||
}
|
||||
|
||||
bool desktop_scene_fault_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#include <storage/storage.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "../views/desktop_first_start.h"
|
||||
#include "../views/desktop_view_first_start.h"
|
||||
#include "../views/desktop_events.h"
|
||||
|
||||
void desktop_scene_first_start_callback(DesktopEvent event, void* context) {
|
||||
@ -17,7 +17,7 @@ void desktop_scene_first_start_on_enter(void* context) {
|
||||
desktop_first_start_set_callback(
|
||||
first_start_view, desktop_scene_first_start_callback, desktop);
|
||||
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewFirstStart);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdFirstStart);
|
||||
}
|
||||
|
||||
bool desktop_scene_first_start_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#include <gui/scene_manager.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include "desktop_scene.h"
|
||||
#include "../desktop_i.h"
|
||||
@ -31,7 +31,7 @@ void desktop_scene_hw_mismatch_on_enter(void* context) {
|
||||
popup, "!!!! HW Mismatch !!!!", 60, 14 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter);
|
||||
popup_set_text(popup, text_buffer, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter);
|
||||
popup_set_callback(popup, desktop_scene_hw_mismatch_callback);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewHwMismatch);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdHwMismatch);
|
||||
}
|
||||
|
||||
bool desktop_scene_hw_mismatch_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
DesktopMainSceneStateUnlocked,
|
||||
DesktopMainSceneStateLockedWithPin,
|
||||
DesktopMainSceneStateLockedNoPin,
|
||||
} DesktopMainSceneState;
|
||||
#define SCENE_LOCKED_FIRST_ENTER 0
|
||||
#define SCENE_LOCKED_REPEAT_ENTER 1
|
||||
|
||||
@ -1,11 +1,18 @@
|
||||
#include <gui/scene_manager.h>
|
||||
#include <applications.h>
|
||||
#include <furi_hal.h>
|
||||
#include <toolbox/saved_struct.h>
|
||||
#include <stdbool.h>
|
||||
#include <loader/loader.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "../views/desktop_lock_menu.h"
|
||||
#include "../desktop_settings/desktop_settings.h"
|
||||
#include "../views/desktop_view_lock_menu.h"
|
||||
#include "desktop_scene_i.h"
|
||||
#include "desktop_scene.h"
|
||||
|
||||
#define TAG "DesktopSceneLock"
|
||||
|
||||
void desktop_scene_lock_menu_callback(DesktopEvent event, void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, event);
|
||||
@ -15,36 +22,53 @@ void desktop_scene_lock_menu_on_enter(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
|
||||
LOAD_DESKTOP_SETTINGS(&desktop->settings);
|
||||
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop);
|
||||
desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pincode.length > 0);
|
||||
desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pin_code.length > 0);
|
||||
desktop_lock_menu_set_idx(desktop->lock_menu, 0);
|
||||
|
||||
uint8_t idx = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu);
|
||||
desktop_lock_menu_set_idx(desktop->lock_menu, idx);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewLockMenu);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu);
|
||||
}
|
||||
|
||||
bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
bool check_pin_changed =
|
||||
scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu);
|
||||
if(check_pin_changed) {
|
||||
LOAD_DESKTOP_SETTINGS(&desktop->settings);
|
||||
if(desktop->settings.pin_code.length > 0) {
|
||||
desktop_lock_menu_pin_set(desktop->lock_menu, 1);
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
}
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DesktopLockMenuEventLock:
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedNoPin);
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockMenuEventPinLock:
|
||||
if(desktop->settings.pincode.length > 0) {
|
||||
if(desktop->settings.pin_code.length > 0) {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedWithPin);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked);
|
||||
} else {
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopScenePinSetup);
|
||||
Loader* loader = furi_record_open("loader");
|
||||
LoaderStatus status =
|
||||
loader_start(loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG);
|
||||
furi_record_close("loader");
|
||||
if(status == LoaderStatusOk) {
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1);
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unable to start desktop settings");
|
||||
}
|
||||
}
|
||||
|
||||
consumed = true;
|
||||
|
||||
109
applications/desktop/scenes/desktop_scene_locked.c
Normal file
109
applications/desktop/scenes/desktop_scene_locked.c
Normal file
@ -0,0 +1,109 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include <stdint.h>
|
||||
#include <portmacro.h>
|
||||
|
||||
#include "../desktop.h"
|
||||
#include "../desktop_i.h"
|
||||
#include "../desktop_helpers.h"
|
||||
#include "../animations/animation_manager.h"
|
||||
#include "../views/desktop_events.h"
|
||||
#include "../views/desktop_view_pin_input.h"
|
||||
#include "../views/desktop_view_locked.h"
|
||||
#include "desktop_scene.h"
|
||||
#include "desktop_scene_i.h"
|
||||
|
||||
#define WRONG_PIN_HEADER_TIMEOUT 3000
|
||||
#define INPUT_PIN_VIEW_TIMEOUT 15000
|
||||
|
||||
static void desktop_scene_locked_callback(DesktopEvent event, void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, event);
|
||||
}
|
||||
|
||||
static void desktop_scene_locked_new_idle_animation_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = context;
|
||||
view_dispatcher_send_custom_event(
|
||||
desktop->view_dispatcher, DesktopAnimationEventNewIdleAnimation);
|
||||
}
|
||||
|
||||
void desktop_scene_locked_on_enter(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
|
||||
// callbacks for 1-st layer
|
||||
animation_manager_set_new_idle_callback(
|
||||
desktop->animation_manager, desktop_scene_locked_new_idle_animation_callback);
|
||||
animation_manager_set_check_callback(desktop->animation_manager, NULL);
|
||||
animation_manager_set_interact_callback(desktop->animation_manager, NULL);
|
||||
|
||||
// callbacks for 2-nd layer
|
||||
desktop_view_locked_set_callback(desktop->locked_view, desktop_scene_locked_callback, desktop);
|
||||
|
||||
bool switch_to_timeout_scene = false;
|
||||
uint32_t state = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLocked);
|
||||
if(state == SCENE_LOCKED_FIRST_ENTER) {
|
||||
bool pin_locked = furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock);
|
||||
desktop_helpers_lock_system(desktop, pin_locked);
|
||||
if(pin_locked) {
|
||||
LOAD_DESKTOP_SETTINGS(&desktop->settings);
|
||||
desktop_view_locked_lock(desktop->locked_view, true);
|
||||
uint32_t pin_fails = furi_hal_rtc_get_pin_fails();
|
||||
uint32_t pin_timeout = desktop_helpers_get_pin_fail_timeout(pin_fails);
|
||||
if(pin_timeout) {
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopScenePinTimeout, pin_timeout);
|
||||
switch_to_timeout_scene = true;
|
||||
} else {
|
||||
desktop_view_locked_close_doors(desktop->locked_view);
|
||||
}
|
||||
} else {
|
||||
desktop_view_locked_lock(desktop->locked_view, false);
|
||||
desktop_view_locked_close_doors(desktop->locked_view);
|
||||
}
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_REPEAT_ENTER);
|
||||
}
|
||||
|
||||
if(switch_to_timeout_scene) {
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopScenePinTimeout);
|
||||
} else {
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLocked);
|
||||
}
|
||||
}
|
||||
|
||||
bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DesktopLockedEventUnlocked:
|
||||
furi_hal_rtc_set_pin_fails(0);
|
||||
desktop_helpers_unlock_system(desktop);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneMain);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockedEventUpdate:
|
||||
desktop_view_locked_update(desktop->locked_view);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockedEventShowPinInput:
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopScenePinInput);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopAnimationEventNewIdleAnimation:
|
||||
animation_manager_new_idle_process(desktop->animation_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_scene_locked_on_exit(void* context) {
|
||||
}
|
||||
@ -4,12 +4,13 @@
|
||||
#include <assets_icons.h>
|
||||
#include <loader/loader.h>
|
||||
|
||||
#include "desktop/desktop_i.h"
|
||||
#include "desktop/views/desktop_main.h"
|
||||
#include "../desktop_i.h"
|
||||
#include "../views/desktop_events.h"
|
||||
#include "../views/desktop_view_main.h"
|
||||
#include "desktop_scene.h"
|
||||
#include "desktop_scene_i.h"
|
||||
|
||||
#define MAIN_VIEW_DEFAULT (0UL)
|
||||
#define TAG "DesktopSrv"
|
||||
|
||||
static void desktop_scene_main_app_started_callback(const void* message, void* context) {
|
||||
furi_assert(context);
|
||||
@ -29,19 +30,22 @@ static void desktop_scene_main_app_started_callback(const void* message, void* c
|
||||
static void desktop_scene_main_new_idle_animation_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopMainEventNewIdleAnimation);
|
||||
view_dispatcher_send_custom_event(
|
||||
desktop->view_dispatcher, DesktopAnimationEventNewIdleAnimation);
|
||||
}
|
||||
|
||||
static void desktop_scene_main_check_animation_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopMainEventCheckAnimation);
|
||||
view_dispatcher_send_custom_event(
|
||||
desktop->view_dispatcher, DesktopAnimationEventCheckAnimation);
|
||||
}
|
||||
|
||||
static void desktop_scene_main_interact_animation_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Desktop* desktop = context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopMainEventInteractAnimation);
|
||||
view_dispatcher_send_custom_event(
|
||||
desktop->view_dispatcher, DesktopAnimationEventInteractAnimation);
|
||||
}
|
||||
|
||||
static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* flipper_app) {
|
||||
@ -78,7 +82,6 @@ void desktop_scene_main_on_enter(void* context) {
|
||||
desktop->animation_manager, desktop_scene_main_check_animation_callback);
|
||||
animation_manager_set_interact_callback(
|
||||
desktop->animation_manager, desktop_scene_main_interact_animation_callback);
|
||||
desktop_locked_set_callback(desktop->locked_view, desktop_scene_main_callback, desktop);
|
||||
|
||||
furi_assert(osSemaphoreGetCount(desktop->unload_animation_semaphore) == 0);
|
||||
Loader* loader = furi_record_open("loader");
|
||||
@ -88,24 +91,7 @@ void desktop_scene_main_on_enter(void* context) {
|
||||
|
||||
desktop_main_set_callback(main_view, desktop_scene_main_callback, desktop);
|
||||
|
||||
DesktopMainSceneState state =
|
||||
scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneMain);
|
||||
if(state == DesktopMainSceneStateLockedNoPin) {
|
||||
desktop_locked_lock(desktop->locked_view);
|
||||
view_port_enabled_set(desktop->lock_viewport, true);
|
||||
} else if(state == DesktopMainSceneStateLockedWithPin) {
|
||||
LOAD_DESKTOP_SETTINGS(&desktop->settings);
|
||||
furi_assert(desktop->settings.pincode.length > 0);
|
||||
desktop_locked_lock_pincode(desktop->locked_view, desktop->settings.pincode);
|
||||
view_port_enabled_set(desktop->lock_viewport, true);
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLock);
|
||||
furi_hal_usb_disable();
|
||||
} else {
|
||||
furi_assert(state == DesktopMainSceneStateUnlocked);
|
||||
view_port_enabled_set(desktop->lock_viewport, false);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewMain);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdMain);
|
||||
}
|
||||
|
||||
bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
@ -142,23 +128,25 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
Loader* loader = furi_record_open("loader");
|
||||
LoaderStatus status =
|
||||
loader_start(loader, FLIPPER_APPS[desktop->settings.favorite].name, NULL);
|
||||
furi_check(status == LoaderStatusOk);
|
||||
if(status != LoaderStatusOk) {
|
||||
FURI_LOG_E(TAG, "loader_start failed: %d", status);
|
||||
}
|
||||
furi_record_close("loader");
|
||||
} else {
|
||||
FURI_LOG_E("DesktopSrv", "Can't find favorite application");
|
||||
FURI_LOG_E(TAG, "Can't find favorite application");
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopMainEventCheckAnimation:
|
||||
case DesktopAnimationEventCheckAnimation:
|
||||
animation_manager_check_blocking_process(desktop->animation_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopMainEventNewIdleAnimation:
|
||||
case DesktopAnimationEventNewIdleAnimation:
|
||||
animation_manager_new_idle_process(desktop->animation_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopMainEventInteractAnimation:
|
||||
case DesktopAnimationEventInteractAnimation:
|
||||
animation_manager_interact_process(desktop->animation_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
@ -171,16 +159,8 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) {
|
||||
animation_manager_load_and_continue_animation(desktop->animation_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopMainEventUnlocked:
|
||||
consumed = true;
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLock);
|
||||
furi_hal_usb_enable();
|
||||
view_port_enabled_set(desktop->lock_viewport, false);
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateUnlocked);
|
||||
break;
|
||||
case DesktopMainEventUpdate:
|
||||
desktop_locked_update(desktop->locked_view);
|
||||
case DesktopLockedEventUpdate:
|
||||
desktop_view_locked_update(desktop->locked_view);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
@ -209,5 +189,4 @@ void desktop_scene_main_on_exit(void* context) {
|
||||
animation_manager_set_check_callback(desktop->animation_manager, NULL);
|
||||
animation_manager_set_interact_callback(desktop->animation_manager, NULL);
|
||||
animation_manager_set_context(desktop->animation_manager, desktop);
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneMain, MAIN_VIEW_DEFAULT);
|
||||
}
|
||||
|
||||
162
applications/desktop/scenes/desktop_scene_pin_input.c
Normal file
162
applications/desktop/scenes/desktop_scene_pin_input.c
Normal file
@ -0,0 +1,162 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_stack.h>
|
||||
#include <stdint.h>
|
||||
#include <portmacro.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#include "../desktop.h"
|
||||
#include "../desktop_i.h"
|
||||
#include "../animations/animation_manager.h"
|
||||
#include "../views/desktop_events.h"
|
||||
#include "../views/desktop_view_pin_input.h"
|
||||
#include "../desktop_helpers.h"
|
||||
#include "desktop_scene.h"
|
||||
#include "desktop_scene_i.h"
|
||||
|
||||
#define WRONG_PIN_HEADER_TIMEOUT 3000
|
||||
#define INPUT_PIN_VIEW_TIMEOUT 15000
|
||||
|
||||
typedef struct {
|
||||
TimerHandle_t timer;
|
||||
} DesktopScenePinInputState;
|
||||
|
||||
static void desktop_scene_locked_light_red(bool value) {
|
||||
NotificationApp* app = furi_record_open("notification");
|
||||
if(value) {
|
||||
notification_message(app, &sequence_set_only_red_255);
|
||||
} else {
|
||||
notification_message(app, &sequence_reset_red);
|
||||
}
|
||||
furi_record_close("notification");
|
||||
}
|
||||
|
||||
static void
|
||||
desktop_scene_pin_input_set_timer(Desktop* desktop, bool enable, TickType_t new_period) {
|
||||
furi_assert(desktop);
|
||||
|
||||
DesktopScenePinInputState* state = (DesktopScenePinInputState*)scene_manager_get_scene_state(
|
||||
desktop->scene_manager, DesktopScenePinInput);
|
||||
furi_assert(state);
|
||||
if(enable) {
|
||||
xTimerChangePeriod(state->timer, new_period, portMAX_DELAY);
|
||||
} else {
|
||||
xTimerStop(state->timer, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_scene_pin_input_back_callback(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventBack);
|
||||
}
|
||||
|
||||
static void desktop_scene_pin_input_done_callback(const PinCode* pin_code, void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
if(pins_are_equal(&desktop->settings.pin_code, pin_code)) {
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventUnlocked);
|
||||
} else {
|
||||
view_dispatcher_send_custom_event(
|
||||
desktop->view_dispatcher, DesktopPinInputEventUnlockFailed);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_scene_pin_input_timer_callback(TimerHandle_t timer) {
|
||||
Desktop* desktop = pvTimerGetTimerID(timer);
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
desktop->view_dispatcher, DesktopPinInputEventResetWrongPinLabel);
|
||||
}
|
||||
|
||||
void desktop_scene_pin_input_on_enter(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
|
||||
desktop_view_pin_input_set_context(desktop->pin_input_view, desktop);
|
||||
desktop_view_pin_input_set_back_callback(
|
||||
desktop->pin_input_view, desktop_scene_pin_input_back_callback);
|
||||
desktop_view_pin_input_set_timeout_callback(
|
||||
desktop->pin_input_view, desktop_scene_pin_input_back_callback);
|
||||
desktop_view_pin_input_set_done_callback(
|
||||
desktop->pin_input_view, desktop_scene_pin_input_done_callback);
|
||||
|
||||
DesktopScenePinInputState* state = furi_alloc(sizeof(DesktopScenePinInputState));
|
||||
state->timer =
|
||||
xTimerCreate(NULL, 10000, pdFALSE, desktop, desktop_scene_pin_input_timer_callback);
|
||||
scene_manager_set_scene_state(desktop->scene_manager, DesktopScenePinInput, (uint32_t)state);
|
||||
|
||||
desktop_view_pin_input_hide_pin(desktop->pin_input_view, true);
|
||||
desktop_view_pin_input_set_label_button(desktop->pin_input_view, "OK");
|
||||
desktop_view_pin_input_set_label_secondary(desktop->pin_input_view, 44, 25, "Enter PIN:");
|
||||
desktop_view_pin_input_set_pin_position(desktop->pin_input_view, 64, 37);
|
||||
desktop_view_pin_input_reset_pin(desktop->pin_input_view);
|
||||
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
bool consumed = false;
|
||||
uint32_t pin_fails = 0;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DesktopPinInputEventUnlockFailed:
|
||||
pin_fails = furi_hal_rtc_get_pin_fails();
|
||||
pin_fails++;
|
||||
furi_hal_rtc_set_pin_fails(pin_fails);
|
||||
uint32_t pin_timeout = desktop_helpers_get_pin_fail_timeout(pin_fails);
|
||||
if(pin_timeout > 0) {
|
||||
desktop_helpers_emit_error_notification();
|
||||
scene_manager_set_scene_state(
|
||||
desktop->scene_manager, DesktopScenePinTimeout, pin_timeout);
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopScenePinTimeout);
|
||||
} else {
|
||||
desktop_scene_locked_light_red(true);
|
||||
desktop_view_pin_input_set_label_primary(desktop->pin_input_view, 0, 0, NULL);
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
desktop->pin_input_view, 25, 25, "Wrong PIN try again:");
|
||||
desktop_scene_pin_input_set_timer(desktop, true, WRONG_PIN_HEADER_TIMEOUT);
|
||||
desktop_view_pin_input_reset_pin(desktop->pin_input_view);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopPinInputEventResetWrongPinLabel:
|
||||
desktop_scene_locked_light_red(false);
|
||||
desktop_view_pin_input_set_label_primary(desktop->pin_input_view, 0, 0, NULL);
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
desktop->pin_input_view, 44, 25, "Enter PIN:");
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopPinInputEventUnlocked:
|
||||
desktop_view_locked_unlock(desktop->locked_view);
|
||||
furi_hal_rtc_set_pin_fails(0);
|
||||
desktop_helpers_unlock_system(desktop);
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneMain);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopPinInputEventBack:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
desktop->scene_manager, DesktopSceneLocked);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_scene_pin_input_on_exit(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
desktop_scene_locked_light_red(false);
|
||||
|
||||
DesktopScenePinInputState* state = (DesktopScenePinInputState*)scene_manager_get_scene_state(
|
||||
desktop->scene_manager, DesktopScenePinInput);
|
||||
xTimerStop(state->timer, portMAX_DELAY);
|
||||
while(xTimerIsTimerActive(state->timer)) {
|
||||
delay(1);
|
||||
}
|
||||
xTimerDelete(state->timer, portMAX_DELAY);
|
||||
free(state);
|
||||
}
|
||||
46
applications/desktop/scenes/desktop_scene_pin_timeout.c
Normal file
46
applications/desktop/scenes/desktop_scene_pin_timeout.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <furi.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <portmacro.h>
|
||||
#include <timer.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "../views/desktop_view_pin_timeout.h"
|
||||
#include "desktop_scene.h"
|
||||
#include "desktop_scene_i.h"
|
||||
|
||||
static void desktop_scene_pin_timeout_callback(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinTimeoutExit);
|
||||
}
|
||||
|
||||
void desktop_scene_pin_timeout_on_enter(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
|
||||
uint32_t timeout =
|
||||
scene_manager_get_scene_state(desktop->scene_manager, DesktopScenePinTimeout);
|
||||
desktop_view_pin_timeout_start(desktop->pin_timeout_view, timeout);
|
||||
desktop_view_pin_timeout_set_callback(
|
||||
desktop->pin_timeout_view, desktop_scene_pin_timeout_callback, desktop);
|
||||
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdPinTimeout);
|
||||
}
|
||||
|
||||
bool desktop_scene_pin_timeout_on_event(void* context, SceneManagerEvent event) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DesktopPinTimeoutExit:
|
||||
scene_manager_previous_scene(desktop->scene_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_scene_pin_timeout_on_exit(void* context) {
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
#include "../desktop_i.h"
|
||||
|
||||
#define SCENE_EXIT_EVENT (0U)
|
||||
|
||||
void desktop_scene_ok_callback(void* context) {
|
||||
Desktop* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT);
|
||||
}
|
||||
|
||||
void desktop_scene_pinsetup_on_enter(void* context) {
|
||||
Desktop* app = context;
|
||||
CodeInput* code_input = app->code_input;
|
||||
|
||||
code_input_set_result_callback(
|
||||
code_input,
|
||||
desktop_scene_ok_callback,
|
||||
NULL,
|
||||
app,
|
||||
app->settings.pincode.data,
|
||||
&app->settings.pincode.length,
|
||||
true);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopViewPinSetup);
|
||||
}
|
||||
|
||||
bool desktop_scene_pinsetup_on_event(void* context, SceneManagerEvent event) {
|
||||
Desktop* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EXIT_EVENT:
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_scene_pinsetup_on_exit(void* context) {
|
||||
Desktop* app = context;
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
code_input_set_result_callback(app->code_input, NULL, NULL, NULL, NULL, NULL, 0);
|
||||
code_input_set_header_text(app->code_input, "");
|
||||
}
|
||||
@ -6,24 +6,35 @@ typedef enum {
|
||||
DesktopMainEventOpenFavorite,
|
||||
DesktopMainEventOpenMenu,
|
||||
DesktopMainEventOpenDebug,
|
||||
DesktopMainEventUpdate,
|
||||
DesktopMainEventUnlocked,
|
||||
DesktopMainEventRightShort,
|
||||
DesktopMainEventCheckAnimation,
|
||||
DesktopMainEventNewIdleAnimation,
|
||||
DesktopMainEventInteractAnimation,
|
||||
DesktopMainEventBeforeAppStarted,
|
||||
DesktopMainEventAfterAppFinished,
|
||||
DesktopLockedEventUnlock,
|
||||
DesktopLockedEventCheckAnimation,
|
||||
DesktopLockedEventMax,
|
||||
|
||||
DesktopLockedEventUnlocked,
|
||||
DesktopLockedEventUpdate,
|
||||
DesktopLockedEventShowPinInput,
|
||||
|
||||
DesktopPinInputEventResetWrongPinLabel,
|
||||
DesktopPinInputEventUnlocked,
|
||||
DesktopPinInputEventUnlockFailed,
|
||||
DesktopPinInputEventBack,
|
||||
|
||||
DesktopPinTimeoutExit,
|
||||
|
||||
DesktopDebugEventDeed,
|
||||
DesktopDebugEventWrongDeed,
|
||||
DesktopDebugEventSaveState,
|
||||
DesktopDebugEventExit,
|
||||
|
||||
DesktopFirstStartCompleted,
|
||||
DesktopFirstStartPoweroff,
|
||||
|
||||
DesktopLockMenuEventLock,
|
||||
DesktopLockMenuEventPinLock,
|
||||
DesktopLockMenuEventExit,
|
||||
|
||||
DesktopAnimationEventCheckAnimation,
|
||||
DesktopAnimationEventNewIdleAnimation,
|
||||
DesktopAnimationEventInteractAnimation,
|
||||
|
||||
} DesktopEvent;
|
||||
|
||||
@ -1,247 +0,0 @@
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
#include "furi/check.h"
|
||||
#include "gui/view.h"
|
||||
#include "portmacro.h"
|
||||
#include <furi.h>
|
||||
#include <gui/gui_i.h>
|
||||
#include <gui/elements.h>
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_locked.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define DOOR_MOVING_INTERVAL_MS (1000 / 16)
|
||||
#define UNLOCKED_HINT_TIMEOUT_MS (2000)
|
||||
|
||||
struct DesktopLockedView {
|
||||
View* view;
|
||||
DesktopLockedViewCallback callback;
|
||||
void* context;
|
||||
|
||||
TimerHandle_t timer;
|
||||
uint8_t lock_count;
|
||||
uint32_t lock_lastpress;
|
||||
|
||||
PinCode pincode;
|
||||
PinCode pincode_input;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t hint_icon_expire_at;
|
||||
bool unlocked_hint;
|
||||
bool locked;
|
||||
bool pin_locked;
|
||||
|
||||
int8_t door_left_x;
|
||||
int8_t door_right_x;
|
||||
bool animation_seq_end;
|
||||
} DesktopLockedViewModel;
|
||||
|
||||
static void desktop_locked_unlock(DesktopLockedView* locked_view);
|
||||
|
||||
void desktop_locked_set_callback(
|
||||
DesktopLockedView* locked_view,
|
||||
DesktopLockedViewCallback callback,
|
||||
void* context) {
|
||||
furi_assert(locked_view);
|
||||
furi_assert(callback);
|
||||
locked_view->callback = callback;
|
||||
locked_view->context = context;
|
||||
}
|
||||
|
||||
void locked_view_timer_callback(TimerHandle_t timer) {
|
||||
DesktopLockedView* locked_view = pvTimerGetTimerID(timer);
|
||||
locked_view->callback(DesktopMainEventUpdate, locked_view->context);
|
||||
}
|
||||
|
||||
static void desktop_locked_update_hint_icon_timeout(DesktopLockedView* locked_view) {
|
||||
DesktopLockedViewModel* model = view_get_model(locked_view->view);
|
||||
model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
|
||||
view_commit_model(locked_view->view, true);
|
||||
}
|
||||
|
||||
static void desktop_locked_reset_door_pos(DesktopLockedView* locked_view) {
|
||||
DesktopLockedViewModel* model = view_get_model(locked_view->view);
|
||||
model->animation_seq_end = false;
|
||||
model->door_left_x = DOOR_L_POS;
|
||||
model->door_right_x = DOOR_R_POS;
|
||||
view_commit_model(locked_view->view, true);
|
||||
}
|
||||
|
||||
void desktop_locked_update(DesktopLockedView* locked_view) {
|
||||
bool stop_timer = false;
|
||||
|
||||
DesktopLockedViewModel* model = view_get_model(locked_view->view);
|
||||
if(model->locked) {
|
||||
if(model->door_left_x != DOOR_L_POS_MAX) {
|
||||
model->door_left_x = CLAMP(model->door_left_x + 5, DOOR_L_POS_MAX, DOOR_L_POS);
|
||||
model->door_right_x = CLAMP(model->door_right_x - 5, DOOR_R_POS, DOOR_R_POS_MIN);
|
||||
} else {
|
||||
model->animation_seq_end = true;
|
||||
}
|
||||
stop_timer = model->animation_seq_end;
|
||||
} else {
|
||||
model->unlocked_hint = false;
|
||||
stop_timer = true;
|
||||
}
|
||||
view_commit_model(locked_view->view, true);
|
||||
|
||||
if(stop_timer) {
|
||||
xTimerStop(locked_view->timer, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void desktop_locked_draw(Canvas* canvas, void* model) {
|
||||
DesktopLockedViewModel* m = model;
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(m->locked) {
|
||||
if(!m->animation_seq_end) {
|
||||
canvas_draw_icon(canvas, m->door_left_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorLeft_70x55);
|
||||
canvas_draw_icon(canvas, m->door_right_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
|
||||
} else if((now < m->hint_icon_expire_at) && !m->pin_locked) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_icon(canvas, 13, 2 + STATUS_BAR_Y_SHIFT, &I_LockPopup_100x49);
|
||||
elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:");
|
||||
}
|
||||
} else {
|
||||
if(m->unlocked_hint) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
View* desktop_locked_get_view(DesktopLockedView* locked_view) {
|
||||
furi_assert(locked_view);
|
||||
return locked_view->view;
|
||||
}
|
||||
|
||||
bool desktop_locked_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
DesktopLockedView* locked_view = context;
|
||||
bool locked = false;
|
||||
bool locked_with_pin = false;
|
||||
uint32_t press_time = xTaskGetTickCount();
|
||||
|
||||
{
|
||||
DesktopLockedViewModel* model = view_get_model(locked_view->view);
|
||||
bool changed = false;
|
||||
locked = model->locked;
|
||||
locked_with_pin = model->pin_locked;
|
||||
if(!locked && model->unlocked_hint && event->type == InputTypePress) {
|
||||
model->unlocked_hint = false;
|
||||
changed = true;
|
||||
}
|
||||
view_commit_model(locked_view->view, changed);
|
||||
}
|
||||
|
||||
if(!locked || (event->type != InputTypeShort)) {
|
||||
return locked;
|
||||
}
|
||||
|
||||
if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
locked_view->lock_count = 0;
|
||||
locked_view->pincode_input.length = 0;
|
||||
}
|
||||
|
||||
if(locked_with_pin) {
|
||||
locked_view->pincode_input.length = code_input_push(
|
||||
locked_view->pincode_input.data, locked_view->pincode_input.length, event->key);
|
||||
bool match = code_input_compare(
|
||||
locked_view->pincode_input.data,
|
||||
locked_view->pincode_input.length,
|
||||
locked_view->pincode.data,
|
||||
locked_view->pincode.length);
|
||||
|
||||
if(match) {
|
||||
desktop_locked_unlock(locked_view);
|
||||
}
|
||||
} else {
|
||||
if(event->key == InputKeyBack) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
locked_view->lock_count++;
|
||||
if(locked_view->lock_count == UNLOCK_CNT) {
|
||||
desktop_locked_unlock(locked_view);
|
||||
}
|
||||
} else {
|
||||
desktop_locked_update_hint_icon_timeout(locked_view);
|
||||
locked_view->lock_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
locked_view->lock_lastpress = press_time;
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
DesktopLockedView* desktop_locked_alloc() {
|
||||
DesktopLockedView* locked_view = furi_alloc(sizeof(DesktopLockedView));
|
||||
locked_view->view = view_alloc();
|
||||
locked_view->timer =
|
||||
xTimerCreate("Locked view", 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback);
|
||||
|
||||
view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopLockedViewModel));
|
||||
view_set_context(locked_view->view, locked_view);
|
||||
view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_draw);
|
||||
view_set_input_callback(locked_view->view, desktop_locked_input);
|
||||
|
||||
return locked_view;
|
||||
}
|
||||
|
||||
void desktop_locked_free(DesktopLockedView* locked_view) {
|
||||
furi_assert(locked_view);
|
||||
osTimerDelete(locked_view->timer);
|
||||
view_free(locked_view->view);
|
||||
free(locked_view);
|
||||
}
|
||||
|
||||
void desktop_locked_lock(DesktopLockedView* locked_view) {
|
||||
locked_view->pincode.length = 0;
|
||||
DesktopLockedViewModel* model = view_get_model(locked_view->view);
|
||||
model->locked = true;
|
||||
model->pin_locked = false;
|
||||
view_commit_model(locked_view->view, true);
|
||||
desktop_locked_reset_door_pos(locked_view);
|
||||
xTimerChangePeriod(locked_view->timer, DOOR_MOVING_INTERVAL_MS, portMAX_DELAY);
|
||||
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_set_lockdown(gui, true);
|
||||
furi_record_close("gui");
|
||||
}
|
||||
|
||||
void desktop_locked_lock_pincode(DesktopLockedView* locked_view, PinCode pincode) {
|
||||
locked_view->pincode = pincode;
|
||||
locked_view->pincode_input.length = 0;
|
||||
DesktopLockedViewModel* model = view_get_model(locked_view->view);
|
||||
model->locked = true;
|
||||
model->pin_locked = true;
|
||||
view_commit_model(locked_view->view, true);
|
||||
desktop_locked_reset_door_pos(locked_view);
|
||||
xTimerChangePeriod(locked_view->timer, DOOR_MOVING_INTERVAL_MS, portMAX_DELAY);
|
||||
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_set_lockdown(gui, true);
|
||||
furi_record_close("gui");
|
||||
}
|
||||
|
||||
static void desktop_locked_unlock(DesktopLockedView* locked_view) {
|
||||
furi_assert(locked_view);
|
||||
|
||||
locked_view->lock_count = 0;
|
||||
DesktopLockedViewModel* model = view_get_model(locked_view->view);
|
||||
model->locked = false;
|
||||
model->pin_locked = false;
|
||||
model->unlocked_hint = true;
|
||||
view_commit_model(locked_view->view, true);
|
||||
locked_view->callback(DesktopMainEventUnlocked, locked_view->context);
|
||||
xTimerChangePeriod(locked_view->timer, UNLOCKED_HINT_TIMEOUT_MS, portMAX_DELAY);
|
||||
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_set_lockdown(gui, false);
|
||||
furi_record_close("gui");
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <desktop/desktop_settings/desktop_settings.h>
|
||||
#include <gui/view.h>
|
||||
#include "desktop_events.h"
|
||||
|
||||
#define UNLOCK_RST_TIMEOUT 300
|
||||
#define UNLOCK_CNT 3
|
||||
|
||||
#define DOOR_L_POS -57
|
||||
#define DOOR_L_POS_MAX 0
|
||||
#define DOOR_R_POS 115
|
||||
#define DOOR_R_POS_MIN 60
|
||||
|
||||
typedef enum {
|
||||
DesktopLockedWithPin,
|
||||
DesktopLockedNoPin,
|
||||
} DesktopLockedSceneState;
|
||||
|
||||
typedef struct DesktopLockedView DesktopLockedView;
|
||||
|
||||
typedef void (*DesktopLockedViewCallback)(DesktopEvent event, void* context);
|
||||
|
||||
void desktop_locked_set_callback(
|
||||
DesktopLockedView* locked_view,
|
||||
DesktopLockedViewCallback callback,
|
||||
void* context);
|
||||
|
||||
void desktop_locked_update(DesktopLockedView* locked_view);
|
||||
|
||||
View* desktop_locked_get_view(DesktopLockedView* locked_view);
|
||||
DesktopLockedView* desktop_locked_alloc();
|
||||
void desktop_locked_free(DesktopLockedView* locked_view);
|
||||
|
||||
void desktop_locked_lock_pincode(DesktopLockedView* locked_view, PinCode pincode);
|
||||
void desktop_locked_lock(DesktopLockedView* locked_view);
|
||||
@ -1,11 +1,11 @@
|
||||
#include <toolbox/version.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <dolphin/helpers/dolphin_state.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_debug.h"
|
||||
#include "dolphin/helpers/dolphin_state.h"
|
||||
#include "dolphin/dolphin.h"
|
||||
#include "desktop_view_debug.h"
|
||||
|
||||
void desktop_debug_set_callback(
|
||||
DesktopDebugView* debug_view,
|
||||
@ -1,8 +1,9 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_first_start.h"
|
||||
#include "desktop_view_first_start.h"
|
||||
|
||||
#define DESKTOP_FIRST_START_POWEROFF_SHORT 5000
|
||||
#define DESKTOP_FIRST_START_POWEROFF_LONG (60 * 60 * 1000)
|
||||
@ -2,7 +2,7 @@
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_lock_menu.h"
|
||||
#include "desktop_view_lock_menu.h"
|
||||
|
||||
#define LOCK_MENU_ITEMS_NB 3
|
||||
|
||||
233
applications/desktop/views/desktop_view_locked.c
Normal file
233
applications/desktop/views/desktop_view_locked.c
Normal file
@ -0,0 +1,233 @@
|
||||
#include <projdefs.h>
|
||||
#include <stdint.h>
|
||||
#include <furi.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/icon.h>
|
||||
#include <gui/view.h>
|
||||
#include <portmacro.h>
|
||||
|
||||
#include "../desktop_settings/desktop_settings.h"
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_view_locked.h"
|
||||
|
||||
#define DOOR_MOVING_INTERVAL_MS (1000 / 16)
|
||||
#define UNLOCKED_HINT_TIMEOUT_MS (2000)
|
||||
|
||||
#define DOOR_OFFSET_START -55
|
||||
#define DOOR_OFFSET_END 0
|
||||
|
||||
#define DOOR_L_FINAL_POS 0
|
||||
#define DOOR_R_FINAL_POS 60
|
||||
|
||||
#define UNLOCK_CNT 3
|
||||
#define UNLOCK_RST_TIMEOUT 600
|
||||
|
||||
struct DesktopViewLocked {
|
||||
View* view;
|
||||
DesktopViewLockedCallback callback;
|
||||
void* context;
|
||||
|
||||
TimerHandle_t timer;
|
||||
uint8_t lock_count;
|
||||
uint32_t lock_lastpress;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t hint_icon_expire_at;
|
||||
bool unlocked_hint;
|
||||
bool locked;
|
||||
bool pin_locked;
|
||||
|
||||
int8_t door_offset;
|
||||
bool doors_closing;
|
||||
} DesktopViewLockedModel;
|
||||
|
||||
void desktop_view_locked_set_callback(
|
||||
DesktopViewLocked* locked_view,
|
||||
DesktopViewLockedCallback callback,
|
||||
void* context) {
|
||||
furi_assert(locked_view);
|
||||
furi_assert(callback);
|
||||
locked_view->callback = callback;
|
||||
locked_view->context = context;
|
||||
}
|
||||
|
||||
static void locked_view_timer_callback(TimerHandle_t timer) {
|
||||
DesktopViewLocked* locked_view = pvTimerGetTimerID(timer);
|
||||
locked_view->callback(DesktopLockedEventUpdate, locked_view->context);
|
||||
}
|
||||
|
||||
static void desktop_view_locked_doors_draw(Canvas* canvas, DesktopViewLockedModel* model) {
|
||||
int8_t offset = model->door_offset;
|
||||
uint8_t door_left_x = DOOR_L_FINAL_POS + offset;
|
||||
uint8_t door_right_x = DOOR_R_FINAL_POS - offset;
|
||||
uint8_t height = icon_get_height(&I_DoorLeft_70x55);
|
||||
canvas_draw_icon(canvas, door_left_x, canvas_height(canvas) - height, &I_DoorLeft_70x55);
|
||||
canvas_draw_icon(canvas, door_right_x, canvas_height(canvas) - height, &I_DoorRight_70x55);
|
||||
}
|
||||
|
||||
static bool desktop_view_locked_doors_move(DesktopViewLockedModel* model) {
|
||||
bool stop = false;
|
||||
if(model->door_offset < DOOR_OFFSET_END) {
|
||||
model->door_offset = CLAMP(model->door_offset + 5, DOOR_OFFSET_END, DOOR_OFFSET_START);
|
||||
stop = true;
|
||||
}
|
||||
|
||||
return stop;
|
||||
}
|
||||
|
||||
static void desktop_view_locked_update_hint_icon_timeout(DesktopViewLocked* locked_view) {
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
|
||||
view_commit_model(locked_view->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_locked_update(DesktopViewLocked* locked_view) {
|
||||
bool stop_timer = false;
|
||||
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
if(model->locked) {
|
||||
model->doors_closing = desktop_view_locked_doors_move(model);
|
||||
stop_timer = !model->doors_closing;
|
||||
} else {
|
||||
model->unlocked_hint = false;
|
||||
stop_timer = true;
|
||||
}
|
||||
view_commit_model(locked_view->view, true);
|
||||
|
||||
if(stop_timer) {
|
||||
xTimerStop(locked_view->timer, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_view_locked_draw(Canvas* canvas, void* model) {
|
||||
DesktopViewLockedModel* m = model;
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(m->locked) {
|
||||
if(m->doors_closing) {
|
||||
desktop_view_locked_doors_draw(canvas, m);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
|
||||
} else if((now < m->hint_icon_expire_at) && !m->pin_locked) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_bold_rounded_frame(canvas, 14, 2 + STATUS_BAR_Y_SHIFT, 99, 48);
|
||||
elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:");
|
||||
canvas_draw_icon(canvas, 65, 36 + STATUS_BAR_Y_SHIFT, &I_Back3_45x8);
|
||||
canvas_draw_icon(canvas, 16, 7 + STATUS_BAR_Y_SHIFT, &I_WarningDolphin_45x42);
|
||||
canvas_draw_dot(canvas, 17, 61);
|
||||
}
|
||||
} else {
|
||||
if(m->unlocked_hint) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
View* desktop_view_locked_get_view(DesktopViewLocked* locked_view) {
|
||||
furi_assert(locked_view);
|
||||
return locked_view->view;
|
||||
}
|
||||
|
||||
static bool desktop_view_locked_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
DesktopViewLocked* locked_view = context;
|
||||
bool locked = false;
|
||||
bool locked_with_pin = false;
|
||||
bool doors_closing = false;
|
||||
uint32_t press_time = xTaskGetTickCount();
|
||||
|
||||
{
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
bool changed = false;
|
||||
locked = model->locked;
|
||||
locked_with_pin = model->pin_locked;
|
||||
doors_closing = model->doors_closing;
|
||||
if(!locked && model->unlocked_hint && event->type == InputTypePress) {
|
||||
model->unlocked_hint = false;
|
||||
changed = true;
|
||||
}
|
||||
view_commit_model(locked_view->view, changed);
|
||||
}
|
||||
|
||||
if(!locked || doors_closing || (event->type != InputTypeShort)) {
|
||||
return locked;
|
||||
}
|
||||
|
||||
if(locked_with_pin) {
|
||||
locked_view->callback(DesktopLockedEventShowPinInput, locked_view->context);
|
||||
} else {
|
||||
if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
locked_view->lock_count = 0;
|
||||
}
|
||||
|
||||
desktop_view_locked_update_hint_icon_timeout(locked_view);
|
||||
if(event->key == InputKeyBack) {
|
||||
locked_view->lock_lastpress = press_time;
|
||||
locked_view->lock_count++;
|
||||
if(locked_view->lock_count == UNLOCK_CNT) {
|
||||
desktop_view_locked_unlock(locked_view);
|
||||
locked_view->callback(DesktopLockedEventUnlocked, locked_view->context);
|
||||
}
|
||||
} else {
|
||||
locked_view->lock_count = 0;
|
||||
}
|
||||
|
||||
locked_view->lock_lastpress = press_time;
|
||||
}
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
DesktopViewLocked* desktop_view_locked_alloc() {
|
||||
DesktopViewLocked* locked_view = furi_alloc(sizeof(DesktopViewLocked));
|
||||
locked_view->view = view_alloc();
|
||||
locked_view->timer =
|
||||
xTimerCreate(NULL, 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback);
|
||||
|
||||
locked_view->view = view_alloc();
|
||||
view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopViewLockedModel));
|
||||
view_set_context(locked_view->view, locked_view);
|
||||
view_set_draw_callback(locked_view->view, desktop_view_locked_draw);
|
||||
view_set_input_callback(locked_view->view, desktop_view_locked_input);
|
||||
|
||||
return locked_view;
|
||||
}
|
||||
|
||||
void desktop_view_locked_free(DesktopViewLocked* locked_view) {
|
||||
furi_assert(locked_view);
|
||||
osTimerDelete(locked_view->timer);
|
||||
view_free(locked_view->view);
|
||||
free(locked_view);
|
||||
}
|
||||
|
||||
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) {
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->doors_closing = true;
|
||||
model->door_offset = DOOR_OFFSET_START;
|
||||
view_commit_model(locked_view->view, true);
|
||||
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(DOOR_MOVING_INTERVAL_MS), portMAX_DELAY);
|
||||
}
|
||||
|
||||
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked) {
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->locked = true;
|
||||
model->pin_locked = pin_locked;
|
||||
view_commit_model(locked_view->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_locked_unlock(DesktopViewLocked* locked_view) {
|
||||
furi_assert(locked_view);
|
||||
|
||||
locked_view->lock_count = 0;
|
||||
DesktopViewLockedModel* model = view_get_model(locked_view->view);
|
||||
model->locked = false;
|
||||
model->pin_locked = false;
|
||||
model->unlocked_hint = true;
|
||||
view_commit_model(locked_view->view, true);
|
||||
xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(UNLOCKED_HINT_TIMEOUT_MS), portMAX_DELAY);
|
||||
}
|
||||
21
applications/desktop/views/desktop_view_locked.h
Normal file
21
applications/desktop/views/desktop_view_locked.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "../desktop_settings/desktop_settings.h"
|
||||
#include "../views/desktop_events.h"
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct DesktopViewLocked DesktopViewLocked;
|
||||
|
||||
typedef void (*DesktopViewLockedCallback)(DesktopEvent event, void* context);
|
||||
|
||||
void desktop_view_locked_set_callback(
|
||||
DesktopViewLocked* locked_view,
|
||||
DesktopViewLockedCallback callback,
|
||||
void* context);
|
||||
void desktop_view_locked_update(DesktopViewLocked* locked_view);
|
||||
View* desktop_view_locked_get_view(DesktopViewLocked* locked_view);
|
||||
DesktopViewLocked* desktop_view_locked_alloc();
|
||||
void desktop_view_locked_free(DesktopViewLocked* locked_view);
|
||||
void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked);
|
||||
void desktop_view_locked_unlock(DesktopViewLocked* locked_view);
|
||||
void desktop_view_locked_close_doors(DesktopViewLocked* locked_view);
|
||||
@ -7,7 +7,7 @@
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_main.h"
|
||||
#include "desktop_view_main.h"
|
||||
|
||||
struct DesktopMainView {
|
||||
View* view;
|
||||
340
applications/desktop/views/desktop_view_pin_input.c
Normal file
340
applications/desktop/views/desktop_view_pin_input.c
Normal file
@ -0,0 +1,340 @@
|
||||
#include <gui/canvas.h>
|
||||
#include <furi.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/elements.h>
|
||||
#include <stdint.h>
|
||||
#include <portmacro.h>
|
||||
|
||||
#include "desktop_view_pin_input.h"
|
||||
#include "../desktop_settings/desktop_settings.h"
|
||||
|
||||
#define NO_ACTIVITY_TIMEOUT 15000
|
||||
|
||||
#define PIN_CELL_WIDTH 13
|
||||
#define DEFAULT_PIN_X 64
|
||||
#define DEFAULT_PIN_Y 32
|
||||
|
||||
struct DesktopViewPinInput {
|
||||
View* view;
|
||||
DesktopViewPinInputCallback back_callback;
|
||||
DesktopViewPinInputCallback timeout_callback;
|
||||
DesktopViewPinInputDoneCallback done_callback;
|
||||
void* context;
|
||||
TimerHandle_t timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PinCode pin;
|
||||
bool pin_hidden;
|
||||
bool locked_input;
|
||||
uint8_t pin_x;
|
||||
uint8_t pin_y;
|
||||
const char* primary_str;
|
||||
uint8_t primary_str_x;
|
||||
uint8_t primary_str_y;
|
||||
const char* secondary_str;
|
||||
uint8_t secondary_str_x;
|
||||
uint8_t secondary_str_y;
|
||||
const char* button_label;
|
||||
} DesktopViewPinInputModel;
|
||||
|
||||
static bool desktop_view_pin_input_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
DesktopViewPinInput* pin_input = context;
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
|
||||
bool call_back_callback = false;
|
||||
bool call_done_callback = false;
|
||||
PinCode pin_code = {0};
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
switch(event->key) {
|
||||
case InputKeyRight:
|
||||
case InputKeyLeft:
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
if(!model->locked_input) {
|
||||
if(model->pin.length < MAX_PIN_SIZE) {
|
||||
model->pin.data[model->pin.length++] = event->key;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if(model->pin.length >= MIN_PIN_SIZE) {
|
||||
call_done_callback = true;
|
||||
pin_code = model->pin;
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if(!model->locked_input) {
|
||||
if(model->pin.length > 0) {
|
||||
model->pin.length = 0;
|
||||
} else {
|
||||
call_back_callback = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
furi_assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
view_commit_model(pin_input->view, true);
|
||||
|
||||
if(call_done_callback && pin_input->done_callback) {
|
||||
pin_input->done_callback(&pin_code, pin_input->context);
|
||||
} else if(call_back_callback && pin_input->back_callback) {
|
||||
pin_input->back_callback(pin_input->context);
|
||||
}
|
||||
|
||||
xTimerStart(pin_input->timer, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void desktop_view_pin_input_draw_cells(Canvas* canvas, DesktopViewPinInputModel* model) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(model);
|
||||
|
||||
uint8_t draw_pin_size = MAX(4, model->pin.length + 1);
|
||||
if(model->locked_input || (model->pin.length == MAX_PIN_SIZE)) {
|
||||
draw_pin_size = model->pin.length;
|
||||
}
|
||||
|
||||
uint8_t x = model->pin_x - (draw_pin_size * (PIN_CELL_WIDTH - 1)) / 2;
|
||||
uint8_t y = model->pin_y - (PIN_CELL_WIDTH / 2);
|
||||
|
||||
for(int i = 0; i < draw_pin_size; ++i) {
|
||||
canvas_draw_frame(canvas, x, y, PIN_CELL_WIDTH, PIN_CELL_WIDTH);
|
||||
if(i < model->pin.length) {
|
||||
if(model->pin_hidden) {
|
||||
canvas_draw_icon(canvas, x + 3, y + 3, &I_Pin_star_7x7);
|
||||
} else {
|
||||
switch(model->pin.data[i]) {
|
||||
case InputKeyDown:
|
||||
canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_down_7x9);
|
||||
break;
|
||||
case InputKeyUp:
|
||||
canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_up7x9);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
canvas_draw_icon(canvas, x + 2, y + 3, &I_Pin_arrow_left_9x7);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
canvas_draw_icon(canvas, x + 2, y + 3, &I_Pin_arrow_right_9x7);
|
||||
break;
|
||||
default:
|
||||
furi_assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if(i == model->pin.length) {
|
||||
canvas_draw_icon(canvas, x + 4, y + PIN_CELL_WIDTH + 1, &I_Pin_pointer_5x3);
|
||||
}
|
||||
x += PIN_CELL_WIDTH - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_view_pin_input_draw(Canvas* canvas, void* context) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(context);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
DesktopViewPinInputModel* model = context;
|
||||
desktop_view_pin_input_draw_cells(canvas, model);
|
||||
|
||||
if((model->pin.length > 0) && !model->locked_input) {
|
||||
canvas_draw_icon(canvas, 4, 53, &I_Pin_back_full_40x8);
|
||||
}
|
||||
|
||||
if(model->button_label && ((model->pin.length >= MIN_PIN_SIZE) || model->locked_input)) {
|
||||
elements_button_center(canvas, model->button_label);
|
||||
}
|
||||
|
||||
if(model->primary_str) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, model->primary_str_x, model->primary_str_y, model->primary_str);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
}
|
||||
|
||||
if(model->secondary_str) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(
|
||||
canvas, model->secondary_str_x, model->secondary_str_y, model->secondary_str);
|
||||
}
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_timer_callback(TimerHandle_t timer) {
|
||||
DesktopViewPinInput* pin_input = pvTimerGetTimerID(timer);
|
||||
|
||||
if(pin_input->timeout_callback) {
|
||||
pin_input->timeout_callback(pin_input->context);
|
||||
}
|
||||
}
|
||||
|
||||
static void desktop_view_pin_input_enter(void* context) {
|
||||
DesktopViewPinInput* pin_input = context;
|
||||
xTimerStart(pin_input->timer, portMAX_DELAY);
|
||||
}
|
||||
|
||||
static void desktop_view_pin_input_exit(void* context) {
|
||||
DesktopViewPinInput* pin_input = context;
|
||||
xTimerStop(pin_input->timer, portMAX_DELAY);
|
||||
}
|
||||
|
||||
DesktopViewPinInput* desktop_view_pin_input_alloc(void) {
|
||||
DesktopViewPinInput* pin_input = furi_alloc(sizeof(DesktopViewPinInput));
|
||||
pin_input->view = view_alloc();
|
||||
view_allocate_model(pin_input->view, ViewModelTypeLocking, sizeof(DesktopViewPinInputModel));
|
||||
view_set_context(pin_input->view, pin_input);
|
||||
view_set_draw_callback(pin_input->view, desktop_view_pin_input_draw);
|
||||
view_set_input_callback(pin_input->view, desktop_view_pin_input_input);
|
||||
pin_input->timer = xTimerCreate(
|
||||
NULL,
|
||||
pdMS_TO_TICKS(NO_ACTIVITY_TIMEOUT),
|
||||
pdFALSE,
|
||||
pin_input,
|
||||
desktop_view_pin_input_timer_callback);
|
||||
view_set_enter_callback(pin_input->view, desktop_view_pin_input_enter);
|
||||
view_set_exit_callback(pin_input->view, desktop_view_pin_input_exit);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->pin_x = DEFAULT_PIN_X;
|
||||
model->pin_y = DEFAULT_PIN_Y;
|
||||
model->pin.length = 0;
|
||||
view_commit_model(pin_input->view, false);
|
||||
|
||||
return pin_input;
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_free(DesktopViewPinInput* pin_input) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
xTimerStop(pin_input->timer, portMAX_DELAY);
|
||||
while(xTimerIsTimerActive(pin_input->timer)) {
|
||||
delay(1);
|
||||
}
|
||||
xTimerDelete(pin_input->timer, portMAX_DELAY);
|
||||
|
||||
view_free(pin_input->view);
|
||||
free(pin_input);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_lock_input(DesktopViewPinInput* pin_input) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->locked_input = true;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_unlock_input(DesktopViewPinInput* pin_input) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->locked_input = false;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const PinCode* pin) {
|
||||
furi_assert(pin_input);
|
||||
furi_assert(pin);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->pin = *pin;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_reset_pin(DesktopViewPinInput* pin_input) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->pin.length = 0;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_hide_pin(DesktopViewPinInput* pin_input, bool pin_hidden) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->pin_hidden = pin_hidden;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_label_button(DesktopViewPinInput* pin_input, const char* label) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->button_label = label;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_label_primary(
|
||||
DesktopViewPinInput* pin_input,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
const char* label) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->primary_str = label;
|
||||
model->primary_str_x = x;
|
||||
model->primary_str_y = y;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_label_secondary(
|
||||
DesktopViewPinInput* pin_input,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
const char* label) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->secondary_str = label;
|
||||
model->secondary_str_x = x;
|
||||
model->secondary_str_y = y;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_pin_position(DesktopViewPinInput* pin_input, uint8_t x, uint8_t y) {
|
||||
furi_assert(pin_input);
|
||||
|
||||
DesktopViewPinInputModel* model = view_get_model(pin_input->view);
|
||||
model->pin_x = x;
|
||||
model->pin_y = y;
|
||||
view_commit_model(pin_input->view, true);
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_context(DesktopViewPinInput* pin_input, void* context) {
|
||||
furi_assert(pin_input);
|
||||
pin_input->context = context;
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_timeout_callback(
|
||||
DesktopViewPinInput* pin_input,
|
||||
DesktopViewPinInputCallback callback) {
|
||||
furi_assert(pin_input);
|
||||
pin_input->timeout_callback = callback;
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_back_callback(
|
||||
DesktopViewPinInput* pin_input,
|
||||
DesktopViewPinInputCallback callback) {
|
||||
furi_assert(pin_input);
|
||||
pin_input->back_callback = callback;
|
||||
}
|
||||
|
||||
void desktop_view_pin_input_set_done_callback(
|
||||
DesktopViewPinInput* pin_input,
|
||||
DesktopViewPinInputDoneCallback callback) {
|
||||
furi_assert(pin_input);
|
||||
pin_input->done_callback = callback;
|
||||
}
|
||||
|
||||
View* desktop_view_pin_input_get_view(DesktopViewPinInput* pin_input) {
|
||||
furi_assert(pin_input);
|
||||
return pin_input->view;
|
||||
}
|
||||
40
applications/desktop/views/desktop_view_pin_input.h
Normal file
40
applications/desktop/views/desktop_view_pin_input.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "desktop/desktop_settings/desktop_settings.h"
|
||||
|
||||
typedef void (*DesktopViewPinInputCallback)(void*);
|
||||
typedef void (*DesktopViewPinInputDoneCallback)(const PinCode* pin_code, void*);
|
||||
typedef struct DesktopViewPinInput DesktopViewPinInput;
|
||||
|
||||
DesktopViewPinInput* desktop_view_pin_input_alloc(void);
|
||||
void desktop_view_pin_input_free(DesktopViewPinInput*);
|
||||
|
||||
void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const PinCode* pin);
|
||||
void desktop_view_pin_input_reset_pin(DesktopViewPinInput* pin_input);
|
||||
void desktop_view_pin_input_hide_pin(DesktopViewPinInput* pin_input, bool pin_hidden);
|
||||
void desktop_view_pin_input_set_label_button(DesktopViewPinInput* pin_input, const char* label);
|
||||
void desktop_view_pin_input_set_label_primary(
|
||||
DesktopViewPinInput* pin_input,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
const char* label);
|
||||
void desktop_view_pin_input_set_label_secondary(
|
||||
DesktopViewPinInput* pin_input,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
const char* label);
|
||||
void desktop_view_pin_input_set_pin_position(DesktopViewPinInput* pin_input, uint8_t x, uint8_t y);
|
||||
View* desktop_view_pin_input_get_view(DesktopViewPinInput*);
|
||||
void desktop_view_pin_input_set_done_callback(
|
||||
DesktopViewPinInput* pin_input,
|
||||
DesktopViewPinInputDoneCallback callback);
|
||||
void desktop_view_pin_input_set_back_callback(
|
||||
DesktopViewPinInput* pin_input,
|
||||
DesktopViewPinInputCallback callback);
|
||||
void desktop_view_pin_input_set_timeout_callback(
|
||||
DesktopViewPinInput* pin_input,
|
||||
DesktopViewPinInputCallback callback);
|
||||
void desktop_view_pin_input_set_context(DesktopViewPinInput* pin_input, void* context);
|
||||
void desktop_view_pin_input_lock_input(DesktopViewPinInput* pin_input);
|
||||
void desktop_view_pin_input_unlock_input(DesktopViewPinInput* pin_input);
|
||||
80
applications/desktop/views/desktop_view_pin_setup_done.c
Normal file
80
applications/desktop/views/desktop_view_pin_setup_done.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <toolbox/version.h>
|
||||
#include <assets_icons.h>
|
||||
#include <dolphin/helpers/dolphin_state.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "../desktop_i.h"
|
||||
#include "desktop_view_pin_setup_done.h"
|
||||
|
||||
struct DesktopViewPinSetupDone {
|
||||
View* view;
|
||||
DesktopViewPinSetupDoneDoneCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
static void desktop_view_pin_done_draw(Canvas* canvas, void* model) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(model);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 64, 0, AlignCenter, AlignTop, "Prepare to use\narrows as\nPIN symbols");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text(canvas, 58, 24, "Prepare to use\narrows as\nPIN symbols");
|
||||
|
||||
canvas_draw_icon(canvas, 16, 18, &I_Pin_attention_dpad_29x29);
|
||||
elements_button_right(canvas, "Next");
|
||||
}
|
||||
|
||||
static bool desktop_view_pin_done_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
DesktopViewPinSetupDone* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if((event->key == InputKeyRight) && (event->type == InputTypeShort)) {
|
||||
instance->callback(instance->context);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_view_pin_done_set_callback(
|
||||
DesktopViewPinSetupDone* instance,
|
||||
DesktopViewPinSetupDoneDoneCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
DesktopViewPinSetupDone* desktop_view_pin_done_alloc() {
|
||||
DesktopViewPinSetupDone* view = furi_alloc(sizeof(DesktopViewPinSetupDone));
|
||||
view->view = view_alloc();
|
||||
view_allocate_model(view->view, ViewModelTypeLockFree, 1);
|
||||
view_set_context(view->view, view);
|
||||
view_set_draw_callback(view->view, desktop_view_pin_done_draw);
|
||||
view_set_input_callback(view->view, desktop_view_pin_done_input);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void desktop_view_pin_done_free(DesktopViewPinSetupDone* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* desktop_view_pin_done_get_view(DesktopViewPinSetupDone* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->view;
|
||||
}
|
||||
15
applications/desktop/views/desktop_view_pin_setup_done.h
Normal file
15
applications/desktop/views/desktop_view_pin_setup_done.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct DesktopViewPinSetupDone DesktopViewPinSetupDone;
|
||||
|
||||
typedef void (*DesktopViewPinSetupDoneDoneCallback)(void*);
|
||||
|
||||
void desktop_view_pin_done_set_callback(
|
||||
DesktopViewPinSetupDone* instance,
|
||||
DesktopViewPinSetupDoneDoneCallback callback,
|
||||
void* context);
|
||||
DesktopViewPinSetupDone* desktop_view_pin_done_alloc();
|
||||
void desktop_view_pin_done_free(DesktopViewPinSetupDone* instance);
|
||||
View* desktop_view_pin_done_get_view(DesktopViewPinSetupDone* instance);
|
||||
109
applications/desktop/views/desktop_view_pin_timeout.c
Normal file
109
applications/desktop/views/desktop_view_pin_timeout.c
Normal file
@ -0,0 +1,109 @@
|
||||
|
||||
#include <furi.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <portmacro.h>
|
||||
#include <projdefs.h>
|
||||
#include <input/input.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <gui/view.h>
|
||||
|
||||
#include "desktop_view_pin_timeout.h"
|
||||
|
||||
struct DesktopViewPinTimeout {
|
||||
View* view;
|
||||
TimerHandle_t timer;
|
||||
DesktopViewPinTimeoutDoneCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t time_left;
|
||||
} DesktopViewPinTimeoutModel;
|
||||
|
||||
void desktop_view_pin_timeout_set_callback(
|
||||
DesktopViewPinTimeout* instance,
|
||||
DesktopViewPinTimeoutDoneCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
static void desktop_view_pin_timeout_timer_callback(TimerHandle_t timer) {
|
||||
DesktopViewPinTimeout* instance = pvTimerGetTimerID(timer);
|
||||
bool stop = false;
|
||||
|
||||
DesktopViewPinTimeoutModel* model = view_get_model(instance->view);
|
||||
if(model->time_left > 0) {
|
||||
--model->time_left;
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
view_commit_model(instance->view, true);
|
||||
|
||||
if(stop) {
|
||||
xTimerStop(instance->timer, portMAX_DELAY);
|
||||
instance->callback(instance->context);
|
||||
}
|
||||
}
|
||||
|
||||
static bool desktop_view_pin_timeout_input(InputEvent* event, void* context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void desktop_view_pin_timeout_draw(Canvas* canvas, void* _model) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(_model);
|
||||
|
||||
DesktopViewPinTimeoutModel* model = _model;
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 36, 31, "Wrong PIN!");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
char str[30] = {0};
|
||||
snprintf(str, sizeof(str), "Timeout: %lds", model->time_left);
|
||||
canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignCenter, str);
|
||||
}
|
||||
|
||||
void desktop_view_pin_timeout_free(DesktopViewPinTimeout* instance) {
|
||||
view_free(instance->view);
|
||||
xTimerDelete(instance->timer, portMAX_DELAY);
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
DesktopViewPinTimeout* desktop_view_pin_timeout_alloc(void) {
|
||||
DesktopViewPinTimeout* instance = furi_alloc(sizeof(DesktopViewPinTimeout));
|
||||
instance->timer = xTimerCreate(
|
||||
NULL, pdMS_TO_TICKS(1000), pdTRUE, instance, desktop_view_pin_timeout_timer_callback);
|
||||
|
||||
instance->view = view_alloc();
|
||||
view_allocate_model(instance->view, ViewModelTypeLockFree, sizeof(DesktopViewPinTimeoutModel));
|
||||
|
||||
view_set_context(instance->view, instance);
|
||||
view_set_draw_callback(instance->view, desktop_view_pin_timeout_draw);
|
||||
view_set_input_callback(instance->view, desktop_view_pin_timeout_input);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void desktop_view_pin_timeout_start(DesktopViewPinTimeout* instance, uint32_t time_left) {
|
||||
furi_assert(instance);
|
||||
|
||||
DesktopViewPinTimeoutModel* model = view_get_model(instance->view);
|
||||
// no race - always called when timer is stopped
|
||||
model->time_left = time_left;
|
||||
view_commit_model(instance->view, true);
|
||||
|
||||
xTimerStart(instance->timer, portMAX_DELAY);
|
||||
}
|
||||
|
||||
View* desktop_view_pin_timeout_get_view(DesktopViewPinTimeout* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->view;
|
||||
}
|
||||
16
applications/desktop/views/desktop_view_pin_timeout.h
Normal file
16
applications/desktop/views/desktop_view_pin_timeout.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef void (*DesktopViewPinTimeoutDoneCallback)(void*);
|
||||
typedef struct DesktopViewPinTimeout DesktopViewPinTimeout;
|
||||
|
||||
void desktop_view_pin_timeout_set_callback(
|
||||
DesktopViewPinTimeout* instance,
|
||||
DesktopViewPinTimeoutDoneCallback callback,
|
||||
void* context);
|
||||
DesktopViewPinTimeout* desktop_view_pin_timeout_alloc(void);
|
||||
void desktop_view_pin_timeout_free(DesktopViewPinTimeout*);
|
||||
void desktop_view_pin_timeout_start(DesktopViewPinTimeout* instance, uint32_t time_left);
|
||||
View* desktop_view_pin_timeout_get_view(DesktopViewPinTimeout* instance);
|
||||
@ -80,15 +80,11 @@ Dolphin* dolphin_alloc() {
|
||||
dolphin->event_queue = osMessageQueueNew(8, sizeof(DolphinEvent), NULL);
|
||||
dolphin->pubsub = furi_pubsub_alloc();
|
||||
dolphin->butthurt_timer = xTimerCreate(
|
||||
"Butthurt timer", HOURS_IN_TICKS(2 * 24), pdTRUE, dolphin, dolphin_butthurt_timer_callback);
|
||||
NULL, HOURS_IN_TICKS(2 * 24), pdTRUE, dolphin, dolphin_butthurt_timer_callback);
|
||||
dolphin->flush_timer =
|
||||
xTimerCreate("Flush timer", 30 * 1000, pdFALSE, dolphin, dolphin_flush_timer_callback);
|
||||
xTimerCreate(NULL, 30 * 1000, pdFALSE, dolphin, dolphin_flush_timer_callback);
|
||||
dolphin->clear_limits_timer = xTimerCreate(
|
||||
"Clear limits timer",
|
||||
HOURS_IN_TICKS(24),
|
||||
pdTRUE,
|
||||
dolphin,
|
||||
dolphin_clear_limits_timer_callback);
|
||||
NULL, HOURS_IN_TICKS(24), pdTRUE, dolphin, dolphin_clear_limits_timer_callback);
|
||||
|
||||
return dolphin;
|
||||
}
|
||||
|
||||
@ -12,19 +12,20 @@
|
||||
#define MOODS_TOTAL 3
|
||||
#define BUTTHURT_MAX 3
|
||||
|
||||
static const Icon* portrait_happy[BUTTHURT_MAX] = {
|
||||
static const Icon* const portrait_happy[BUTTHURT_MAX] = {
|
||||
&I_passport_happy1_46x49,
|
||||
&I_passport_happy2_46x49,
|
||||
&I_passport_happy3_46x49};
|
||||
static const Icon* portrait_ok[BUTTHURT_MAX] = {
|
||||
static const Icon* const portrait_ok[BUTTHURT_MAX] = {
|
||||
&I_passport_okay1_46x49,
|
||||
&I_passport_okay2_46x49,
|
||||
&I_passport_okay3_46x49};
|
||||
static const Icon* portrait_bad[BUTTHURT_MAX] = {
|
||||
static const Icon* const portrait_bad[BUTTHURT_MAX] = {
|
||||
&I_passport_bad1_46x49,
|
||||
&I_passport_bad2_46x49,
|
||||
&I_passport_bad3_46x49};
|
||||
static const Icon** portraits[MOODS_TOTAL] = {portrait_happy, portrait_ok, portrait_bad};
|
||||
|
||||
static const Icon* const* portraits[MOODS_TOTAL] = {portrait_happy, portrait_ok, portrait_bad};
|
||||
|
||||
static void input_callback(InputEvent* input, void* ctx) {
|
||||
osSemaphoreId_t semaphore = ctx;
|
||||
|
||||
@ -151,6 +151,6 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa
|
||||
model->rx_active = (model->rx_cnt != st->rx_cnt);
|
||||
model->tx_cnt = st->tx_cnt;
|
||||
model->rx_cnt = st->rx_cnt;
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
#include "elements.h"
|
||||
#include <assets_icons.h>
|
||||
#include "furi_hal_resources.h"
|
||||
#include <furi_hal.h>
|
||||
#include "gui/canvas.h"
|
||||
|
||||
#include <gui/icon_i.h>
|
||||
@ -337,6 +340,47 @@ void elements_slightly_rounded_box(
|
||||
canvas_draw_rbox(canvas, x, y, width, height, 1);
|
||||
}
|
||||
|
||||
void elements_bold_rounded_frame(
|
||||
Canvas* canvas,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
uint8_t width,
|
||||
uint8_t height) {
|
||||
furi_assert(canvas);
|
||||
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, x + 2, y + 2, width - 3, height - 3);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
canvas_draw_line(canvas, x + 3, y, x + width - 3, y);
|
||||
canvas_draw_line(canvas, x + 2, y + 1, x + width - 2, y + 1);
|
||||
|
||||
canvas_draw_line(canvas, x, y + 3, x, y + height - 3);
|
||||
canvas_draw_line(canvas, x + 1, y + 2, x + 1, y + height - 2);
|
||||
|
||||
canvas_draw_line(canvas, x + width, y + 3, x + width, y + height - 3);
|
||||
canvas_draw_line(canvas, x + width - 1, y + 2, x + width - 1, y + height - 2);
|
||||
|
||||
canvas_draw_line(canvas, x + 3, y + height, x + width - 3, y + height);
|
||||
canvas_draw_line(canvas, x + 2, y + height - 1, x + width - 2, y + height - 1);
|
||||
|
||||
canvas_draw_dot(canvas, x + 2, y + 2);
|
||||
canvas_draw_dot(canvas, x + 3, y + 2);
|
||||
canvas_draw_dot(canvas, x + 2, y + 3);
|
||||
|
||||
canvas_draw_dot(canvas, x + width - 2, y + 2);
|
||||
canvas_draw_dot(canvas, x + width - 3, y + 2);
|
||||
canvas_draw_dot(canvas, x + width - 2, y + 3);
|
||||
|
||||
canvas_draw_dot(canvas, x + 2, y + height - 2);
|
||||
canvas_draw_dot(canvas, x + 3, y + height - 2);
|
||||
canvas_draw_dot(canvas, x + 2, y + height - 3);
|
||||
|
||||
canvas_draw_dot(canvas, x + width - 2, y + height - 2);
|
||||
canvas_draw_dot(canvas, x + width - 3, y + height - 2);
|
||||
canvas_draw_dot(canvas, x + width - 2, y + height - 3);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -150,6 +150,19 @@ void elements_slightly_rounded_box(
|
||||
uint8_t width,
|
||||
uint8_t height);
|
||||
|
||||
/** Draw bold rounded frame
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
* @param x, y top left corner coordinates
|
||||
* @param width, height size of frame
|
||||
*/
|
||||
void elements_bold_rounded_frame(
|
||||
Canvas* canvas,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
uint8_t width,
|
||||
uint8_t height);
|
||||
|
||||
/** Draw bubble frame for text
|
||||
*
|
||||
* @param canvas Canvas instance
|
||||
|
||||
@ -11,5 +11,5 @@ struct Icon {
|
||||
const uint8_t height;
|
||||
const uint8_t frame_count;
|
||||
const uint8_t frame_rate;
|
||||
const uint8_t** frames;
|
||||
const uint8_t* const* frames;
|
||||
};
|
||||
|
||||
@ -1,478 +0,0 @@
|
||||
#include "code_input.h"
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
|
||||
#define MAX_CODE_LEN 10
|
||||
|
||||
struct CodeInput {
|
||||
View* view;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CodeInputStateVerify,
|
||||
CodeInputStateUpdate,
|
||||
CodeInputStateTotal,
|
||||
} CodeInputStateEnum;
|
||||
|
||||
typedef enum {
|
||||
CodeInputFirst,
|
||||
CodeInputSecond,
|
||||
CodeInputTotal,
|
||||
} CodeInputsEnum;
|
||||
|
||||
typedef struct {
|
||||
uint8_t state;
|
||||
uint8_t current;
|
||||
bool ext_update;
|
||||
|
||||
uint8_t input_length[CodeInputTotal];
|
||||
uint8_t local_buffer[CodeInputTotal][MAX_CODE_LEN];
|
||||
|
||||
CodeInputOkCallback ok_callback;
|
||||
CodeInputFailCallback fail_callback;
|
||||
void* callback_context;
|
||||
|
||||
const char* header;
|
||||
|
||||
uint8_t* ext_buffer;
|
||||
uint8_t* ext_buffer_length;
|
||||
} CodeInputModel;
|
||||
|
||||
static const Icon* keys_assets[] = {
|
||||
[InputKeyUp] = &I_ButtonUp_7x4,
|
||||
[InputKeyDown] = &I_ButtonDown_7x4,
|
||||
[InputKeyRight] = &I_ButtonRight_4x7,
|
||||
[InputKeyLeft] = &I_ButtonLeft_4x7,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare buffers
|
||||
*
|
||||
* @param in Input buffer pointer
|
||||
* @param len_in Input array length
|
||||
* @param src Source buffer pointer
|
||||
* @param len_src Source array length
|
||||
*/
|
||||
|
||||
bool code_input_compare(uint8_t* in, size_t len_in, uint8_t* src, size_t len_src) {
|
||||
bool result = false;
|
||||
do {
|
||||
result = (len_in && len_src);
|
||||
if(!result) {
|
||||
break;
|
||||
}
|
||||
result = (len_in == len_src);
|
||||
if(!result) {
|
||||
break;
|
||||
}
|
||||
for(size_t i = 0; i < len_in; i++) {
|
||||
result = (in[i] == src[i]);
|
||||
if(!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare local buffers
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
static bool code_input_compare_local(CodeInputModel* model) {
|
||||
uint8_t* source = model->local_buffer[CodeInputFirst];
|
||||
size_t source_length = model->input_length[CodeInputFirst];
|
||||
|
||||
uint8_t* input = model->local_buffer[CodeInputSecond];
|
||||
size_t input_length = model->input_length[CodeInputSecond];
|
||||
|
||||
return code_input_compare(input, input_length, source, source_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare ext with local
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
static bool code_input_compare_ext(CodeInputModel* model) {
|
||||
uint8_t* input = model->local_buffer[CodeInputFirst];
|
||||
size_t input_length = model->input_length[CodeInputFirst];
|
||||
|
||||
uint8_t* source = model->ext_buffer;
|
||||
size_t source_length = *model->ext_buffer_length;
|
||||
|
||||
return code_input_compare(input, input_length, source, source_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set ext buffer
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
static void code_input_set_ext(CodeInputModel* model) {
|
||||
*model->ext_buffer_length = model->input_length[CodeInputFirst];
|
||||
for(size_t i = 0; i <= model->input_length[CodeInputFirst]; i++) {
|
||||
model->ext_buffer[i] = model->local_buffer[CodeInputFirst][i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Draw input sequence
|
||||
*
|
||||
* @param canvas
|
||||
* @param buffer
|
||||
* @param length
|
||||
* @param x
|
||||
* @param y
|
||||
* @param active
|
||||
*/
|
||||
static void code_input_draw_sequence(
|
||||
Canvas* canvas,
|
||||
uint8_t* buffer,
|
||||
uint8_t length,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
bool active) {
|
||||
uint8_t pos_x = x + 6;
|
||||
uint8_t pos_y = y + 3;
|
||||
|
||||
if(active) canvas_draw_icon(canvas, x - 4, y + 5, &I_ButtonRightSmall_3x5);
|
||||
|
||||
elements_slightly_rounded_frame(canvas, x, y, 116, 15);
|
||||
|
||||
for(size_t i = 0; i < length; i++) {
|
||||
// maybe symmetrical assets? :-/
|
||||
uint8_t offset_y = buffer[i] < 2 ? 2 + (buffer[i] * 2) : 1;
|
||||
canvas_draw_icon(canvas, pos_x, pos_y + offset_y, keys_assets[buffer[i]]);
|
||||
pos_x += buffer[i] > 1 ? 9 : 11;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset input count
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
static void code_input_reset_count(CodeInputModel* model) {
|
||||
model->input_length[model->current] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call input callback
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
static void code_input_call_ok_callback(CodeInputModel* model) {
|
||||
if(model->ok_callback != NULL) {
|
||||
model->ok_callback(model->callback_context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call changed callback
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
static void code_input_call_fail_callback(CodeInputModel* model) {
|
||||
if(model->fail_callback != NULL) {
|
||||
model->fail_callback(model->callback_context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle Back button
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
static bool code_input_handle_back(CodeInputModel* model) {
|
||||
if(model->current && !model->input_length[model->current]) {
|
||||
--model->current;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(model->input_length[model->current]) {
|
||||
code_input_reset_count(model);
|
||||
return true;
|
||||
}
|
||||
|
||||
code_input_call_fail_callback(model);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle OK button
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
static void code_input_handle_ok(CodeInputModel* model) {
|
||||
switch(model->state) {
|
||||
case CodeInputStateVerify:
|
||||
|
||||
if(code_input_compare_ext(model)) {
|
||||
if(model->ext_update) {
|
||||
model->state = CodeInputStateUpdate;
|
||||
} else {
|
||||
code_input_call_ok_callback(model);
|
||||
}
|
||||
}
|
||||
code_input_reset_count(model);
|
||||
break;
|
||||
|
||||
case CodeInputStateUpdate:
|
||||
|
||||
if(!model->current && model->input_length[model->current]) {
|
||||
model->current++;
|
||||
} else {
|
||||
if(code_input_compare_local(model)) {
|
||||
if(model->ext_update) {
|
||||
code_input_set_ext(model);
|
||||
}
|
||||
code_input_call_ok_callback(model);
|
||||
} else {
|
||||
code_input_reset_count(model);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle input
|
||||
*
|
||||
* @param model
|
||||
* @param key
|
||||
*/
|
||||
|
||||
size_t code_input_push(uint8_t* buffer, size_t length, InputKey key) {
|
||||
buffer[length] = key;
|
||||
length = CLAMP(length + 1, MAX_CODE_LEN, 0);
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle D-pad keys
|
||||
*
|
||||
* @param model
|
||||
* @param key
|
||||
*/
|
||||
static void code_input_handle_dpad(CodeInputModel* model, InputKey key) {
|
||||
uint8_t at = model->current;
|
||||
size_t new_length = code_input_push(model->local_buffer[at], model->input_length[at], key);
|
||||
model->input_length[at] = new_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Draw callback
|
||||
*
|
||||
* @param canvas
|
||||
* @param _model
|
||||
*/
|
||||
static void code_input_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
CodeInputModel* model = _model;
|
||||
uint8_t y_offset = 0;
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(model->header && strlen(model->header)) {
|
||||
canvas_draw_str(canvas, 2, 9, model->header);
|
||||
} else {
|
||||
y_offset = 4;
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
switch(model->state) {
|
||||
case CodeInputStateVerify:
|
||||
code_input_draw_sequence(
|
||||
canvas,
|
||||
model->local_buffer[CodeInputFirst],
|
||||
model->input_length[CodeInputFirst],
|
||||
6,
|
||||
30 + y_offset,
|
||||
true);
|
||||
break;
|
||||
case CodeInputStateUpdate:
|
||||
code_input_draw_sequence(
|
||||
canvas,
|
||||
model->local_buffer[CodeInputFirst],
|
||||
model->input_length[CodeInputFirst],
|
||||
6,
|
||||
14 + y_offset,
|
||||
!model->current);
|
||||
code_input_draw_sequence(
|
||||
canvas,
|
||||
model->local_buffer[CodeInputSecond],
|
||||
model->input_length[CodeInputSecond],
|
||||
6,
|
||||
44 + y_offset,
|
||||
model->current);
|
||||
|
||||
if(model->current) canvas_draw_str(canvas, 2, 39 + y_offset, "Repeat code");
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Input callback
|
||||
*
|
||||
* @param event
|
||||
* @param context
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
static bool code_input_view_input_callback(InputEvent* event, void* context) {
|
||||
CodeInput* code_input = context;
|
||||
furi_assert(code_input);
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
|
||||
switch(event->key) {
|
||||
case InputKeyBack:
|
||||
with_view_model(
|
||||
code_input->view, (CodeInputModel * model) {
|
||||
consumed = code_input_handle_back(model);
|
||||
return true;
|
||||
});
|
||||
break;
|
||||
|
||||
case InputKeyOk:
|
||||
with_view_model(
|
||||
code_input->view, (CodeInputModel * model) {
|
||||
code_input_handle_ok(model);
|
||||
return true;
|
||||
});
|
||||
consumed = true;
|
||||
break;
|
||||
default:
|
||||
|
||||
with_view_model(
|
||||
code_input->view, (CodeInputModel * model) {
|
||||
code_input_handle_dpad(model, event->key);
|
||||
return true;
|
||||
});
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset all input-related data in model
|
||||
*
|
||||
* @param model CodeInputModel
|
||||
*/
|
||||
static void code_input_reset_model_input_data(CodeInputModel* model) {
|
||||
model->current = 0;
|
||||
model->input_length[CodeInputFirst] = 0;
|
||||
model->input_length[CodeInputSecond] = 0;
|
||||
model->ext_buffer = NULL;
|
||||
model->ext_update = false;
|
||||
model->state = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize code input. This code input is used to enter codes.
|
||||
*
|
||||
* @return CodeInput instance pointer
|
||||
*/
|
||||
CodeInput* code_input_alloc() {
|
||||
CodeInput* code_input = furi_alloc(sizeof(CodeInput));
|
||||
code_input->view = view_alloc();
|
||||
view_set_context(code_input->view, code_input);
|
||||
view_allocate_model(code_input->view, ViewModelTypeLocking, sizeof(CodeInputModel));
|
||||
view_set_draw_callback(code_input->view, code_input_view_draw_callback);
|
||||
view_set_input_callback(code_input->view, code_input_view_input_callback);
|
||||
|
||||
with_view_model(
|
||||
code_input->view, (CodeInputModel * model) {
|
||||
model->header = "";
|
||||
model->ok_callback = NULL;
|
||||
model->fail_callback = NULL;
|
||||
model->callback_context = NULL;
|
||||
code_input_reset_model_input_data(model);
|
||||
return true;
|
||||
});
|
||||
|
||||
return code_input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deinitialize and free code input
|
||||
*
|
||||
* @param code_input Code input instance
|
||||
*/
|
||||
void code_input_free(CodeInput* code_input) {
|
||||
furi_assert(code_input);
|
||||
view_free(code_input->view);
|
||||
free(code_input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get code input view
|
||||
*
|
||||
* @param code_input code input instance
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* code_input_get_view(CodeInput* code_input) {
|
||||
furi_assert(code_input);
|
||||
return code_input->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set code input callbacks
|
||||
*
|
||||
* @param code_input code input instance
|
||||
* @param ok_callback input callback fn
|
||||
* @param fail_callback code match callback fn
|
||||
* @param callback_context callback context
|
||||
* @param buffer buffer
|
||||
* @param buffer_length ptr to buffer length uint
|
||||
* @param ext_update true to update buffer
|
||||
*/
|
||||
void code_input_set_result_callback(
|
||||
CodeInput* code_input,
|
||||
CodeInputOkCallback ok_callback,
|
||||
CodeInputFailCallback fail_callback,
|
||||
void* callback_context,
|
||||
uint8_t* buffer,
|
||||
uint8_t* buffer_length,
|
||||
bool ext_update) {
|
||||
with_view_model(
|
||||
code_input->view, (CodeInputModel * model) {
|
||||
code_input_reset_model_input_data(model);
|
||||
model->ok_callback = ok_callback;
|
||||
model->fail_callback = fail_callback;
|
||||
model->callback_context = callback_context;
|
||||
|
||||
model->ext_buffer = buffer;
|
||||
model->ext_buffer_length = buffer_length;
|
||||
model->state = (*buffer_length == 0) ? 1 : 0;
|
||||
model->ext_update = ext_update;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set code input header text
|
||||
*
|
||||
* @param code_input code input instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void code_input_set_header_text(CodeInput* code_input, const char* text) {
|
||||
with_view_model(
|
||||
code_input->view, (CodeInputModel * model) {
|
||||
model->header = text;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -1,91 +0,0 @@
|
||||
/**
|
||||
* @file code_input.h
|
||||
* GUI: CodeInput keyboard view module API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Code input anonymous structure */
|
||||
typedef struct CodeInput CodeInput;
|
||||
|
||||
/** callback that is executed when entered code matches ext buffer */
|
||||
typedef void (*CodeInputOkCallback)(void* context);
|
||||
|
||||
/** callback that is executed when entered code does not matches ext buffer */
|
||||
typedef void (*CodeInputFailCallback)(void* context);
|
||||
|
||||
/** Allocate and initialize code input. This code input is used to enter codes.
|
||||
*
|
||||
* @return CodeInput instance pointer
|
||||
*/
|
||||
CodeInput* code_input_alloc();
|
||||
|
||||
/** Deinitialize and free code input
|
||||
*
|
||||
* @param code_input Code input instance
|
||||
*/
|
||||
void code_input_free(CodeInput* code_input);
|
||||
|
||||
/** Get code input view
|
||||
*
|
||||
* @param code_input code input instance
|
||||
*
|
||||
* @return View instance that can be used for embedding
|
||||
*/
|
||||
View* code_input_get_view(CodeInput* code_input);
|
||||
|
||||
/** Set code input result callback
|
||||
*
|
||||
* @param code_input code input instance
|
||||
* @param ok_callback ok callback fn
|
||||
* @param fail_callback fail callback fn
|
||||
* @param callback_context callback context
|
||||
* @param buffer buffer to use
|
||||
* @param buffer_length buffer length
|
||||
* @param update set true to update buffer
|
||||
*/
|
||||
void code_input_set_result_callback(
|
||||
CodeInput* code_input,
|
||||
CodeInputOkCallback ok_callback,
|
||||
CodeInputFailCallback fail_callback,
|
||||
void* callback_context,
|
||||
uint8_t* buffer,
|
||||
uint8_t* buffer_length,
|
||||
bool update);
|
||||
|
||||
/** Set code input header text
|
||||
*
|
||||
* @param code_input code input instance
|
||||
* @param text text to be shown
|
||||
*/
|
||||
void code_input_set_header_text(CodeInput* code_input, const char* text);
|
||||
|
||||
/** Compare two buffers
|
||||
*
|
||||
* @param in buffer to compare to source
|
||||
* @param len_in length of input buffer
|
||||
* @param src source buffer
|
||||
* @param len_src length of insourceput buffer
|
||||
* @return true if buffers match
|
||||
*/
|
||||
|
||||
bool code_input_compare(uint8_t* in, size_t len_in, uint8_t* src, size_t len_src);
|
||||
|
||||
/** Push input into the end of array
|
||||
*
|
||||
* @param buffer buffer
|
||||
* @param length length of buffer
|
||||
* @param key input key
|
||||
* @return new length of input buffer
|
||||
*/
|
||||
size_t code_input_push(uint8_t* buffer, size_t length, InputKey key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -253,27 +253,26 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
|
||||
}
|
||||
|
||||
// Deliver event
|
||||
if(view_dispatcher->ongoing_input_view == view_dispatcher->current_view) {
|
||||
bool is_consumed = false;
|
||||
if(view_dispatcher->current_view) {
|
||||
is_consumed = view_input(view_dispatcher->current_view, event);
|
||||
}
|
||||
if(!is_consumed && (event->type == InputTypeShort || event->type == InputTypeLong)) {
|
||||
// TODO remove view navigation handlers
|
||||
uint32_t view_id = VIEW_IGNORE;
|
||||
if(event->key == InputKeyBack) {
|
||||
view_id = view_previous(view_dispatcher->current_view);
|
||||
if((view_id == VIEW_IGNORE) && (view_dispatcher->navigation_event_callback)) {
|
||||
is_consumed =
|
||||
view_dispatcher->navigation_event_callback(view_dispatcher->event_context);
|
||||
if(!is_consumed) {
|
||||
view_dispatcher_stop(view_dispatcher);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!is_consumed) {
|
||||
if(view_dispatcher->current_view &&
|
||||
view_dispatcher->ongoing_input_view == view_dispatcher->current_view) {
|
||||
// Dispatch input to current view
|
||||
bool is_consumed = view_input(view_dispatcher->current_view, event);
|
||||
|
||||
// Navigate if input is not consumed
|
||||
if(!is_consumed && (event->key == InputKeyBack) &&
|
||||
(event->type == InputTypeShort || event->type == InputTypeLong)) {
|
||||
// Navigate to previous
|
||||
uint32_t view_id = view_previous(view_dispatcher->current_view);
|
||||
if(view_id != VIEW_IGNORE) {
|
||||
// Switch to returned view
|
||||
view_dispatcher_switch_to_view(view_dispatcher, view_id);
|
||||
} else if(view_dispatcher->navigation_event_callback) {
|
||||
// Dispatch navigation event
|
||||
if(!view_dispatcher->navigation_event_callback(view_dispatcher->event_context)) {
|
||||
// TODO: should we allow view_dispatcher to stop without navigation_event_callback?
|
||||
view_dispatcher_stop(view_dispatcher);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) {
|
||||
|
||||
@ -59,9 +59,8 @@ KeyReader::~KeyReader() {
|
||||
bool KeyReader::read_key(iButtonKeyType* key_type, uint8_t* data, uint8_t data_size) {
|
||||
bool readed = false;
|
||||
|
||||
switch(read_mode) {
|
||||
case ReadMode::DALLAS:
|
||||
__disable_irq();
|
||||
if(read_mode == ReadMode::DALLAS) {
|
||||
FURI_CRITICAL_ENTER();
|
||||
if(onewire_master->search(data)) {
|
||||
onewire_master->reset_search();
|
||||
readed = true;
|
||||
@ -69,9 +68,8 @@ bool KeyReader::read_key(iButtonKeyType* key_type, uint8_t* data, uint8_t data_s
|
||||
} else {
|
||||
onewire_master->reset_search();
|
||||
}
|
||||
__enable_irq();
|
||||
break;
|
||||
case ReadMode::CYFRAL_METAKOM:
|
||||
FURI_CRITICAL_EXIT();
|
||||
} else if(read_mode == ReadMode::CYFRAL_METAKOM) {
|
||||
if(cyfral_decoder.read(data, 2)) {
|
||||
readed = true;
|
||||
*key_type = iButtonKeyType::KeyCyfral;
|
||||
@ -79,7 +77,6 @@ bool KeyReader::read_key(iButtonKeyType* key_type, uint8_t* data, uint8_t data_s
|
||||
readed = true;
|
||||
*key_type = iButtonKeyType::KeyMetakom;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return readed;
|
||||
@ -88,10 +85,10 @@ bool KeyReader::read_key(iButtonKeyType* key_type, uint8_t* data, uint8_t data_s
|
||||
bool KeyReader::verify_key(iButtonKeyType key_type, const uint8_t* const data, uint8_t data_size) {
|
||||
bool result = true;
|
||||
|
||||
switch(key_type) {
|
||||
case iButtonKeyType::KeyDallas:
|
||||
if(key_type == iButtonKeyType::KeyDallas) {
|
||||
switch_to(ReadMode::DALLAS);
|
||||
__disable_irq();
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
if(onewire_master->reset()) {
|
||||
onewire_master->write(DS1990::CMD_READ_ROM);
|
||||
for(uint8_t i = 0; i < data_size; i++) {
|
||||
@ -101,14 +98,11 @@ bool KeyReader::verify_key(iButtonKeyType key_type, const uint8_t* const data, u
|
||||
}
|
||||
} else {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
__enable_irq();
|
||||
break;
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
default:
|
||||
} else {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@ -74,7 +74,7 @@ bool KeyWriter::compare_key_ds1990(iButtonKey* key) {
|
||||
bool result = false;
|
||||
|
||||
if(key->get_key_type() == iButtonKeyType::KeyDallas) {
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
bool presence = onewire_master->reset();
|
||||
|
||||
if(presence) {
|
||||
@ -89,7 +89,7 @@ bool KeyWriter::compare_key_ds1990(iButtonKey* key) {
|
||||
}
|
||||
}
|
||||
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -99,7 +99,7 @@ bool KeyWriter::write_1990_1(iButtonKey* key) {
|
||||
bool result = false;
|
||||
|
||||
if(key->get_key_type() == iButtonKeyType::KeyDallas) {
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
// unlock
|
||||
onewire_master->reset();
|
||||
@ -120,7 +120,7 @@ bool KeyWriter::write_1990_1(iButtonKey* key) {
|
||||
onewire_master->write(RW1990_1::CMD_WRITE_RECORD_FLAG);
|
||||
onewire_write_one_bit(1);
|
||||
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
if(compare_key_ds1990(key)) {
|
||||
result = true;
|
||||
@ -134,7 +134,7 @@ bool KeyWriter::write_1990_2(iButtonKey* key) {
|
||||
bool result = false;
|
||||
|
||||
if(key->get_key_type() == iButtonKeyType::KeyDallas) {
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
// unlock
|
||||
onewire_master->reset();
|
||||
@ -154,7 +154,7 @@ bool KeyWriter::write_1990_2(iButtonKey* key) {
|
||||
onewire_master->write(RW1990_2::CMD_WRITE_RECORD_FLAG);
|
||||
onewire_write_one_bit(0);
|
||||
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
if(compare_key_ds1990(key)) {
|
||||
result = true;
|
||||
@ -169,7 +169,7 @@ bool KeyWriter::write_TM2004(iButtonKey* key) {
|
||||
bool result = true;
|
||||
|
||||
if(key->get_key_type() == iButtonKeyType::KeyDallas) {
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
// write rom, addr is 0x0000
|
||||
onewire_master->reset();
|
||||
@ -204,7 +204,7 @@ bool KeyWriter::write_TM2004(iButtonKey* key) {
|
||||
|
||||
onewire_master->reset();
|
||||
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
@ -216,7 +216,7 @@ bool KeyWriter::write_TM01(iButtonKey* key) {
|
||||
/*bool result = true;
|
||||
|
||||
// TODO test and encoding
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
// unlock
|
||||
onewire_master->reset();
|
||||
@ -240,13 +240,13 @@ bool KeyWriter::write_TM01(iButtonKey* key) {
|
||||
onewire_master->write(TM01::CMD_WRITE_RECORD_FLAG);
|
||||
onewire_write_one_bit(0, 10000);
|
||||
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
if(!compare_key_ds1990(key)) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
if(key->get_key_type() == iButtonKeyType::KeyMetakom ||
|
||||
key->get_key_type() == iButtonKeyType::KeyCyfral) {
|
||||
@ -258,7 +258,7 @@ bool KeyWriter::write_TM01(iButtonKey* key) {
|
||||
onewire_write_one_bit(1);
|
||||
}
|
||||
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
return result;*/
|
||||
return false;
|
||||
@ -275,4 +275,4 @@ void KeyWriter::write_byte_ds1990(uint8_t data) {
|
||||
delay_us(5000);
|
||||
data = data >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,12 +121,12 @@ void RfidWriter::write_em(const uint8_t em_data[5]) {
|
||||
em_card.encode(em_data, 5, reinterpret_cast<uint8_t*>(&em_encoded_data), sizeof(uint64_t));
|
||||
const uint32_t em_config_block_data = 0b00000000000101001000000001000000;
|
||||
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
write_block(0, 0, false, em_config_block_data);
|
||||
write_block(0, 1, false, em_encoded_data);
|
||||
write_block(0, 2, false, em_encoded_data >> 32);
|
||||
write_reset();
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
void RfidWriter::write_hid(const uint8_t hid_data[3]) {
|
||||
@ -136,13 +136,13 @@ void RfidWriter::write_hid(const uint8_t hid_data[3]) {
|
||||
|
||||
const uint32_t hid_config_block_data = 0b00000000000100000111000001100000;
|
||||
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
write_block(0, 0, false, hid_config_block_data);
|
||||
write_block(0, 1, false, card_data[0]);
|
||||
write_block(0, 2, false, card_data[1]);
|
||||
write_block(0, 3, false, card_data[2]);
|
||||
write_reset();
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
void RfidWriter::write_indala(const uint8_t indala_data[3]) {
|
||||
@ -153,10 +153,10 @@ void RfidWriter::write_indala(const uint8_t indala_data[3]) {
|
||||
|
||||
const uint32_t indala_config_block_data = 0b00000000000010000001000001000000;
|
||||
|
||||
__disable_irq();
|
||||
FURI_CRITICAL_ENTER();
|
||||
write_block(0, 0, false, indala_config_block_data);
|
||||
write_block(0, 1, false, card_data[0]);
|
||||
write_block(0, 2, false, card_data[1]);
|
||||
write_reset();
|
||||
__enable_irq();
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#include "applications.h"
|
||||
#include <furi.h>
|
||||
#include "loader/loader.h"
|
||||
#include "loader_i.h"
|
||||
@ -9,28 +10,46 @@
|
||||
|
||||
static Loader* loader_instance = NULL;
|
||||
|
||||
static bool
|
||||
loader_start_application(const FlipperApplication* application, const char* arguments) {
|
||||
loader_instance->application = application;
|
||||
|
||||
furi_assert(loader_instance->application_arguments == NULL);
|
||||
if(arguments && strlen(arguments) > 0) {
|
||||
loader_instance->application_arguments = strdup(arguments);
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name);
|
||||
|
||||
furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name);
|
||||
furi_thread_set_stack_size(
|
||||
loader_instance->application_thread, loader_instance->application->stack_size);
|
||||
furi_thread_set_context(
|
||||
loader_instance->application_thread, loader_instance->application_arguments);
|
||||
furi_thread_set_callback(
|
||||
loader_instance->application_thread, loader_instance->application->app);
|
||||
|
||||
bool result = furi_thread_start(loader_instance->application_thread);
|
||||
|
||||
if(!result) {
|
||||
loader_instance->application = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void loader_menu_callback(void* _ctx, uint32_t index) {
|
||||
const FlipperApplication* flipper_app = _ctx;
|
||||
const FlipperApplication* application = _ctx;
|
||||
|
||||
furi_assert(flipper_app->app);
|
||||
furi_assert(flipper_app->name);
|
||||
furi_assert(application->app);
|
||||
furi_assert(application->name);
|
||||
|
||||
if(!loader_lock(loader_instance)) return;
|
||||
|
||||
if(furi_thread_get_state(loader_instance->thread) != FuriThreadStateStopped) {
|
||||
FURI_LOG_E(TAG, "Can't start app. %s is running", loader_instance->current_app->name);
|
||||
if(!loader_lock(loader_instance)) {
|
||||
FURI_LOG_E(TAG, "Loader is locked");
|
||||
return;
|
||||
}
|
||||
furi_hal_power_insomnia_enter();
|
||||
|
||||
loader_instance->current_app = flipper_app;
|
||||
|
||||
FURI_LOG_I(TAG, "Starting: %s", loader_instance->current_app->name);
|
||||
furi_thread_set_name(loader_instance->thread, flipper_app->name);
|
||||
furi_thread_set_stack_size(loader_instance->thread, flipper_app->stack_size);
|
||||
furi_thread_set_context(loader_instance->thread, NULL);
|
||||
furi_thread_set_callback(loader_instance->thread, flipper_app->app);
|
||||
furi_thread_start(loader_instance->thread);
|
||||
loader_start_application(application, NULL);
|
||||
}
|
||||
|
||||
static void loader_submenu_callback(void* context, uint32_t index) {
|
||||
@ -61,6 +80,12 @@ const FlipperApplication* loader_find_application_by_name(const char* name) {
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
|
||||
if(strcmp(name, FLIPPER_SETTINGS_APPS[i].name) == 0) {
|
||||
application = &FLIPPER_SETTINGS_APPS[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) {
|
||||
if(strcmp(name, FLIPPER_DEBUG_APPS[i].name) == 0) {
|
||||
@ -73,32 +98,36 @@ const FlipperApplication* loader_find_application_by_name(const char* name) {
|
||||
}
|
||||
|
||||
void loader_cli_open(Cli* cli, string_t args, Loader* instance) {
|
||||
string_strim(args);
|
||||
string_t application_name;
|
||||
string_init(application_name);
|
||||
|
||||
if(string_size(args) == 0) {
|
||||
printf("No application provided\r\n");
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if(!args_read_probably_quoted_string_and_trim(args, application_name)) {
|
||||
printf("No application provided\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
const FlipperApplication* application = loader_find_application_by_name(string_get_cstr(args));
|
||||
if(!application) {
|
||||
printf("%s doesn't exists\r\n", string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
const FlipperApplication* application =
|
||||
loader_find_application_by_name(string_get_cstr(application_name));
|
||||
if(!application) {
|
||||
printf("%s doesn't exists\r\n", string_get_cstr(application_name));
|
||||
break;
|
||||
}
|
||||
|
||||
if(furi_thread_get_state(instance->thread) != FuriThreadStateStopped) {
|
||||
printf("Can't start, furi application is running");
|
||||
return;
|
||||
}
|
||||
string_strim(args);
|
||||
if(!loader_start_application(application, string_get_cstr(args))) {
|
||||
printf("Can't start, furi application is running");
|
||||
return;
|
||||
} else {
|
||||
// We must to increment lock counter to keep balance
|
||||
// TODO: rewrite whole thing, it's complex as hell
|
||||
FURI_CRITICAL_ENTER();
|
||||
instance->lock_count++;
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
} while(false);
|
||||
|
||||
instance->lock_semaphore++;
|
||||
furi_hal_power_insomnia_enter();
|
||||
instance->current_app = application;
|
||||
printf("Starting: %s\r\n", instance->current_app->name);
|
||||
furi_thread_set_name(instance->thread, application->name);
|
||||
furi_thread_set_stack_size(instance->thread, application->stack_size);
|
||||
furi_thread_set_callback(instance->thread, application->app);
|
||||
furi_thread_start(instance->thread);
|
||||
string_clear(application_name);
|
||||
}
|
||||
|
||||
void loader_cli_list(Cli* cli, string_t args, Loader* instance) {
|
||||
@ -152,62 +181,44 @@ void loader_cli(Cli* cli, string_t args, void* _ctx) {
|
||||
LoaderStatus loader_start(Loader* instance, const char* name, const char* args) {
|
||||
furi_assert(name);
|
||||
|
||||
const FlipperApplication* flipper_app = loader_find_application_by_name(name);
|
||||
const FlipperApplication* application = loader_find_application_by_name(name);
|
||||
|
||||
if(!flipper_app) {
|
||||
if(!application) {
|
||||
FURI_LOG_E(TAG, "Can't find application with name %s", name);
|
||||
return LoaderStatusErrorUnknownApp;
|
||||
}
|
||||
|
||||
bool locked = loader_lock(instance);
|
||||
|
||||
if(!locked || (furi_thread_get_state(instance->thread) != FuriThreadStateStopped)) {
|
||||
FURI_LOG_E(TAG, "Can't start app. %s is running", instance->current_app->name);
|
||||
/* no need to call loader_unlock() - it is called as soon as application stops */
|
||||
if(!loader_lock(loader_instance)) {
|
||||
FURI_LOG_E(TAG, "Loader is locked");
|
||||
return LoaderStatusErrorAppStarted;
|
||||
}
|
||||
|
||||
instance->current_app = flipper_app;
|
||||
void* thread_args = NULL;
|
||||
if(args) {
|
||||
string_set_str(instance->args, args);
|
||||
string_strim(instance->args);
|
||||
thread_args = (void*)string_get_cstr(instance->args);
|
||||
FURI_LOG_I(TAG, "Start %s app with args: %s", name, args);
|
||||
} else {
|
||||
string_reset(instance->args);
|
||||
FURI_LOG_I(TAG, "Start %s app with no args", name);
|
||||
if(!loader_start_application(application, args)) {
|
||||
return LoaderStatusErrorInternal;
|
||||
}
|
||||
|
||||
furi_thread_set_name(instance->thread, flipper_app->name);
|
||||
furi_thread_set_stack_size(instance->thread, flipper_app->stack_size);
|
||||
furi_thread_set_context(instance->thread, thread_args);
|
||||
furi_thread_set_callback(instance->thread, flipper_app->app);
|
||||
|
||||
bool thread_started = furi_thread_start(instance->thread);
|
||||
return thread_started ? LoaderStatusOk : LoaderStatusErrorInternal;
|
||||
return LoaderStatusOk;
|
||||
}
|
||||
|
||||
bool loader_lock(Loader* instance) {
|
||||
bool ret = false;
|
||||
furi_check(osMutexAcquire(instance->mutex, osWaitForever) == osOK);
|
||||
if(instance->lock_semaphore == 0) {
|
||||
instance->lock_semaphore++;
|
||||
ret = true;
|
||||
FURI_CRITICAL_ENTER();
|
||||
bool result = false;
|
||||
if(instance->lock_count == 0) {
|
||||
instance->lock_count++;
|
||||
result = true;
|
||||
}
|
||||
furi_check(osMutexRelease(instance->mutex) == osOK);
|
||||
return ret;
|
||||
FURI_CRITICAL_EXIT();
|
||||
return result;
|
||||
}
|
||||
|
||||
void loader_unlock(Loader* instance) {
|
||||
furi_check(osMutexAcquire(instance->mutex, osWaitForever) == osOK);
|
||||
furi_check(instance->lock_semaphore > 0);
|
||||
instance->lock_semaphore--;
|
||||
furi_check(osMutexRelease(instance->mutex) == osOK);
|
||||
FURI_CRITICAL_ENTER();
|
||||
if(instance->lock_count > 0) instance->lock_count--;
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
bool loader_is_locked(Loader* instance) {
|
||||
return (instance->lock_semaphore > 0);
|
||||
return instance->lock_count > 0;
|
||||
}
|
||||
|
||||
static void loader_thread_state_callback(FuriThreadState thread_state, void* context) {
|
||||
@ -219,6 +230,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
|
||||
if(thread_state == FuriThreadStateRunning) {
|
||||
event.type = LoaderEventTypeApplicationStarted;
|
||||
furi_pubsub_publish(loader_instance->pubsub, &event);
|
||||
furi_hal_power_insomnia_enter();
|
||||
|
||||
// Snapshot current memory usage
|
||||
instance->free_heap_size = memmgr_get_free_heap();
|
||||
@ -239,7 +251,13 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
|
||||
TAG,
|
||||
"Application thread stopped. Heap allocation balance: %d. Thread allocation balance: %d.",
|
||||
heap_diff,
|
||||
furi_thread_get_heap_size(instance->thread));
|
||||
furi_thread_get_heap_size(instance->application_thread));
|
||||
|
||||
if(loader_instance->application_arguments) {
|
||||
free(loader_instance->application_arguments);
|
||||
loader_instance->application_arguments = NULL;
|
||||
}
|
||||
|
||||
furi_hal_power_insomnia_exit();
|
||||
loader_unlock(instance);
|
||||
|
||||
@ -262,15 +280,12 @@ static uint32_t loader_back_to_primary_menu(void* context) {
|
||||
static Loader* loader_alloc() {
|
||||
Loader* instance = furi_alloc(sizeof(Loader));
|
||||
|
||||
instance->thread = furi_thread_alloc();
|
||||
furi_thread_enable_heap_trace(instance->thread);
|
||||
furi_thread_set_state_context(instance->thread, instance);
|
||||
furi_thread_set_state_callback(instance->thread, loader_thread_state_callback);
|
||||
|
||||
string_init(instance->args);
|
||||
instance->application_thread = furi_thread_alloc();
|
||||
furi_thread_enable_heap_trace(instance->application_thread);
|
||||
furi_thread_set_state_context(instance->application_thread, instance);
|
||||
furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback);
|
||||
|
||||
instance->pubsub = furi_pubsub_alloc();
|
||||
instance->mutex = osMutexNew(NULL);
|
||||
|
||||
#ifdef SRV_CLI
|
||||
instance->cli = furi_record_open("cli");
|
||||
@ -327,13 +342,9 @@ static void loader_free(Loader* instance) {
|
||||
furi_record_close("cli");
|
||||
}
|
||||
|
||||
osMutexDelete(instance->mutex);
|
||||
|
||||
furi_pubsub_free(instance->pubsub);
|
||||
|
||||
string_clear(instance->args);
|
||||
|
||||
furi_thread_free(instance->thread);
|
||||
furi_thread_free(instance->application_thread);
|
||||
|
||||
menu_free(loader_instance->primary_menu);
|
||||
view_dispatcher_remove_view(loader_instance->view_dispatcher, LoaderMenuViewPrimary);
|
||||
|
||||
@ -16,9 +16,11 @@
|
||||
|
||||
struct Loader {
|
||||
osThreadId_t loader_thread;
|
||||
FuriThread* thread;
|
||||
const FlipperApplication* current_app;
|
||||
string_t args;
|
||||
|
||||
const FlipperApplication* application;
|
||||
FuriThread* application_thread;
|
||||
char* application_arguments;
|
||||
|
||||
Cli* cli;
|
||||
Gui* gui;
|
||||
|
||||
@ -29,8 +31,7 @@ struct Loader {
|
||||
Submenu* settings_menu;
|
||||
|
||||
size_t free_heap_size;
|
||||
osMutexId_t mutex;
|
||||
volatile uint8_t lock_semaphore;
|
||||
volatile uint8_t lock_count;
|
||||
|
||||
FuriPubSub* pubsub;
|
||||
};
|
||||
|
||||
@ -102,7 +102,7 @@ typedef struct {
|
||||
uint8_t volume_id_max;
|
||||
} State;
|
||||
|
||||
float volumes[] = {0, 0.02, 0.05, 0.1, 0.5};
|
||||
const float volumes[] = {0, 0.02, 0.05, 0.1, 0.5};
|
||||
|
||||
bool is_white_note(const MelodyEventRecord* note_record, uint8_t id) {
|
||||
if(note_record == NULL) return false;
|
||||
|
||||
@ -1,28 +1,30 @@
|
||||
#include "power_cli.h"
|
||||
|
||||
#include <power/power_service/power.h>
|
||||
#include <cli/cli.h>
|
||||
#include <furi_hal.h>
|
||||
#include <cli/cli.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <power/power_service/power.h>
|
||||
|
||||
void power_cli_poweroff(Cli* cli, string_t args, void* context) {
|
||||
void power_cli_off(Cli* cli, string_t args) {
|
||||
Power* power = furi_record_open("power");
|
||||
printf("It's now safe to disconnect USB from your flipper\r\n");
|
||||
osDelay(666);
|
||||
power_off(power);
|
||||
}
|
||||
|
||||
void power_cli_reboot(Cli* cli, string_t args, void* context) {
|
||||
void power_cli_reboot(Cli* cli, string_t args) {
|
||||
power_reboot(PowerBootModeNormal);
|
||||
}
|
||||
|
||||
void power_cli_dfu(Cli* cli, string_t args, void* context) {
|
||||
void power_cli_reboot2dfu(Cli* cli, string_t args) {
|
||||
power_reboot(PowerBootModeDfu);
|
||||
}
|
||||
|
||||
void power_cli_info(Cli* cli, string_t args, void* context) {
|
||||
void power_cli_debug(Cli* cli, string_t args) {
|
||||
furi_hal_power_dump_state();
|
||||
}
|
||||
|
||||
void power_cli_otg(Cli* cli, string_t args, void* context) {
|
||||
void power_cli_5v(Cli* cli, string_t args) {
|
||||
if(!string_cmp(args, "0")) {
|
||||
furi_hal_power_disable_otg();
|
||||
} else if(!string_cmp(args, "1")) {
|
||||
@ -32,7 +34,7 @@ void power_cli_otg(Cli* cli, string_t args, void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
void power_cli_ext(Cli* cli, string_t args, void* context) {
|
||||
void power_cli_3v3(Cli* cli, string_t args) {
|
||||
if(!string_cmp(args, "0")) {
|
||||
furi_hal_power_disable_external_3_3v();
|
||||
} else if(!string_cmp(args, "1")) {
|
||||
@ -42,16 +44,70 @@ void power_cli_ext(Cli* cli, string_t args, void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
static void power_cli_command_print_usage() {
|
||||
printf("Usage:\r\n");
|
||||
printf("power <cmd> <args>\r\n");
|
||||
printf("Cmd list:\r\n");
|
||||
|
||||
printf("\toff\t - shutdown power\r\n");
|
||||
printf("\treboot\t - reboot\r\n");
|
||||
printf("\treboot2dfu\t - reboot to dfu bootloader\r\n");
|
||||
printf("\tdebug\t - show debug information\r\n");
|
||||
printf("\t5v <0 or 1>\t - enable or disable 5v ext\r\n");
|
||||
printf("\t3v3 <0 or 1>\t - enable or disable 3v3 ext\r\n");
|
||||
}
|
||||
|
||||
void power_cli(Cli* cli, string_t args, void* context) {
|
||||
string_t cmd;
|
||||
string_init(cmd);
|
||||
|
||||
do {
|
||||
if(!args_read_string_and_trim(args, cmd)) {
|
||||
power_cli_command_print_usage();
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "off") == 0) {
|
||||
power_cli_off(cli, args);
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "reboot") == 0) {
|
||||
power_cli_reboot(cli, args);
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "reboot2dfu") == 0) {
|
||||
power_cli_reboot2dfu(cli, args);
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "debug") == 0) {
|
||||
power_cli_debug(cli, args);
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "5v") == 0) {
|
||||
power_cli_5v(cli, args);
|
||||
break;
|
||||
}
|
||||
|
||||
if(string_cmp_str(cmd, "3v3") == 0) {
|
||||
power_cli_3v3(cli, args);
|
||||
break;
|
||||
}
|
||||
|
||||
power_cli_command_print_usage();
|
||||
} while(false);
|
||||
|
||||
string_clear(cmd);
|
||||
}
|
||||
|
||||
void power_on_system_start() {
|
||||
#ifdef SRV_CLI
|
||||
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, "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);
|
||||
cli_add_command(cli, "power", CliCommandFlagParallelSafe, power_cli, NULL);
|
||||
|
||||
furi_record_close("cli");
|
||||
#endif
|
||||
|
||||
@ -10,7 +10,7 @@ void power_off(Power* power) {
|
||||
view_dispatcher_send_to_front(power->view_dispatcher);
|
||||
view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewPopup);
|
||||
osDelay(10);
|
||||
furi_crash("Disconnect USB for safe shutdown");
|
||||
furi_halt("Disconnect USB for safe shutdown");
|
||||
}
|
||||
|
||||
void power_reboot(PowerBootMode mode) {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
typedef enum {
|
||||
SubghzCustomEventManagerNoSet = 0,
|
||||
SubghzCustomEventManagerSet,
|
||||
SubghzCustomEventManagerSetRAW,
|
||||
|
||||
SubghzCustomEventSceneDeleteSuccess = 100,
|
||||
SubghzCustomEventSceneDelete,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user