[FL-1191][FL-1524] Filesystem rework (#568)
* FS-Api: removed datetime manipulation functions and most of the file flags * Filesystem: common proxy api * Filesystem: renamed to Storage. Work has begun on a glue layer. Added functions for reentrance. * Storage: sd mount and sd file open * Storage: sd file close * Storage: temporary test app * Storage: free filedata on close * Storage: sd file read and write * Storage: added internal storage (LittleFS) * Storage: renamed internal commands * Storage: seek, tell, truncate, size, sync, eof * Storage: error descriptions * Storage: directory management api (open, close, read, rewind) * Storage: common management api (stat, fs_stat, remove, rename, mkdir) * Dolphin app and Notifications app now use raw storage. * Storage: storage statuses renamed. Implemented sd card icon. * Storage: added raw sd-card api. * Storage settings: work started * Assets: use new icons approach * Storage settings: working storage settings * Storage: completely redesigned api, no longer sticking out FS_Api * Storage: more simplified api, getting error_id from file is hidden from user, pointer to api is hidden inside file * Storage: cli info and format commands * Storage-cli: file list * Storage: a simpler and more reliable api * FatFS: slightly lighter and faster config. Also disabled reentrancy and file locking functions. They moved to a storage service. * Storage-cli: accommodate to the new cli api. * Storage: filesystem api is separated into internal and common api. * Cli: added the ability to print the list of free heap blocks * Storage: uses a list instead of an array to store the StorageFile. Rewrote api calls to use semaphores instead of thread flags. * Storage settings: added the ability to benchmark the SD card. * Gui module file select: uses new storage api * Apps: removed deprecated sd_card_test application * Args lib: support for enquoted arguments * Dialogs: a new gui app for simple non-asynchronous apps * Dialogs: view holder for easy single view work * File worker: use new storage api * IButton and lfrrfid apps: save keys to any storage * Apps: fix ibutton and lfrfid stack, remove sd_card_test. * SD filesystem: app removed * File worker: fixed api pointer type * Subghz: loading assets using the new storage api * NFC: use the new storage api * Dialogs: the better api for the message element * Archive: use new storage api * Irda: changed assest path, changed app path * FileWorker: removed unused file_buf_cnt * Storage: copying and renaming files now works between storages * Storage cli: read, copy, remove, rename commands * Archive: removed commented code * Storage cli: write command * Applications: add SRV_STORAGE and SRV_DIALOGS * Internal-storage: removed * Storage: improved api * Storage app: changed api pointer from StorageApp to Storage * Storage: better file_id handling * Storage: more consistent errors * Loader: support for NULL icons * Storage: do nothing with the lfs file or directory if it is not open * Storage: fix typo * Storage: minor float usage cleanup, rename some symbols. * Storage: compact doxygen comments. Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
8
applications/dialogs/dialogs-api-lock.h
Normal file
8
applications/dialogs/dialogs-api-lock.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#define API_LOCK_INIT_LOCKED() osSemaphoreNew(1, 0, NULL);
|
||||
|
||||
#define API_LOCK_WAIT_UNTIL_UNLOCK_AND_FREE(_lock) \
|
||||
osSemaphoreAcquire(_lock, osWaitForever); \
|
||||
osSemaphoreDelete(_lock);
|
||||
|
||||
#define API_LOCK_UNLOCK(_lock) osSemaphoreRelease(_lock);
|
62
applications/dialogs/dialogs-api.c
Normal file
62
applications/dialogs/dialogs-api.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "dialogs-i.h"
|
||||
#include "dialogs-api-lock.h"
|
||||
|
||||
/****************** File select ******************/
|
||||
|
||||
bool dialog_file_select_show(
|
||||
DialogsApp* context,
|
||||
const char* path,
|
||||
const char* extension,
|
||||
char* result,
|
||||
uint8_t result_size,
|
||||
const char* preselected_filename) {
|
||||
osSemaphoreId_t semaphore = API_LOCK_INIT_LOCKED();
|
||||
furi_check(semaphore != NULL);
|
||||
|
||||
DialogsAppData data = {
|
||||
.file_select = {
|
||||
.path = path,
|
||||
.extension = extension,
|
||||
.result = result,
|
||||
.result_size = result_size,
|
||||
.preselected_filename = preselected_filename,
|
||||
}};
|
||||
|
||||
DialogsAppReturn return_data;
|
||||
DialogsAppMessage message = {
|
||||
.semaphore = semaphore,
|
||||
.command = DialogsAppCommandFileOpen,
|
||||
.data = &data,
|
||||
.return_data = &return_data,
|
||||
};
|
||||
|
||||
furi_check(osMessageQueuePut(context->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
API_LOCK_WAIT_UNTIL_UNLOCK_AND_FREE(semaphore);
|
||||
|
||||
return return_data.bool_value;
|
||||
}
|
||||
|
||||
/****************** Message ******************/
|
||||
|
||||
DialogMessageButton dialog_message_show(DialogsApp* context, const DialogMessage* dialog_message) {
|
||||
osSemaphoreId_t semaphore = API_LOCK_INIT_LOCKED();
|
||||
furi_check(semaphore != NULL);
|
||||
|
||||
DialogsAppData data = {
|
||||
.dialog = {
|
||||
.message = dialog_message,
|
||||
}};
|
||||
|
||||
DialogsAppReturn return_data;
|
||||
DialogsAppMessage message = {
|
||||
.semaphore = semaphore,
|
||||
.command = DialogsAppCommandDialog,
|
||||
.data = &data,
|
||||
.return_data = &return_data,
|
||||
};
|
||||
|
||||
furi_check(osMessageQueuePut(context->message_queue, &message, 0, osWaitForever) == osOK);
|
||||
API_LOCK_WAIT_UNTIL_UNLOCK_AND_FREE(semaphore);
|
||||
|
||||
return return_data.dialog_value;
|
||||
}
|
15
applications/dialogs/dialogs-i.h
Normal file
15
applications/dialogs/dialogs-i.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "dialogs.h"
|
||||
#include "dialogs-message.h"
|
||||
#include "view-holder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
struct DialogsApp {
|
||||
osMessageQueueId_t message_queue;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
45
applications/dialogs/dialogs-message.h
Normal file
45
applications/dialogs/dialogs-message.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include "dialogs-i.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
const char* path;
|
||||
const char* extension;
|
||||
char* result;
|
||||
uint8_t result_size;
|
||||
const char* preselected_filename;
|
||||
} DialogsAppMessageDataFileSelect;
|
||||
|
||||
typedef struct {
|
||||
const DialogMessage* message;
|
||||
} DialogsAppMessageDataDialog;
|
||||
|
||||
typedef union {
|
||||
DialogsAppMessageDataFileSelect file_select;
|
||||
DialogsAppMessageDataDialog dialog;
|
||||
} DialogsAppData;
|
||||
|
||||
typedef union {
|
||||
bool bool_value;
|
||||
DialogMessageButton dialog_value;
|
||||
} DialogsAppReturn;
|
||||
|
||||
typedef enum {
|
||||
DialogsAppCommandFileOpen,
|
||||
DialogsAppCommandDialog,
|
||||
} DialogsAppCommand;
|
||||
|
||||
typedef struct {
|
||||
osSemaphoreId_t semaphore;
|
||||
DialogsAppCommand command;
|
||||
DialogsAppData* data;
|
||||
DialogsAppReturn* return_data;
|
||||
} DialogsAppMessage;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
59
applications/dialogs/dialogs-module-file-select.c
Normal file
59
applications/dialogs/dialogs-module-file-select.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "dialogs-i.h"
|
||||
#include "dialogs-api-lock.h"
|
||||
#include <gui/modules/file_select.h>
|
||||
|
||||
typedef struct {
|
||||
osSemaphoreId_t semaphore;
|
||||
bool result;
|
||||
} DialogsAppFileSelectContext;
|
||||
|
||||
static void dialogs_app_file_select_back_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DialogsAppFileSelectContext* file_select_context = context;
|
||||
file_select_context->result = false;
|
||||
API_LOCK_UNLOCK(file_select_context->semaphore);
|
||||
}
|
||||
|
||||
static void dialogs_app_file_select_callback(bool result, void* context) {
|
||||
furi_assert(context);
|
||||
DialogsAppFileSelectContext* file_select_context = context;
|
||||
file_select_context->result = result;
|
||||
API_LOCK_UNLOCK(file_select_context->semaphore);
|
||||
}
|
||||
|
||||
bool dialogs_app_process_module_file_select(const DialogsAppMessageDataFileSelect* data) {
|
||||
bool ret = false;
|
||||
Gui* gui = furi_record_open("gui");
|
||||
|
||||
DialogsAppFileSelectContext* file_select_context =
|
||||
furi_alloc(sizeof(DialogsAppFileSelectContext));
|
||||
file_select_context->semaphore = API_LOCK_INIT_LOCKED();
|
||||
|
||||
ViewHolder* view_holder = view_holder_alloc();
|
||||
view_holder_attach_to_gui(view_holder, gui);
|
||||
view_holder_set_back_callback(
|
||||
view_holder, dialogs_app_file_select_back_callback, file_select_context);
|
||||
|
||||
FileSelect* file_select = file_select_alloc();
|
||||
file_select_set_callback(file_select, dialogs_app_file_select_callback, file_select_context);
|
||||
file_select_set_filter(file_select, data->path, data->extension);
|
||||
file_select_set_result_buffer(file_select, data->result, data->result_size);
|
||||
file_select_init(file_select);
|
||||
if(data->preselected_filename != NULL) {
|
||||
file_select_set_selected_file(file_select, data->preselected_filename);
|
||||
}
|
||||
|
||||
view_holder_set_view(view_holder, file_select_get_view(file_select));
|
||||
view_holder_start(view_holder);
|
||||
API_LOCK_WAIT_UNTIL_UNLOCK_AND_FREE(file_select_context->semaphore);
|
||||
|
||||
ret = file_select_context->result;
|
||||
|
||||
free(file_select_context);
|
||||
view_holder_stop(view_holder);
|
||||
view_holder_free(view_holder);
|
||||
file_select_free(file_select);
|
||||
furi_record_close("gui");
|
||||
|
||||
return ret;
|
||||
}
|
12
applications/dialogs/dialogs-module-file-select.h
Normal file
12
applications/dialogs/dialogs-module-file-select.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "dialogs-message.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool dialogs_app_process_module_file_select(const DialogsAppMessageDataFileSelect* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
152
applications/dialogs/dialogs-module-message.c
Normal file
152
applications/dialogs/dialogs-module-message.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "dialogs-i.h"
|
||||
#include "dialogs-api-lock.h"
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
|
||||
typedef struct {
|
||||
osSemaphoreId_t semaphore;
|
||||
DialogMessageButton result;
|
||||
} DialogsAppMessageContext;
|
||||
|
||||
struct DialogMessage {
|
||||
const char* header_text;
|
||||
uint8_t header_text_x;
|
||||
uint8_t header_text_y;
|
||||
Align header_horizontal;
|
||||
Align header_vertical;
|
||||
const char* dialog_text;
|
||||
uint8_t dialog_text_x;
|
||||
uint8_t dialog_text_y;
|
||||
Align dialog_text_horizontal;
|
||||
Align dialog_text_vertical;
|
||||
const Icon* icon;
|
||||
uint8_t icon_x;
|
||||
uint8_t icon_y;
|
||||
const char* left_button_text;
|
||||
const char* center_button_text;
|
||||
const char* right_button_text;
|
||||
};
|
||||
|
||||
static void dialogs_app_message_back_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DialogsAppMessageContext* message_context = context;
|
||||
message_context->result = DialogMessageButtonBack;
|
||||
API_LOCK_UNLOCK(message_context->semaphore);
|
||||
}
|
||||
|
||||
static void dialogs_app_message_callback(DialogExResult result, void* context) {
|
||||
furi_assert(context);
|
||||
DialogsAppMessageContext* message_context = context;
|
||||
switch(result) {
|
||||
case DialogExResultLeft:
|
||||
message_context->result = DialogMessageButtonLeft;
|
||||
break;
|
||||
case DialogExResultRight:
|
||||
message_context->result = DialogMessageButtonRight;
|
||||
break;
|
||||
case DialogExResultCenter:
|
||||
message_context->result = DialogMessageButtonCenter;
|
||||
break;
|
||||
}
|
||||
API_LOCK_UNLOCK(message_context->semaphore);
|
||||
}
|
||||
|
||||
DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDataDialog* data) {
|
||||
DialogMessageButton ret = DialogMessageButtonBack;
|
||||
Gui* gui = furi_record_open("gui");
|
||||
const DialogMessage* message = data->message;
|
||||
DialogsAppMessageContext* message_context = furi_alloc(sizeof(DialogsAppMessageContext));
|
||||
message_context->semaphore = API_LOCK_INIT_LOCKED();
|
||||
|
||||
ViewHolder* view_holder = view_holder_alloc();
|
||||
view_holder_attach_to_gui(view_holder, gui);
|
||||
view_holder_set_back_callback(view_holder, dialogs_app_message_back_callback, message_context);
|
||||
|
||||
DialogEx* dialog_ex = dialog_ex_alloc();
|
||||
dialog_ex_set_result_callback(dialog_ex, dialogs_app_message_callback);
|
||||
dialog_ex_set_context(dialog_ex, message_context);
|
||||
dialog_ex_set_header(
|
||||
dialog_ex,
|
||||
message->header_text,
|
||||
message->header_text_x,
|
||||
message->header_text_y,
|
||||
message->header_horizontal,
|
||||
message->header_vertical);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
message->dialog_text,
|
||||
message->dialog_text_x,
|
||||
message->dialog_text_y,
|
||||
message->dialog_text_horizontal,
|
||||
message->dialog_text_vertical);
|
||||
dialog_ex_set_icon(dialog_ex, message->icon_x, message->icon_y, message->icon);
|
||||
dialog_ex_set_left_button_text(dialog_ex, message->left_button_text);
|
||||
dialog_ex_set_center_button_text(dialog_ex, message->center_button_text);
|
||||
dialog_ex_set_right_button_text(dialog_ex, message->right_button_text);
|
||||
|
||||
view_holder_set_view(view_holder, dialog_ex_get_view(dialog_ex));
|
||||
view_holder_start(view_holder);
|
||||
API_LOCK_WAIT_UNTIL_UNLOCK_AND_FREE(message_context->semaphore);
|
||||
|
||||
ret = message_context->result;
|
||||
|
||||
free(message_context);
|
||||
view_holder_stop(view_holder);
|
||||
view_holder_free(view_holder);
|
||||
dialog_ex_free(dialog_ex);
|
||||
furi_record_close("gui");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DialogMessage* dialog_message_alloc() {
|
||||
DialogMessage* message = furi_alloc(sizeof(DialogMessage));
|
||||
return message;
|
||||
}
|
||||
|
||||
void dialog_message_free(DialogMessage* message) {
|
||||
free(message);
|
||||
}
|
||||
|
||||
void dialog_message_set_text(
|
||||
DialogMessage* message,
|
||||
const char* text,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical) {
|
||||
message->dialog_text = text;
|
||||
message->dialog_text_x = x;
|
||||
message->dialog_text_y = y;
|
||||
message->dialog_text_horizontal = horizontal;
|
||||
message->dialog_text_vertical = vertical;
|
||||
}
|
||||
|
||||
void dialog_message_set_header(
|
||||
DialogMessage* message,
|
||||
const char* text,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical) {
|
||||
message->header_text = text;
|
||||
message->header_text_x = x;
|
||||
message->header_text_y = y;
|
||||
message->header_horizontal = horizontal;
|
||||
message->header_vertical = vertical;
|
||||
}
|
||||
|
||||
void dialog_message_set_icon(DialogMessage* message, const Icon* icon, uint8_t x, uint8_t y) {
|
||||
message->icon = icon;
|
||||
message->icon_x = x;
|
||||
message->icon_y = y;
|
||||
}
|
||||
|
||||
void dialog_message_set_buttons(
|
||||
DialogMessage* message,
|
||||
const char* left,
|
||||
const char* center,
|
||||
const char* right) {
|
||||
message->left_button_text = left;
|
||||
message->center_button_text = center;
|
||||
message->right_button_text = right;
|
||||
}
|
12
applications/dialogs/dialogs-module-message.h
Normal file
12
applications/dialogs/dialogs-module-message.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "dialogs-message.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DialogMessageButton dialogs_app_process_module_message(const DialogsAppMessageDataDialog* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
39
applications/dialogs/dialogs.c
Normal file
39
applications/dialogs/dialogs.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "dialogs-i.h"
|
||||
#include "dialogs-api-lock.h"
|
||||
#include "dialogs-module-file-select.h"
|
||||
#include "dialogs-module-message.h"
|
||||
|
||||
static DialogsApp* dialogs_app_alloc() {
|
||||
DialogsApp* app = malloc(sizeof(DialogsApp));
|
||||
app->message_queue = osMessageQueueNew(8, sizeof(DialogsAppMessage), NULL);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void dialogs_app_process_message(DialogsApp* app, DialogsAppMessage* message) {
|
||||
switch(message->command) {
|
||||
case DialogsAppCommandFileOpen:
|
||||
message->return_data->bool_value =
|
||||
dialogs_app_process_module_file_select(&message->data->file_select);
|
||||
break;
|
||||
case DialogsAppCommandDialog:
|
||||
message->return_data->dialog_value =
|
||||
dialogs_app_process_module_message(&message->data->dialog);
|
||||
break;
|
||||
}
|
||||
API_LOCK_UNLOCK(message->semaphore);
|
||||
}
|
||||
|
||||
int32_t dialogs_app(void* p) {
|
||||
DialogsApp* app = dialogs_app_alloc();
|
||||
furi_record_create("dialogs", app);
|
||||
|
||||
DialogsAppMessage message;
|
||||
while(1) {
|
||||
if(osMessageQueueGet(app->message_queue, &message, NULL, osWaitForever) == osOK) {
|
||||
dialogs_app_process_message(app, &message);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
128
applications/dialogs/dialogs.h
Normal file
128
applications/dialogs/dialogs.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <gui/canvas.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/****************** COMMON ******************/
|
||||
|
||||
typedef struct DialogsApp DialogsApp;
|
||||
|
||||
/****************** FILE SELECT ******************/
|
||||
|
||||
/**
|
||||
* Shows and processes the file selection dialog
|
||||
* @param context api pointer
|
||||
* @param path path to directory
|
||||
* @param extension file extension to be offered for selection
|
||||
* @param selected_filename buffer where the selected filename will be saved
|
||||
* @param selected_filename_size and the size of this buffer
|
||||
* @param preselected_filename filename to be preselected
|
||||
* @return bool whether a file was selected
|
||||
*/
|
||||
bool dialog_file_select_show(
|
||||
DialogsApp* context,
|
||||
const char* path,
|
||||
const char* extension,
|
||||
char* result,
|
||||
uint8_t result_size,
|
||||
const char* preselected_filename);
|
||||
|
||||
/****************** MESSAGE ******************/
|
||||
|
||||
/**
|
||||
* Message result type
|
||||
*/
|
||||
typedef enum {
|
||||
DialogMessageButtonBack,
|
||||
DialogMessageButtonLeft,
|
||||
DialogMessageButtonCenter,
|
||||
DialogMessageButtonRight,
|
||||
} DialogMessageButton;
|
||||
|
||||
/**
|
||||
* Message struct
|
||||
*/
|
||||
typedef struct DialogMessage DialogMessage;
|
||||
|
||||
/**
|
||||
* Allocate and fill message
|
||||
* @return DialogMessage*
|
||||
*/
|
||||
DialogMessage* dialog_message_alloc();
|
||||
|
||||
/**
|
||||
* Free message struct
|
||||
* @param message message pointer
|
||||
*/
|
||||
void dialog_message_free(DialogMessage* message);
|
||||
|
||||
/**
|
||||
* Set message text
|
||||
* @param message message pointer
|
||||
* @param text text, can be NULL if you don't want to display the text
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param horizontal horizontal alignment
|
||||
* @param vertical vertical alignment
|
||||
*/
|
||||
void dialog_message_set_text(
|
||||
DialogMessage* message,
|
||||
const char* text,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical);
|
||||
|
||||
/**
|
||||
* Set message header
|
||||
* @param message message pointer
|
||||
* @param text text, can be NULL if you don't want to display the header
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
* @param horizontal horizontal alignment
|
||||
* @param vertical vertical alignment
|
||||
*/
|
||||
void dialog_message_set_header(
|
||||
DialogMessage* message,
|
||||
const char* text,
|
||||
uint8_t x,
|
||||
uint8_t y,
|
||||
Align horizontal,
|
||||
Align vertical);
|
||||
|
||||
/**
|
||||
* Set message icon
|
||||
* @param message message pointer
|
||||
* @param icon icon pointer, can be NULL if you don't want to display the icon
|
||||
* @param x x position
|
||||
* @param y y position
|
||||
*/
|
||||
void dialog_message_set_icon(DialogMessage* message, const Icon* icon, uint8_t x, uint8_t y);
|
||||
|
||||
/**
|
||||
* Set message buttons text, button text can be NULL if you don't want to display and process some buttons
|
||||
* @param message message pointer
|
||||
* @param left left button text, can be NULL if you don't want to display the left button
|
||||
* @param center center button text, can be NULL if you don't want to display the center button
|
||||
* @param right right button text, can be NULL if you don't want to display the right button
|
||||
*/
|
||||
void dialog_message_set_buttons(
|
||||
DialogMessage* message,
|
||||
const char* left,
|
||||
const char* center,
|
||||
const char* right);
|
||||
|
||||
/**
|
||||
* Show message from filled struct
|
||||
* @param context api pointer
|
||||
* @param message message struct pointer to be shown
|
||||
* @return DialogMessageButton type
|
||||
*/
|
||||
DialogMessageButton dialog_message_show(DialogsApp* context, const DialogMessage* message);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
98
applications/dialogs/view-holder.h
Normal file
98
applications/dialogs/view-holder.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include <gui/gui.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ViewHolder ViewHolder;
|
||||
|
||||
/**
|
||||
* @brief Free callback type
|
||||
*/
|
||||
typedef void (*FreeCallback)(void* free_context);
|
||||
|
||||
/**
|
||||
* @brief Back callback type
|
||||
* @warning comes from GUI thread
|
||||
*/
|
||||
typedef void (*BackCallback)(void* back_context);
|
||||
|
||||
/**
|
||||
* @brief Allocate ViewHolder
|
||||
* @return pointer to ViewHolder instance
|
||||
*/
|
||||
ViewHolder* view_holder_alloc();
|
||||
|
||||
/**
|
||||
* @brief Free ViewHolder and call Free callback
|
||||
* @param view_holder pointer to ViewHolder
|
||||
*/
|
||||
void view_holder_free(ViewHolder* view_holder);
|
||||
|
||||
/**
|
||||
* @brief Set view for ViewHolder
|
||||
*
|
||||
* @param view_holder ViewHolder instance
|
||||
* @param view View instance
|
||||
*/
|
||||
void view_holder_set_view(ViewHolder* view_holder, View* view);
|
||||
|
||||
/**
|
||||
* @brief Set Free callback
|
||||
*
|
||||
* @param view_holder ViewHolder instance
|
||||
* @param free_callback callback pointer
|
||||
* @param free_context callback context
|
||||
*/
|
||||
void view_holder_set_free_callback(
|
||||
ViewHolder* view_holder,
|
||||
FreeCallback free_callback,
|
||||
void* free_context);
|
||||
|
||||
/**
|
||||
* @brief Free callback context getter. Useful if your Free callback is a module destructor, so you can get an instance of the module using this method.
|
||||
*
|
||||
* @param view_holder ViewHolder instance
|
||||
* @return void* free callback context
|
||||
*/
|
||||
void* view_holder_get_free_context(ViewHolder* view_holder);
|
||||
|
||||
void view_holder_set_back_callback(
|
||||
ViewHolder* view_holder,
|
||||
BackCallback back_callback,
|
||||
void* back_context);
|
||||
|
||||
/**
|
||||
* @brief Attach ViewHolder to GUI
|
||||
*
|
||||
* @param view_holder ViewHolder instance
|
||||
* @param gui GUI instance to attach to
|
||||
*/
|
||||
void view_holder_attach_to_gui(ViewHolder* view_holder, Gui* gui);
|
||||
|
||||
/**
|
||||
* @brief Enable view processing
|
||||
*
|
||||
* @param view_holder
|
||||
*/
|
||||
void view_holder_start(ViewHolder* view_holder);
|
||||
|
||||
/**
|
||||
* @brief Disable view processing
|
||||
*
|
||||
* @param view_holder
|
||||
*/
|
||||
void view_holder_stop(ViewHolder* view_holder);
|
||||
|
||||
/** View Update Handler
|
||||
* @param view, View Instance
|
||||
* @param context, ViewHolder instance
|
||||
*/
|
||||
void view_holder_update(View* view, void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
130
applications/dialogs/view_holder.c
Normal file
130
applications/dialogs/view_holder.c
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "view-holder.h"
|
||||
#include <gui/view_i.h>
|
||||
|
||||
struct ViewHolder {
|
||||
View* view;
|
||||
ViewPort* view_port;
|
||||
Gui* gui;
|
||||
|
||||
FreeCallback free_callback;
|
||||
void* free_context;
|
||||
|
||||
BackCallback back_callback;
|
||||
void* back_context;
|
||||
};
|
||||
|
||||
static void view_holder_draw_callback(Canvas* canvas, void* context);
|
||||
static void view_holder_input_callback(InputEvent* event, void* context);
|
||||
|
||||
ViewHolder* view_holder_alloc() {
|
||||
ViewHolder* view_holder = furi_alloc(sizeof(ViewHolder));
|
||||
|
||||
view_holder->view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_holder->view_port, view_holder_draw_callback, view_holder);
|
||||
view_port_input_callback_set(view_holder->view_port, view_holder_input_callback, view_holder);
|
||||
view_port_enabled_set(view_holder->view_port, false);
|
||||
|
||||
return view_holder;
|
||||
}
|
||||
|
||||
void view_holder_free(ViewHolder* view_holder) {
|
||||
furi_assert(view_holder);
|
||||
|
||||
if(view_holder->gui) {
|
||||
gui_remove_view_port(view_holder->gui, view_holder->view_port);
|
||||
}
|
||||
|
||||
view_port_free(view_holder->view_port);
|
||||
|
||||
if(view_holder->free_callback) {
|
||||
view_holder->free_callback(view_holder->free_context);
|
||||
}
|
||||
|
||||
free(view_holder);
|
||||
}
|
||||
|
||||
void view_holder_set_view(ViewHolder* view_holder, View* view) {
|
||||
furi_assert(view_holder);
|
||||
if(view_holder->view) {
|
||||
view_set_update_callback(view_holder->view, NULL);
|
||||
view_set_update_callback_context(view_holder->view, NULL);
|
||||
}
|
||||
|
||||
view_holder->view = view;
|
||||
|
||||
if(view_holder->view) {
|
||||
view_set_update_callback(view_holder->view, view_holder_update);
|
||||
view_set_update_callback_context(view_holder->view, view_holder);
|
||||
}
|
||||
}
|
||||
|
||||
void view_holder_set_free_callback(
|
||||
ViewHolder* view_holder,
|
||||
FreeCallback free_callback,
|
||||
void* free_context) {
|
||||
furi_assert(view_holder);
|
||||
view_holder->free_callback = free_callback;
|
||||
view_holder->free_context = free_context;
|
||||
}
|
||||
|
||||
void* view_holder_get_free_context(ViewHolder* view_holder) {
|
||||
return view_holder->free_context;
|
||||
}
|
||||
|
||||
void view_holder_set_back_callback(
|
||||
ViewHolder* view_holder,
|
||||
BackCallback back_callback,
|
||||
void* back_context) {
|
||||
furi_assert(view_holder);
|
||||
view_holder->back_callback = back_callback;
|
||||
view_holder->back_context = back_context;
|
||||
}
|
||||
|
||||
void view_holder_attach_to_gui(ViewHolder* view_holder, Gui* gui) {
|
||||
furi_assert(gui);
|
||||
furi_assert(view_holder);
|
||||
view_holder->gui = gui;
|
||||
gui_add_view_port(gui, view_holder->view_port, GuiLayerFullscreen);
|
||||
}
|
||||
|
||||
void view_holder_start(ViewHolder* view_holder) {
|
||||
view_port_enabled_set(view_holder->view_port, true);
|
||||
}
|
||||
|
||||
void view_holder_stop(ViewHolder* view_holder) {
|
||||
view_port_enabled_set(view_holder->view_port, false);
|
||||
}
|
||||
|
||||
void view_holder_update(View* view, void* context) {
|
||||
furi_assert(view);
|
||||
furi_assert(context);
|
||||
|
||||
ViewHolder* view_holder = context;
|
||||
if(view == view_holder->view) {
|
||||
view_port_update(view_holder->view_port);
|
||||
}
|
||||
}
|
||||
|
||||
static void view_holder_draw_callback(Canvas* canvas, void* context) {
|
||||
ViewHolder* view_holder = context;
|
||||
if(view_holder->view) {
|
||||
view_draw(view_holder->view, canvas);
|
||||
}
|
||||
}
|
||||
|
||||
static void view_holder_input_callback(InputEvent* event, void* context) {
|
||||
ViewHolder* view_holder = context;
|
||||
bool is_consumed = false;
|
||||
|
||||
if(view_holder->view) {
|
||||
is_consumed = view_input(view_holder->view, event);
|
||||
}
|
||||
|
||||
if(!is_consumed && event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyBack) {
|
||||
if(view_holder->back_callback) {
|
||||
view_holder->back_callback(view_holder->back_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user