Skip to content

Commit 6fc0380

Browse files
authored
Add media control view (#11)
* Remove depreciated call * Add blinking when Power is pressed * Add media controller view * Custom buttons icon * Add dolphin deed Simplify sending of power command by using common method
1 parent 86ad252 commit 6fc0380

File tree

8 files changed

+266
-27
lines changed

8 files changed

+266
-27
lines changed

assets/Voldown_Icon_11x11.png

5 KB
Loading

assets/Volup_Icon_11x11.png

4.77 KB
Loading

views/media_controller_view.c

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
#include "xbox_controller.h"
2+
#include "media_controller_view.h"
3+
4+
#include <infrared_worker.h>
5+
#include <infrared_transmit.h>
6+
7+
struct MediaControllerView {
8+
View* view;
9+
NotificationApp* notifications;
10+
};
11+
12+
typedef struct {
13+
bool left_pressed;
14+
bool up_pressed;
15+
bool right_pressed;
16+
bool down_pressed;
17+
bool ok_pressed;
18+
bool back_pressed;
19+
bool connected;
20+
} MediaControllerViewModel;
21+
22+
static void
23+
media_controller_view_draw_icon(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) {
24+
if(dir == CanvasDirectionBottomToTop) {
25+
canvas_draw_icon(canvas, x - 7, y - 5, &I_Volup_Icon_11x11);
26+
} else if(dir == CanvasDirectionTopToBottom) {
27+
canvas_draw_icon(canvas, x - 7, y - 5, &I_Voldown_Icon_11x11);
28+
} else if(dir == CanvasDirectionRightToLeft) {
29+
canvas_draw_triangle(canvas, x, y, 8, 5, CanvasDirectionRightToLeft);
30+
canvas_draw_line(canvas, x - 5, y - 4, x - 5, y + 4);
31+
} else if(dir == CanvasDirectionLeftToRight) {
32+
canvas_draw_triangle(canvas, x - 4, y, 8, 5, CanvasDirectionLeftToRight);
33+
canvas_draw_line(canvas, x + 1, y - 4, x + 1, y + 4);
34+
}
35+
}
36+
37+
static void media_controller_view_draw_arrow_button(
38+
Canvas* canvas,
39+
bool pressed,
40+
uint8_t x,
41+
uint8_t y,
42+
CanvasDirection direction) {
43+
canvas_draw_icon(canvas, x, y, &I_Button_18x18);
44+
if(pressed) {
45+
elements_slightly_rounded_box(canvas, x + 3, y + 2, 13, 13);
46+
canvas_set_color(canvas, ColorWhite);
47+
}
48+
media_controller_view_draw_icon(canvas, x + 11, y + 8, direction);
49+
canvas_set_color(canvas, ColorBlack);
50+
}
51+
52+
static void media_controller_draw_wide_button(
53+
Canvas* canvas,
54+
bool pressed,
55+
uint8_t x,
56+
uint8_t y,
57+
char* text,
58+
const Icon* icon) {
59+
// canvas_draw_icon(canvas, 0, 25, &I_Space_65x18);
60+
elements_slightly_rounded_frame(canvas, x, y, 64, 17);
61+
if(pressed) {
62+
elements_slightly_rounded_box(canvas, x + 2, y + 2, 60, 13);
63+
canvas_set_color(canvas, ColorWhite);
64+
}
65+
canvas_draw_icon(canvas, x + 11, y + 4, icon);
66+
elements_multiline_text_aligned(canvas, x + 28, y + 12, AlignLeft, AlignBottom, text);
67+
canvas_set_color(canvas, ColorBlack);
68+
}
69+
70+
static void media_controller_view_draw_callback(Canvas* canvas, void* context) {
71+
furi_assert(context);
72+
MediaControllerViewModel* model = context;
73+
74+
canvas_set_font(canvas, FontPrimary);
75+
elements_multiline_text_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Media");
76+
77+
canvas_set_font(canvas, FontSecondary);
78+
79+
canvas_draw_icon(canvas, 0, 12, &I_Pin_back_arrow_10x8);
80+
canvas_draw_str(canvas, 12, 20, "Hold");
81+
82+
media_controller_view_draw_arrow_button(
83+
canvas, model->up_pressed, 23, 74, CanvasDirectionBottomToTop);
84+
media_controller_view_draw_arrow_button(
85+
canvas, model->down_pressed, 23, 110, CanvasDirectionTopToBottom);
86+
media_controller_view_draw_arrow_button(
87+
canvas, model->left_pressed, 0, 92, CanvasDirectionRightToLeft);
88+
media_controller_view_draw_arrow_button(
89+
canvas, model->right_pressed, 46, 92, CanvasDirectionLeftToRight);
90+
91+
int buttons_post = 30;
92+
// Ok
93+
media_controller_draw_wide_button(
94+
canvas, model->ok_pressed, 0, buttons_post, "Play", &I_Ok_btn_9x9);
95+
// Back
96+
media_controller_draw_wide_button(
97+
canvas, model->back_pressed, 0, buttons_post + 19, "Mute", &I_Pin_back_arrow_10x8);
98+
}
99+
100+
static void
101+
media_controller_view_process(MediaControllerView* media_controller_view, InputEvent* event) {
102+
with_view_model(
103+
media_controller_view->view,
104+
MediaControllerViewModel * model,
105+
{
106+
if(event->type == InputTypePress || event->type == InputTypeRepeat) {
107+
bool repeat = event->type == InputTypeRepeat;
108+
if(event->key == InputKeyUp) {
109+
model->up_pressed = true;
110+
send_xbox_ir(0xEF10, media_controller_view->notifications, repeat);
111+
} else if(event->key == InputKeyDown) {
112+
model->down_pressed = true;
113+
send_xbox_ir(0xEE11, media_controller_view->notifications, repeat);
114+
} else if(event->key == InputKeyLeft) {
115+
model->left_pressed = true;
116+
send_xbox_ir(0xE41B, media_controller_view->notifications, repeat);
117+
} else if(event->key == InputKeyRight) {
118+
model->right_pressed = true;
119+
send_xbox_ir(0xE51A, media_controller_view->notifications, repeat);
120+
} else if(event->key == InputKeyOk) {
121+
model->ok_pressed = true;
122+
send_xbox_ir(0x8F70, media_controller_view->notifications, repeat);
123+
} else if(event->key == InputKeyBack) {
124+
model->back_pressed = true;
125+
send_xbox_ir(0xF10E, media_controller_view->notifications, repeat);
126+
}
127+
} else if(event->type == InputTypeRelease) {
128+
if(event->key == InputKeyUp) {
129+
model->up_pressed = false;
130+
} else if(event->key == InputKeyDown) {
131+
model->down_pressed = false;
132+
} else if(event->key == InputKeyLeft) {
133+
model->left_pressed = false;
134+
} else if(event->key == InputKeyRight) {
135+
model->right_pressed = false;
136+
} else if(event->key == InputKeyOk) {
137+
model->ok_pressed = false;
138+
} else if(event->key == InputKeyBack) {
139+
model->back_pressed = false;
140+
}
141+
}
142+
},
143+
true);
144+
}
145+
146+
static bool media_controller_view_input_callback(InputEvent* event, void* context) {
147+
furi_assert(context);
148+
MediaControllerView* media_controller_view = context;
149+
bool consumed = false;
150+
151+
if(event->type == InputTypeLong && event->key == InputKeyBack) {
152+
// LONG KEY BACK PRESS HANDLER
153+
} else {
154+
media_controller_view_process(media_controller_view, event);
155+
consumed = true;
156+
}
157+
158+
return consumed;
159+
}
160+
161+
MediaControllerView* media_controller_view_alloc(NotificationApp* notifications) {
162+
MediaControllerView* media_controller_view = malloc(sizeof(MediaControllerView));
163+
media_controller_view->view = view_alloc();
164+
media_controller_view->notifications = notifications;
165+
view_set_orientation(media_controller_view->view, ViewOrientationVertical);
166+
view_set_context(media_controller_view->view, media_controller_view);
167+
view_allocate_model(
168+
media_controller_view->view, ViewModelTypeLocking, sizeof(MediaControllerViewModel));
169+
view_set_draw_callback(media_controller_view->view, media_controller_view_draw_callback);
170+
view_set_input_callback(media_controller_view->view, media_controller_view_input_callback);
171+
172+
return media_controller_view;
173+
}
174+
175+
void media_controller_view_free(MediaControllerView* media_controller_view) {
176+
furi_assert(media_controller_view);
177+
view_free(media_controller_view->view);
178+
free(media_controller_view);
179+
}
180+
181+
View* media_controller_view_get_view(MediaControllerView* media_controller_view) {
182+
furi_assert(media_controller_view);
183+
return media_controller_view->view;
184+
}
185+
186+
void media_controller_view_set_connected_status(
187+
MediaControllerView* media_controller_view,
188+
bool connected) {
189+
furi_assert(media_controller_view);
190+
with_view_model(
191+
media_controller_view->view,
192+
MediaControllerViewModel * model,
193+
{ model->connected = connected; },
194+
true);
195+
}

views/media_controller_view.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#pragma once
2+
3+
#include <gui/view.h>
4+
#include <furi.h>
5+
#include <gui/elements.h>
6+
#include <xc_icons.h>
7+
#include <notification/notification.h>
8+
#include <notification/notification_messages.h>
9+
10+
typedef struct MediaControllerView MediaControllerView;
11+
12+
MediaControllerView* media_controller_view_alloc();
13+
14+
void media_controller_view_free(MediaControllerView* media_controller_view);
15+
16+
View* media_controller_view_get_view(MediaControllerView* media_controller_view);
17+
18+
void media_controller_view_set_connected_status(
19+
MediaControllerView* media_controller_view,
20+
bool connected);

views/xbox_controller_view.c

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "xbox_controller.h"
12
#include "xbox_controller_view.h"
23

34
#include <infrared_worker.h>
@@ -98,24 +99,6 @@ static void xbox_controller_view_draw_callback(Canvas* canvas, void* context) {
9899
canvas, model->back_pressed, 0, buttons_post + 19, "B", &I_Pin_back_arrow_10x8);
99100
}
100101

101-
const NotificationSequence sequence_blink_purple_50 = {
102-
&message_red_255,
103-
&message_blue_255,
104-
&message_delay_50,
105-
NULL,
106-
};
107-
108-
void send_xbox_ir(uint32_t command, NotificationApp* notifications, bool repeat) {
109-
InfraredMessage* message = malloc(sizeof(InfraredMessage));
110-
message->protocol = InfraredProtocolNECext;
111-
message->address = 0xD880;
112-
message->command = command;
113-
message->repeat = repeat;
114-
notification_message(notifications, &sequence_blink_purple_50);
115-
infrared_send(message, 2);
116-
free(message);
117-
}
118-
119102
static void
120103
xbox_controller_view_process(XboxControllerView* xbox_controller_view, InputEvent* event) {
121104
with_view_model(

views/xbox_controller_view.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <notification/notification.h>
88
#include <notification/notification_messages.h>
99

10-
1110
typedef struct XboxControllerView XboxControllerView;
1211

1312
XboxControllerView* xbox_controller_view_alloc();

xbox_controller.c

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
enum XboxControllerSubmenuIndex {
99
XboxControllerSubmenuIndexXboxOne,
10+
XboxControllerSubmenuIndexMediaController,
1011
XboxControllerSubmenuIndexPower
1112
};
1213

@@ -26,14 +27,11 @@ void usb_hid_submenu_callback(void* context, uint32_t index) {
2627
if(index == XboxControllerSubmenuIndexXboxOne) {
2728
app->view_id = UsbHidViewXboxController;
2829
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewXboxController);
30+
} else if(index == XboxControllerSubmenuIndexMediaController) {
31+
app->view_id = UsbHidViewMediaController;
32+
view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMediaController);
2933
} else if(index == XboxControllerSubmenuIndexPower) {
30-
InfraredMessage* message = malloc(sizeof(InfraredMessage));
31-
message->protocol = InfraredProtocolNECext;
32-
message->address = 0xD880;
33-
message->command = 0xD02F;
34-
message->repeat = false;
35-
infrared_send(message, 2);
36-
free(message);
34+
send_xbox_ir(0xD02F, app->notifications, false);
3735
}
3836
}
3937

@@ -56,7 +54,6 @@ XboxController* xbox_controller_app_alloc() {
5654
app->notifications = furi_record_open(RECORD_NOTIFICATION);
5755
app->view_dispatcher = view_dispatcher_alloc();
5856

59-
view_dispatcher_enable_queue(app->view_dispatcher);
6057
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
6158

6259
// Submenu view
@@ -65,6 +62,12 @@ XboxController* xbox_controller_app_alloc() {
6562

6663
submenu_add_item(
6764
app->submenu, "Xbox One", XboxControllerSubmenuIndexXboxOne, usb_hid_submenu_callback, app);
65+
submenu_add_item(
66+
app->submenu,
67+
"Media",
68+
XboxControllerSubmenuIndexMediaController,
69+
usb_hid_submenu_callback,
70+
app);
6871
submenu_add_item(
6972
app->submenu, "Power", XboxControllerSubmenuIndexPower, usb_hid_submenu_callback, app);
7073
view_set_previous_callback(submenu_get_view(app->submenu), usb_hid_exit);
@@ -80,6 +83,15 @@ XboxController* xbox_controller_app_alloc() {
8083
UsbHidViewXboxController,
8184
xbox_controller_view_get_view(app->xbox_controller_view));
8285

86+
// Media control view
87+
app->media_controller_view = media_controller_view_alloc(app->notifications);
88+
view_set_previous_callback(
89+
media_controller_view_get_view(app->media_controller_view), usb_hid_exit_confirm_view);
90+
view_dispatcher_add_view(
91+
app->view_dispatcher,
92+
UsbHidViewMediaController,
93+
media_controller_view_get_view(app->media_controller_view));
94+
8395
// Switch to Xbox Controller by default
8496
app->view_id = UsbHidViewSubmenu;
8597
view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id);
@@ -98,6 +110,8 @@ void xbox_controller_app_free(XboxController* app) {
98110
submenu_free(app->submenu);
99111
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewXboxController);
100112
xbox_controller_view_free(app->xbox_controller_view);
113+
view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMediaController);
114+
media_controller_view_free(app->media_controller_view);
101115
view_dispatcher_free(app->view_dispatcher);
102116

103117
// Close records
@@ -120,3 +134,22 @@ int32_t xbox_controller_app(void* p) {
120134

121135
return 0;
122136
}
137+
138+
const NotificationSequence sequence_blink_purple_50 = {
139+
&message_red_255,
140+
&message_blue_255,
141+
&message_delay_50,
142+
NULL,
143+
};
144+
145+
void send_xbox_ir(uint32_t command, NotificationApp* notifications, bool repeat) {
146+
InfraredMessage* message = malloc(sizeof(InfraredMessage));
147+
message->protocol = InfraredProtocolNECext;
148+
message->address = 0xD880;
149+
message->command = command;
150+
message->repeat = repeat;
151+
notification_message(notifications, &sequence_blink_purple_50);
152+
infrared_send(message, 2);
153+
free(message);
154+
dolphin_deed(DolphinDeedIrSend);
155+
}

xbox_controller.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
#include <gui/modules/dialog_ex.h>
1212

1313
#include "views/xbox_controller_view.h"
14+
#include "views/media_controller_view.h"
1415
#include "xc_icons.h"
1516

17+
#include <dolphin/dolphin.h>
18+
1619
// this should be used as global state
1720
// we can store different things here
1821
typedef struct {
@@ -22,11 +25,17 @@ typedef struct {
2225
Submenu* submenu;
2326
DialogEx* dialog;
2427
XboxControllerView* xbox_controller_view;
28+
MediaControllerView* media_controller_view;
2529
uint32_t view_id;
2630
} XboxController;
2731

2832
typedef enum {
2933
UsbHidViewSubmenu,
3034
UsbHidViewXboxController,
35+
UsbHidViewMediaController,
3136
UsbHidViewExitConfirm,
3237
} UsbHidView;
38+
39+
extern const NotificationSequence sequence_blink_purple_50;
40+
41+
void send_xbox_ir(uint32_t command, NotificationApp* notifications, bool repeat);

0 commit comments

Comments
 (0)