Просмотр исходного кода

Merge flip_library from https://github.com/jblanked/FlipLibrary

Willy-JL 1 год назад
Родитель
Сommit
3070d6a51a

+ 17 - 1
flip_library/CHANGELOG.md

@@ -1,3 +1,19 @@
+## v1.3
+Refactored by Derek Jamison:  
+- Improved progress display.  
+- Added connectivity check on startup.
+
+## v1.2
+- Improved memory allocation.
+- Added in Dog Facts.
+- Added in Random Quotes.
+
+## v1.1
+- Update for app catalog.
+
+## v1.0
+- Initial Release.
+
 ## v1.2
 - Improved memory allocation.
 - Added in Dog Facts.
@@ -7,4 +23,4 @@
 - Update for app catalog.
 
 ## v1.0
-- Initial Release.
+- Initial Release.

+ 3 - 3
flip_library/README.md

@@ -1,12 +1,12 @@
 The **FlipLibrary** app for Flipper Zero is a versatile and user-friendly application that offers a combination of useful features to enhance your Flipper Zero experience. 
 
-The app includes a **dictionary**, **random facts**, and additional functionalities, all accessible directly from your Flipper Zero device. It is designed for easy navigation and quick access to information, making it a handy companion for on-the-go learning and entertainment. 
+The app includes a **dictionary**, **random facts**, and additional functionalities, all accessible directly from your Flipper Zero device. It is designed for easy navigation and quick access to information, making it a handy companion for on-the-go learning and entertainment. Big shout out to [Derek Jamison](https://github.com/jamisonderek) for his contributions. 
 
 FlipLibrary uses the FlipperHTTP flash for the WiFi Devboard, first introduced in the WebCrawler app: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
 
 
 ## Requirements
-- WiFi Dev Board or Raspberry Pi Pico W for Flipper Zero with FlipperHTTP Flash: https://github.com/jblanked/FlipperHTTP
+- WiFi Developer Board or Raspberry Pi Pico W with FlipperHTTP Flash: https://github.com/jblanked/FlipperHTTP
 - WiFi Access Point
 
 
@@ -38,4 +38,4 @@ The app automatically allocates necessary resources and initializes settings. If
 # Known Bugs
 
 1. **Screen Delay**: Occasionally, the Defition or Random Facts screen may get stuck on "Loading".
-   - If it takes longer than 10 seconds, restart your Flipper Zero.
+   - Update to version 1.3 or higher.

+ 22 - 37
flip_library/alloc/flip_library_alloc.c

@@ -14,7 +14,7 @@ FlipLibraryApp* flip_library_app_alloc() {
     // Allocate the text input buffer
     app->uart_text_input_buffer_size_ssid = 64;
     app->uart_text_input_buffer_size_password = 64;
-    app->uart_text_input_buffer_size_dictionary = 64;
+    app->uart_text_input_buffer_size_query = 64;
     if(!easy_flipper_set_buffer(
            &app->uart_text_input_buffer_ssid, app->uart_text_input_buffer_size_ssid)) {
         return NULL;
@@ -33,12 +33,11 @@ FlipLibraryApp* flip_library_app_alloc() {
         return NULL;
     }
     if(!easy_flipper_set_buffer(
-           &app->uart_text_input_buffer_dictionary, app->uart_text_input_buffer_size_dictionary)) {
+           &app->uart_text_input_buffer_query, app->uart_text_input_buffer_size_query)) {
         return NULL;
     }
     if(!easy_flipper_set_buffer(
-           &app->uart_text_input_temp_buffer_dictionary,
-           app->uart_text_input_buffer_size_dictionary)) {
+           &app->uart_text_input_temp_buffer_query, app->uart_text_input_buffer_size_query)) {
         return NULL;
     }
 
@@ -46,54 +45,39 @@ FlipLibraryApp* flip_library_app_alloc() {
     if(!easy_flipper_set_view_dispatcher(&app->view_dispatcher, gui, app)) {
         return NULL;
     }
+    view_dispatcher_set_custom_event_callback(
+        app->view_dispatcher, flip_library_custom_event_callback);
 
     // Main view
     if(!easy_flipper_set_view(
-           &app->view_random_facts,
-           FlipLibraryViewRandomFactsRun,
-           view_draw_callback_random_facts,
+           &app->view_loader,
+           FlipLibraryViewLoader,
+           flip_library_loader_draw_callback,
            NULL,
            callback_to_random_facts,
            &app->view_dispatcher,
            app)) {
         return NULL;
     }
-    if(!easy_flipper_set_view(
-           &app->view_dictionary,
-           FlipLibraryViewDictionaryRun,
-           view_draw_callback_dictionary_run,
-           NULL,
-           callback_to_submenu,
-           &app->view_dispatcher,
-           app)) {
-        return NULL;
-    }
+    flip_library_loader_init(app->view_loader);
 
     // Widget
     if(!easy_flipper_set_widget(
-           &app->widget,
+           &app->widget_about,
            FlipLibraryViewAbout,
-           "FlipLibrary v1.2\n-----\nDictionary, random facts, and\nmore.\n-----\nwww.github.com/jblanked",
+           "FlipLibrary v1.3\n-----\nDictionary, random facts, and\nmore.\n-----\nwww.github.com/jblanked",
            callback_to_submenu,
            &app->view_dispatcher)) {
         return NULL;
     }
     if(!easy_flipper_set_widget(
-           &app->widget_random_fact,
-           FlipLibraryViewRandomFactWidget,
+           &app->widget_result,
+           FlipLibraryViewWidgetResult,
            "Error, try again.",
            callback_to_random_facts,
            &app->view_dispatcher)) {
         return NULL;
     }
-    if(!easy_flipper_set_widget(
-           &app->widget_dictionary,
-           FlipLibraryViewDictionaryWidget,
-           "Error, try again.",
-           callback_to_submenu,
-           &app->view_dispatcher)) {
-        return NULL;
-    }
 
     // Text Input
     if(!easy_flipper_set_uart_text_input(
@@ -121,12 +105,12 @@ FlipLibraryApp* flip_library_app_alloc() {
         return NULL;
     }
     if(!easy_flipper_set_uart_text_input(
-           &app->uart_text_input_dictionary,
-           FlipLibraryViewDictionaryTextInput,
-           "Enter a word",
-           app->uart_text_input_temp_buffer_dictionary,
-           app->uart_text_input_buffer_size_dictionary,
-           text_updated_dictionary,
+           &app->uart_text_input_query,
+           FlipLibraryViewTextInputQuery,
+           "Enter Query",
+           app->uart_text_input_temp_buffer_query,
+           app->uart_text_input_buffer_size_query,
+           text_updated_query,
            callback_to_submenu,
            &app->view_dispatcher,
            app)) {
@@ -155,7 +139,7 @@ FlipLibraryApp* flip_library_app_alloc() {
     if(!easy_flipper_set_submenu(
            &app->submenu_main,
            FlipLibraryViewSubmenuMain,
-           "FlipLibrary v1.2",
+           "FlipLibrary v1.3",
            callback_exit_app,
            &app->view_dispatcher)) {
         return NULL;
@@ -218,9 +202,10 @@ FlipLibraryApp* flip_library_app_alloc() {
            app->uart_text_input_buffer_password,
            app->uart_text_input_buffer_size_password)) {
         // Update variable items
-        if(app->variable_item_ssid)
+        if(app->variable_item_ssid) {
             variable_item_set_current_value_text(
                 app->variable_item_ssid, app->uart_text_input_buffer_ssid);
+        }
         // dont show password
 
         // Copy items into their temp buffers with safety checks

+ 27 - 0
flip_library/app.c

@@ -18,6 +18,33 @@ int32_t flip_library_app(void* p) {
         return -1;
     }
 
+    if(app_instance->uart_text_input_buffer_ssid != NULL &&
+       app_instance->uart_text_input_buffer_password != NULL) {
+        // Try to wait for pong response.
+        uint8_t counter = 10;
+        while(fhttp.state == INACTIVE && --counter > 0) {
+            FURI_LOG_D(TAG, "Waiting for PONG");
+            furi_delay_ms(100);
+        }
+
+        if(counter == 0) {
+            DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
+            DialogMessage* message = dialog_message_alloc();
+            dialog_message_set_header(
+                message, "[FlipperHTTP Error]", 64, 0, AlignCenter, AlignTop);
+            dialog_message_set_text(
+                message,
+                "Ensure your WiFi Developer\nBoard or Pico W is connected\nand the latest FlipperHTTP\nfirmware is installed.",
+                0,
+                63,
+                AlignLeft,
+                AlignBottom);
+            dialog_message_show(dialogs, message);
+            dialog_message_free(message);
+            furi_record_close(RECORD_DIALOGS);
+        }
+    }
+
     // Run the view dispatcher
     view_dispatcher_run(app_instance->view_dispatcher);
 

+ 1 - 1
flip_library/application.fam

@@ -10,5 +10,5 @@ App(
     fap_description="Dictionary, random facts, and more.",
     fap_author="JBlanked",
     fap_weburl="https://github.com/jblanked/FlipLibrary",
-    fap_version="1.2",
+    fap_version="1.3",
 )

Разница между файлами не показана из-за своего большого размера
+ 393 - 486
flip_library/callback/flip_library_callback.c


+ 44 - 19
flip_library/callback/flip_library_callback.h

@@ -5,34 +5,59 @@
 
 #define MAX_TOKENS 512 // Adjust based on expected JSON size
 
+typedef enum FactState FactState;
+enum FactState {
+    FactStateInitial,
+    FactStateRequested,
+    FactStateReceived,
+    FactStateParsed,
+    FactStateParseError,
+    FactStateError,
+};
+
+typedef enum FlipLibraryCustomEvent FlipLibraryCustomEvent;
+enum FlipLibraryCustomEvent {
+    FlipLibraryCustomEventProcess,
+};
+
+typedef struct FactLoaderModel FactLoaderModel;
+typedef bool (*FactLoaderFetch)(FactLoaderModel* model);
+typedef char* (*FactLoaderParser)(FactLoaderModel* model);
+struct FactLoaderModel {
+    char* title;
+    char* fact_text;
+    FactState fact_state;
+    FactLoaderFetch fetcher;
+    FactLoaderParser parser;
+    void* parser_context;
+    size_t request_index;
+    size_t request_count;
+    ViewNavigationCallback back_callback;
+    FuriTimer* timer;
+};
+
 extern uint32_t random_facts_index;
 extern bool sent_random_fact_request;
 extern bool random_fact_request_success;
 extern bool random_fact_request_success_all;
 extern char* random_fact;
 
-// Parse JSON to find the "text" key
-char* flip_library_parse_random_fact();
-
-char* flip_library_parse_cat_fact();
-
-char* flip_library_parse_dog_fact();
-
-char* flip_library_parse_quote();
-
-char* flip_library_parse_dictionary();
-
-void flip_library_request_error(Canvas* canvas);
+void flip_library_generic_switch_to_view(
+    FlipLibraryApp* app,
+    char* title,
+    FactLoaderFetch fetcher,
+    FactLoaderParser parser,
+    size_t request_count,
+    ViewNavigationCallback back,
+    uint32_t view_id);
 
-void flip_library_draw_fact(char* message, Widget** widget);
+void flip_library_loader_draw_callback(Canvas* canvas, void* model);
 
-// Callback for drawing the main screen
-void view_draw_callback_random_facts(Canvas* canvas, void* model);
+void flip_library_loader_init(View* view);
 
-void view_draw_callback_dictionary_run(Canvas* canvas, void* model);
+void flip_library_loader_free_model(View* view);
 
-// Input callback for the view (async input handling)
-bool view_input_callback_random_facts(InputEvent* event, void* context);
+bool flip_library_custom_event_callback(void* context, uint32_t index);
 
 void callback_submenu_choices(void* context, uint32_t index);
 
@@ -40,7 +65,7 @@ void text_updated_ssid(void* context);
 
 void text_updated_password(void* context);
 
-void text_updated_dictionary(void* context);
+void text_updated_query(void* context);
 
 uint32_t callback_to_submenu(void* context);
 

+ 17 - 20
flip_library/flip_library.c

@@ -2,6 +2,8 @@
 
 FlipLibraryApp* app_instance = NULL;
 
+void flip_library_loader_free_model(View* view);
+
 // Function to free the resources used by FlipLibraryApp
 void flip_library_app_free(FlipLibraryApp* app) {
     if(!app) {
@@ -10,13 +12,10 @@ void flip_library_app_free(FlipLibraryApp* app) {
     }
 
     // Free View(s)
-    if(app->view_random_facts) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewRandomFactsRun);
-        view_free(app->view_random_facts);
-    }
-    if(app->view_dictionary) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewDictionaryRun);
-        view_free(app->view_dictionary);
+    if(app->view_loader) {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewLoader);
+        flip_library_loader_free_model(app->view_loader);
+        view_free(app->view_loader);
     }
 
     // Free Submenu(s)
@@ -30,17 +29,13 @@ void flip_library_app_free(FlipLibraryApp* app) {
     }
 
     // Free Widget(s)
-    if(app->widget) {
+    if(app->widget_about) {
         view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewAbout);
-        widget_free(app->widget);
+        widget_free(app->widget_about);
     }
-    if(app->widget_random_fact) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewRandomFactWidget);
-        widget_free(app->widget_random_fact);
-    }
-    if(app->widget_dictionary) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewDictionaryWidget);
-        widget_free(app->widget_dictionary);
+    if(app->widget_result) {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewWidgetResult);
+        widget_free(app->widget_result);
     }
 
     // Free Variable Item List(s)
@@ -58,16 +53,18 @@ void flip_library_app_free(FlipLibraryApp* app) {
         view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewTextInputPassword);
         text_input_free(app->uart_text_input_password);
     }
-    if(app->uart_text_input_dictionary) {
-        view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewDictionaryTextInput);
-        text_input_free(app->uart_text_input_dictionary);
+    if(app->uart_text_input_query) {
+        view_dispatcher_remove_view(app->view_dispatcher, FlipLibraryViewTextInputQuery);
+        text_input_free(app->uart_text_input_query);
     }
 
     // deinitalize flipper http
     flipper_http_deinit();
 
     // free the view dispatcher
-    if(app->view_dispatcher) view_dispatcher_free(app->view_dispatcher);
+    if(app->view_dispatcher) {
+        view_dispatcher_free(app->view_dispatcher);
+    }
 
     // close the gui
     furi_record_close(RECORD_GUI);

+ 15 - 27
flip_library/flip_library.h

@@ -31,43 +31,31 @@ typedef enum {
 // Define a single view for our FlipLibrary application
 typedef enum {
     FlipLibraryViewRandomFacts = 7, // The random facts main screen
-    FlipLibraryViewRandomFactsRun = 8, // The random facts widget that displays the random fact
-    FlipLibraryViewSubmenuMain = 9, // The submenu screen
-    FlipLibraryViewAbout = 10, // The about screen
-    FlipLibraryViewSettings = 11, // The settings screen
-    FlipLibraryViewTextInputSSID = 12, // The text input screen (SSID)
-    FlipLibraryViewTextInputPassword = 13, // The text input screen (password)
-    FlipLibraryViewDictionary = 14, // The dictionary submenu screen
-    //
-    FlipLibraryViewDictionaryTextInput = 15,
-    FlipLibraryViewDictionaryRun = 16,
-    //
-    FlipLibraryViewRandomFactsCats = 17,
-    FlipLibraryViewRandomFactsDogs = 18,
-    FlipLibraryViewRandomFactsQuotes = 19,
-    FlipLibraryViewRandomFactsAll = 20,
-    //
-    FlipLibraryViewRandomFactWidget = 21, // The text box that displays the random fact
-    FlipLibraryViewDictionaryWidget = 22, // The text box that displays the dictionary
+    FlipLibraryViewLoader, // The loader screen retrieves data from the internet
+    FlipLibraryViewSubmenuMain, // The submenu screen
+    FlipLibraryViewAbout, // The about screen
+    FlipLibraryViewSettings, // The settings screen
+    FlipLibraryViewTextInputSSID, // The text input screen (SSID)
+    FlipLibraryViewTextInputPassword, // The text input screen (password)
+    FlipLibraryViewTextInputQuery, // Query the user for information
+    FlipLibraryViewWidgetResult, // The text box that displays the random fact
 } FlipLibraryView;
 
 // Each screen will have its own view
 typedef struct {
     ViewDispatcher* view_dispatcher; // Switches between our views
-    View* view_random_facts; // The main screen that displays the random fact
-    View* view_dictionary; // The dictionary screen
+    View* view_loader; // The screen that loads data from internet
     Submenu* submenu_main; // The submenu for the main screen
     Submenu* submenu_random_facts; // The submenu for the random facts screen
-    Widget* widget; // The widget
+    Widget* widget_about; // The widget for the about screen
     VariableItemList* variable_item_list_wifi; // The variable item list (WiFi settings)
     VariableItem* variable_item_ssid; // The variable item (SSID)
     VariableItem* variable_item_password; // The variable item (password)
     TextInput* uart_text_input_ssid; // The text input for the SSID
     TextInput* uart_text_input_password; // The text input for the password
-    TextInput* uart_text_input_dictionary; // The text input for the dictionary
+    TextInput* uart_text_input_query; // The text input for querying information
     //
-    Widget* widget_random_fact; // The text box that displays the random fact
-    Widget* widget_dictionary; // The text box that displays the dictionary
+    Widget* widget_result; // The text box that displays the result
 
     char* uart_text_input_buffer_ssid; // Buffer for the text input (SSID)
     char* uart_text_input_temp_buffer_ssid; // Temporary buffer for the text input (SSID)
@@ -77,9 +65,9 @@ typedef struct {
     char* uart_text_input_temp_buffer_password; // Temporary buffer for the text input (password)
     uint32_t uart_text_input_buffer_size_password; // Size of the text input buffer (password)
 
-    char* uart_text_input_buffer_dictionary; // Buffer for the text input (dictionary)
-    char* uart_text_input_temp_buffer_dictionary; // Temporary buffer for the text input (dictionary)
-    uint32_t uart_text_input_buffer_size_dictionary; // Size of the text input buffer (dictionary)
+    char* uart_text_input_buffer_query; // Buffer for the text input (query)
+    char* uart_text_input_temp_buffer_query; // Temporary buffer for the text input (query)
+    uint32_t uart_text_input_buffer_size_query; // Size of the text input buffer (query)
 } FlipLibraryApp;
 
 // Function to free the resources used by FlipLibraryApp

+ 16 - 1
flip_library/flipper_http/flipper_http.c

@@ -13,6 +13,15 @@ bool flipper_http_append_to_file(
     File* file = storage_file_alloc(storage);
 
     if(start_new_file) {
+        // Delete the file if it already exists
+        if(storage_file_exists(storage, file_path)) {
+            if(!storage_simply_remove_recursive(storage, file_path)) {
+                FURI_LOG_E(HTTP_TAG, "Failed to delete file: %s", file_path);
+                storage_file_free(file);
+                furi_record_close(RECORD_STORAGE);
+                return false;
+            }
+        }
         // Open the file in write mode
         if(!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
             FURI_LOG_E(HTTP_TAG, "Failed to open file for writing: %s", file_path);
@@ -156,10 +165,14 @@ int32_t flipper_http_worker(void* context) {
                     // Write to file if buffer is full
                     if(file_buffer_len >= FILE_BUFFER_SIZE) {
                         if(!flipper_http_append_to_file(
-                               file_buffer, file_buffer_len, false, fhttp.file_path)) {
+                               file_buffer,
+                               file_buffer_len,
+                               fhttp.just_started_bytes,
+                               fhttp.file_path)) {
                             FURI_LOG_E(HTTP_TAG, "Failed to append data to file");
                         }
                         file_buffer_len = 0;
+                        fhttp.just_started_bytes = false;
                     }
                 }
 
@@ -1149,6 +1162,7 @@ void flipper_http_rx_callback(const char* line, void* context) {
         fhttp.state = RECEIVING;
         // for GET request, save data only if it's a bytes request
         fhttp.save_bytes = fhttp.is_bytes_request;
+        fhttp.just_started_bytes = true;
         return;
     } else if(strstr(line, "[POST/SUCCESS]") != NULL) {
         FURI_LOG_I(HTTP_TAG, "POST request succeeded.");
@@ -1157,6 +1171,7 @@ void flipper_http_rx_callback(const char* line, void* context) {
         fhttp.state = RECEIVING;
         // for POST request, save data only if it's a bytes request
         fhttp.save_bytes = fhttp.is_bytes_request;
+        fhttp.just_started_bytes = true;
         return;
     } else if(strstr(line, "[PUT/SUCCESS]") != NULL) {
         FURI_LOG_I(HTTP_TAG, "PUT request succeeded.");

+ 2 - 0
flip_library/flipper_http/flipper_http.h

@@ -74,6 +74,8 @@ typedef struct {
     bool is_bytes_request; // Flag to indicate if the request is for bytes
     bool save_bytes; // Flag to save the received data to a file
     bool save_received_data; // Flag to save the received data to a file
+
+    bool just_started_bytes; // Indicates if bytes data reception has just started
 } FlipperHTTP;
 
 extern FlipperHTTP fhttp;

Некоторые файлы не были показаны из-за большого количества измененных файлов