Significant Jellyfin API work on the PKJS side

This commit is contained in:
RandyTheSilly committed 2026-10-09 20:41:33 -04:00
1 parent 317241d294
commit 79045d8b4b
5 files changed
+192 -47

No files matched your search

+204
View File
@@ -0,0 +1,204 @@
#include "custom_status_bar.h"
#include "sdk_mod.h"
#include <pebble.h>
typedef enum {
NAV_SCOPE_MAIN = 0,
NAV_SCOPE_ALPHA = 1,
NAV_SCOPE_ARTISTS = 2,
NAV_SCOPE_ALBUMS = 3,
NAV_SCOPE_ALBUM_TRACKS = 4,
NAV_SCOPE_PLAYLISTS = 5,
NAV_SCOPE_PLAYLIST_TRACKS = 6,
NAV_SCOPE_NOW_PLAYING = 7
} NavScope;
// layer-age
static Window *s_main_window;
static CustomStatusBarLayer *s_status_bar_layer;
static Layer *s_divider_layer;
static MenuLayer *s_menu_layer;
// globals
static bool s_pkjs_ready = false;
static NavScope s_current_menu_scope = NAV_SCOPE_MAIN;
// resources
static GFont s_font_chicago;
// constants
#define BAR_HEIGHT 20
#ifdef PBL_RECT
#define MARGIN_X 4
#define MARGIN_Y 4
#else
#define MARGIN_X 0
#if PBL_DISPLAY_WIDTH < 260
#define MARGIN_Y 4
#else
#define MARGIN_Y 5
#endif
#endif
static const GRect s_menu_grect = GRect(MARGIN_X, BAR_HEIGHT + MARGIN_Y, PBL_DISPLAY_WIDTH - (MARGIN_X * 2), PBL_DISPLAY_HEIGHT - (MARGIN_Y * 2));
static const char *s_main_menu_options[3] = {"Artists", "Playlists", "Now Playing"};
////////////////////// PKJS //////////////////////
static void inbox_received_handler(DictionaryIterator *iter, void *context) {
Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_PKJS_READY);
if (ready_tuple) {
s_pkjs_ready = true;
return;
}
}
static void to_pkjs_scope_change(NavScope scope, const char *jfId, bool shuffleInScope) {
if (!s_pkjs_ready) {
return;
}
// send scope to return data for (PKJS side should track last scope and only send new data if the new scope differs)
DictionaryIterator *out;
AppMessageResult result = app_message_outbox_begin(&out);
if (result != APP_MSG_OK) {
return;
}
dict_write_uint8(out, MESSAGE_KEY_OUT_MENU_NAV_SCOPE, scope);
if (shuffleInScope) {
// tell PKJS to shuffle if a shuffle option was clicked
dict_write_uint8(out, MESSAGE_KEY_OUT_SHUFFLE_MODE, shuffleInScope); // if true, PKJS side shuffles IDs in scope and passes them to JF API
} else if (jfId) {
// otherwise, send the selected jfId, if present;
// for artists/albums/playlists, determines next data set returned to C;
// for tracks, starts sequential playback (sequential relative to entire library unless scope is playlist)
dict_write_cstring(out, MESSAGE_KEY_OUT_JFID, jfId);
}
result = app_message_outbox_send();
if (result != APP_MSG_OK) {
return;
}
}
static uint16_t menu_get_num_rows(MenuLayer *menu_layer, uint16_t section_index, void *context) {
switch (s_current_menu_scope) {
case NAV_SCOPE_MAIN:
return 3;
case NAV_SCOPE_ALPHA:
case NAV_SCOPE_ARTISTS:
case NAV_SCOPE_ALBUMS:
case NAV_SCOPE_ALBUM_TRACKS:
case NAV_SCOPE_PLAYLISTS:
default:
return 99;
}
}
static void menu_draw_row(GContext *ctx, const Layer *cell_layer, MenuIndex *cell_index, void *context) {
switch (s_current_menu_scope) {
case NAV_SCOPE_MAIN:
custom_menu_cell_title_draw(ctx, cell_layer, s_main_menu_options[cell_index->row], NULL, s_font_chicago, MARGIN_X);
break;
case NAV_SCOPE_ALPHA:
case NAV_SCOPE_ARTISTS:
case NAV_SCOPE_ALBUMS:
case NAV_SCOPE_ALBUM_TRACKS:
case NAV_SCOPE_PLAYLISTS:
default:
return;
}
}
static void menu_select_click(struct MenuLayer *menu_layer, MenuIndex *clicked_index, void *context) {
switch (s_current_menu_scope) {
case NAV_SCOPE_MAIN:
switch (clicked_index->row) {
case 0:
to_pkjs_scope_change(NAV_SCOPE_ALPHA, NULL, false);
break;
case 1:
to_pkjs_scope_change(NAV_SCOPE_PLAYLISTS, NULL, false);
break;
default:
to_pkjs_scope_change(NAV_SCOPE_NOW_PLAYING, NULL, false); // TODO
}
return;
case NAV_SCOPE_ALPHA:
case NAV_SCOPE_ARTISTS:
case NAV_SCOPE_ALBUMS:
case NAV_SCOPE_ALBUM_TRACKS:
case NAV_SCOPE_PLAYLISTS:
default:
return;
}
}
static void menu_selection_changed(struct MenuLayer *menu_layer, MenuIndex new_index, MenuIndex old_index, void *context) {
speaker_play_tone(200, 10, 80, SpeakerWaveformSine);
}
static void divider_layer_update_proc(Layer *layer, GContext *ctx) {
graphics_context_set_fill_color(ctx, GColorBlack);
graphics_fill_rect(ctx, layer_get_bounds(layer), 0, GCornerNone);
}
static void main_window_load() {
Layer *main_window_layer = window_get_root_layer(s_main_window);
s_menu_layer = menu_layer_create(s_menu_grect);
menu_layer_set_callbacks(s_menu_layer, NULL, (MenuLayerCallbacks){.get_num_rows = menu_get_num_rows, .draw_row = menu_draw_row, .select_click = menu_select_click, .selection_changed = menu_selection_changed});
menu_layer_pad_bottom_enable(s_menu_layer, false);
menu_layer_set_click_config_onto_window(s_menu_layer, s_main_window);
#ifdef PBL_ROUND
menu_layer_set_center_focused(s_menu_layer, false);
#endif
layer_add_child(main_window_layer, menu_layer_get_layer(s_menu_layer));
s_status_bar_layer = custom_status_bar_layer_create(BAR_HEIGHT, GColorWhite, 15);
custom_status_bar_layer_set_text(s_status_bar_layer, CSB_TEXT_CENTER, "jellyPod");
custom_status_bar_layer_set_text_font(s_status_bar_layer, CSB_TEXT_CENTER, s_font_chicago);
#ifdef PBL_RECT
custom_status_bar_layer_set_text(s_status_bar_layer, CSB_TEXT_LEFT, " | |");
custom_status_bar_layer_set_text(s_status_bar_layer, CSB_TEXT_RIGHT, "[// ]- ");
#endif
layer_add_child(main_window_layer, s_status_bar_layer);
s_divider_layer = layer_create(GRect(MARGIN_X, BAR_HEIGHT + (MARGIN_Y / 2), PBL_DISPLAY_WIDTH - (MARGIN_X * 2), 1));
layer_set_update_proc(s_divider_layer, divider_layer_update_proc);
layer_add_child(main_window_layer, s_divider_layer);
}
static void main_window_unload() {
layer_destroy(s_divider_layer);
custom_status_bar_layer_destroy(s_status_bar_layer);
menu_layer_destroy(s_menu_layer);
}
static void init() {
// initialize pkjs
app_message_register_inbox_received(inbox_received_handler);
app_message_open(4096, 1024); // TODO adjust sizes
// load font
s_font_chicago = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_CHICAGO_16));
// create and push window
s_main_window = window_create();
window_set_window_handlers(
s_main_window,
(WindowHandlers){.load = main_window_load, .unload = main_window_unload});
window_stack_push(s_main_window, false);
app_touch_navigation_enable(true);
}
static void deinit() {
window_destroy(s_main_window);
fonts_unload_custom_font(s_font_chicago);
}
int main(void) {
init();
app_event_loop();
deinit();
}