#include "remote.h" #include "../subghz_remote_app_i.h" #include #include #include #define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 30 #define SUBREM_VIEW_REMOTE_LEFT_OFFSET 10 #define SUBREM_VIEW_REMOTE_RIGHT_OFFSET 0 struct SubRemViewRemote { View* view; SubRemViewRemoteCallback callback; void* context; }; typedef struct { char* labels[SubRemSubKeyNameMaxCount]; SubRemViewRemoteState state; uint8_t pressed_btn; bool is_external; } SubRemViewRemoteModel; void subrem_view_remote_set_callback( SubRemViewRemote* subrem_view_remote, SubRemViewRemoteCallback callback, void* context) { furi_assert(subrem_view_remote); subrem_view_remote->callback = callback; subrem_view_remote->context = context; } void subrem_view_remote_update_data_labels( SubRemViewRemote* subrem_view_remote, SubRemSubFilePreset** subs_presets) { furi_assert(subrem_view_remote); furi_assert(subs_presets); FuriString* labels[SubRemSubKeyNameMaxCount]; SubRemSubFilePreset* sub_preset; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { sub_preset = subs_presets[i]; switch(sub_preset->load_state) { case SubRemLoadSubStateOK: if(!furi_string_empty(sub_preset->label)) { labels[i] = furi_string_alloc_set(sub_preset->label); } else if(!furi_string_empty(sub_preset->file_path)) { labels[i] = furi_string_alloc(); path_extract_filename(sub_preset->file_path, labels[i], true); } else { labels[i] = furi_string_alloc_set("Empty Label"); } break; case SubRemLoadSubStateErrorNoFile: labels[i] = furi_string_alloc_set("[X] Can't open file"); break; case SubRemLoadSubStateErrorFreq: case SubRemLoadSubStateErrorMod: case SubRemLoadSubStateErrorProtocol: labels[i] = furi_string_alloc_set("[X] Error in .sub file"); break; default: labels[i] = furi_string_alloc_set(""); break; } } with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { strncpy( model->labels[i], furi_string_get_cstr(labels[i]), SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); } }, true); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { furi_string_free(labels[i]); } } void subrem_view_remote_set_state( SubRemViewRemote* subrem_view_remote, SubRemViewRemoteState state, uint8_t presed_btn) { furi_assert(subrem_view_remote); with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { model->state = state; model->pressed_btn = presed_btn; }, true); } void subrem_view_remote_set_radio(SubRemViewRemote* subrem_view_remote, bool external) { furi_assert(subrem_view_remote); with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { model->is_external = external; }, true); } void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); // Statusbar canvas_draw_icon(canvas, 0, 0, &I_status_bar); if(model->state == SubRemViewRemoteStateOFF) { canvas_invert_color(canvas); canvas_draw_rbox(canvas, 12, 0, 52 - 12, 13, 2); canvas_invert_color(canvas); canvas_draw_rframe(canvas, 12, 0, 52 - 12, 13, 2); canvas_draw_str_aligned(canvas, 32, 3, AlignCenter, AlignTop, "Preview"); } else { canvas_draw_icon( canvas, 0, 2, (model->is_external) ? &I_External_antenna_20x12 : &I_Internal_antenna_20x12); canvas_draw_icon(canvas, 50, 0, &I_Status_cube_14x14); if(model->state == SubRemViewRemoteStateSending) { canvas_draw_icon_ex(canvas, 52, 3, &I_Pin_arrow_up_7x9, IconRotation90); } } //Icons for Labels const uint8_t list_y = 14; canvas_draw_icon(canvas, 1, list_y + 5, &I_ButtonUp_7x4); canvas_draw_icon(canvas, 1, list_y + 15, &I_ButtonDown_7x4); canvas_draw_icon(canvas, 2, list_y + 23, &I_ButtonLeft_4x7); canvas_draw_icon(canvas, 2, list_y + 33, &I_ButtonRight_4x7); canvas_draw_icon(canvas, 0, list_y + 42, &I_Ok_btn_9x9); //Labels canvas_set_font(canvas, FontSecondary); uint8_t y = list_y; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { elements_text_box( canvas, SUBREM_VIEW_REMOTE_LEFT_OFFSET, y + 2, 64 - SUBREM_VIEW_REMOTE_LEFT_OFFSET - SUBREM_VIEW_REMOTE_RIGHT_OFFSET, 12, AlignLeft, AlignBottom, model->labels[i], false); y += 10; } if(model->state != SubRemViewRemoteStateOFF) { // D-pad 59x62 const uint8_t d_pad_x = 3; const uint8_t d_pad_y = 66; canvas_draw_icon(canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 0 * (20 + 1), &I_up); canvas_draw_icon(canvas, d_pad_x + 0 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_left); canvas_draw_icon(canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_ok); canvas_draw_icon(canvas, d_pad_x + 2 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_right); canvas_draw_icon(canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 2 * (20 + 1), &I_down); if(model->state == SubRemViewRemoteStateSending) { switch(model->pressed_btn) { case SubRemSubKeyNameUp: canvas_draw_icon( canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 0 * (20 + 1), &I_up_hover); break; case SubRemSubKeyNameDown: canvas_draw_icon( canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 2 * (20 + 1), &I_down_hover); break; case SubRemSubKeyNameLeft: canvas_draw_icon( canvas, d_pad_x + 0 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_left_hover); break; case SubRemSubKeyNameRight: canvas_draw_icon( canvas, d_pad_x + 2 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_right_hover); break; case SubRemSubKeyNameOk: canvas_draw_icon( canvas, d_pad_x + 1 * (19 + 1), d_pad_y + 1 * (20 + 1), &I_ok_hover); break; default: break; } } } else { canvas_draw_icon(canvas, 2, 128 - 11, &I_ButtonLeft_4x7); canvas_draw_str_aligned(canvas, 8, 128 - 4, AlignLeft, AlignBottom, "Back"); canvas_draw_icon(canvas, 58, 128 - 11, &I_ButtonRight_4x7); canvas_draw_str_aligned(canvas, 56, 128 - 4, AlignRight, AlignBottom, "Save"); } } bool subrem_view_remote_input(InputEvent* event, void* context) { furi_assert(context); SubRemViewRemote* subrem_view_remote = context; if(event->key == InputKeyBack && event->type == InputTypePress) { bool is_stopping = false; with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { if(model->state == SubRemViewRemoteStateSending) { is_stopping = true; model->pressed_btn = 0; } }, true); //Cant send exit the app inside that with_model,locks the model and the app will hang and not unload! if(is_stopping) subrem_view_remote->callback( SubRemCustomEventViewRemoteForcedStop, subrem_view_remote->context); else subrem_view_remote->callback( SubRemCustomEventViewRemoteBack, subrem_view_remote->context); return true; } // BACK button processing end if(event->key == InputKeyUp && event->type == InputTypePress) { subrem_view_remote->callback( SubRemCustomEventViewRemoteStartUP, subrem_view_remote->context); return true; } else if(event->key == InputKeyDown && event->type == InputTypePress) { subrem_view_remote->callback( SubRemCustomEventViewRemoteStartDOWN, subrem_view_remote->context); return true; } else if(event->key == InputKeyLeft && event->type == InputTypePress) { subrem_view_remote->callback( SubRemCustomEventViewRemoteStartLEFT, subrem_view_remote->context); return true; } else if(event->key == InputKeyRight && event->type == InputTypePress) { subrem_view_remote->callback( SubRemCustomEventViewRemoteStartRIGHT, subrem_view_remote->context); return true; } else if(event->key == InputKeyOk && event->type == InputTypePress) { subrem_view_remote->callback( SubRemCustomEventViewRemoteStartOK, subrem_view_remote->context); return true; } else if(event->type == InputTypeRelease) { subrem_view_remote->callback(SubRemCustomEventViewRemoteStop, subrem_view_remote->context); return true; } return true; } void subrem_view_remote_enter(void* context) { furi_assert(context); } void subrem_view_remote_exit(void* context) { furi_assert(context); } SubRemViewRemote* subrem_view_remote_alloc(void) { SubRemViewRemote* subrem_view_remote = malloc(sizeof(SubRemViewRemote)); // View allocation and configuration subrem_view_remote->view = view_alloc(); view_allocate_model( subrem_view_remote->view, ViewModelTypeLocking, sizeof(SubRemViewRemoteModel)); view_set_context(subrem_view_remote->view, subrem_view_remote); view_set_orientation(subrem_view_remote->view, ViewOrientationVertical); view_set_draw_callback(subrem_view_remote->view, (ViewDrawCallback)subrem_view_remote_draw); view_set_input_callback(subrem_view_remote->view, subrem_view_remote_input); view_set_enter_callback(subrem_view_remote->view, subrem_view_remote_enter); view_set_exit_callback(subrem_view_remote->view, subrem_view_remote_exit); with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { model->state = SubRemViewRemoteStateIdle; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { model->labels[i] = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); strcpy(model->labels[i], ""); } model->pressed_btn = 0; model->is_external = false; }, true); return subrem_view_remote; } void subrem_view_remote_free(SubRemViewRemote* subghz_remote) { furi_assert(subghz_remote); with_view_model( subghz_remote->view, SubRemViewRemoteModel * model, { for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { free(model->labels[i]); } }, true); view_free(subghz_remote->view); free(subghz_remote); } View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote) { furi_assert(subrem_view_remote); return subrem_view_remote->view; }