This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch main
in repository eradio.

View the commit online.

commit 7c7b608b02ce95854a05dd4fcdca45e9100b0b70
Author: politebot <[email protected]>
AuthorDate: Fri Oct 10 14:39:56 2025 -0500

    Thumbnails
---
 src/main.c | 250 ++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 171 insertions(+), 79 deletions(-)

diff --git a/src/main.c b/src/main.c
index c7d829e..6ff0b53 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,7 +2,6 @@
 #include <Ecore_Evas.h>
 #include <Emotion.h>
 #include <Ecore_Con.h>
-#include <Ethumb_Client.h>
 #include <libxml/parser.h>
 #include <libxml/xpath.h>
 
@@ -21,16 +20,47 @@ typedef struct _AppData
    Evas_Object *emotion;
    Evas_Object *search_entry;
    Evas_Object *search_hoversel;
+   Evas_Object *play_pause_btn;
    Eina_List *stations;
+   Eina_Bool playing;
 } AppData;
 
+typedef enum _Download_Type
+{
+   DOWNLOAD_TYPE_STATIONS,
+   DOWNLOAD_TYPE_ICON
+} Download_Type;
+
+typedef struct _Download_Context
+{
+   Download_Type type;
+   AppData *ad;
+} Download_Context;
+
+typedef struct _Station_Download_Context
+{
+   Download_Context base;
+   xmlParserCtxtPtr ctxt;
+} Station_Download_Context;
+
+typedef struct _Icon_Download_Context
+{
+   Download_Context base;
+   Elm_Object_Item *list_item;
+   Eina_Binbuf *image_data;
+} Icon_Download_Context;
+
+
 static void _win_del_cb(void *data, Evas_Object *obj, void *event_info);
 static void _list_item_selected_cb(void *data, Evas_Object *obj, void *event_info);
-static void _play_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
-static void _pause_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
+static void _play_pause_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
 static void _stop_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
 static void _hoversel_item_selected_cb(void *data, Evas_Object *obj, void *event_info);
 static void _search_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info);
+static void _search_entry_activated_cb(void *data, Evas_Object *obj, void *event_info);
+static Eina_Bool _url_data_cb(void *data, int type, void *event_info);
+static Eina_Bool _url_complete_cb(void *data, int type, void *event_info);
+
 
 static void
 _win_del_cb(void *data, Evas_Object *obj, void *event_info)
@@ -68,6 +98,7 @@ _list_item_selected_cb(void *data, Evas_Object *obj, void *event_info)
    AppData *ad = data;
    Elm_Object_Item *it = event_info;
    Station *st = elm_object_item_data_get(it);
+   Evas_Object *ic;
 
    if (!st) return;
 
@@ -77,34 +108,28 @@ _list_item_selected_cb(void *data, Evas_Object *obj, void *event_info)
      {
         emotion_object_file_set(ad->emotion, st->url);
         emotion_object_play_set(ad->emotion, EINA_TRUE);
+        ad->playing = EINA_TRUE;
+        ic = elm_object_part_content_get(ad->play_pause_btn, "icon");
+        elm_icon_standard_set(ic, "media-playback-pause");
      }
 }
 
-
-
 static void
-_play_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
+_play_pause_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
 {
    AppData *ad = data;
-   emotion_object_play_set(ad->emotion, EINA_TRUE);
+   Evas_Object *ic;
+
+   ad->playing = !ad->playing;
+   emotion_object_play_set(ad->emotion, ad->playing);
+
+   ic = elm_object_part_content_get(ad->play_pause_btn, "icon");
+   if (ad->playing)
+     elm_icon_standard_set(ic, "media-playback-pause");
+   else
+     elm_icon_standard_set(ic, "media-playback-start");
 }
 
-static void
-_pause_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
-{
-   AppData *ad = data;
-   emotion_object_play_set(ad->emotion, EINA_FALSE);
-}
-
-static Eina_Bool _url_progress_cb(void *data, int type, void *event_info);
-static Eina_Bool _url_complete_cb(void *data, int type, void *event_info);
-
-typedef struct _Download_Context
-{
-   AppData *ad;
-   xmlParserCtxtPtr ctxt;
-} Download_Context;
-
 static void
 _search_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
 {
@@ -113,12 +138,13 @@ _search_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
    const char *search_type = elm_object_text_get(ad->search_hoversel);
    char url_str[1024];
    Ecore_Con_Url *url;
-   Download_Context *d_ctx;
+   Station_Download_Context *d_ctx;
 
    if (!search_term || !search_term[0]) return;
 
-   d_ctx = calloc(1, sizeof(Download_Context));
-   d_ctx->ad = ad;
+   d_ctx = calloc(1, sizeof(Station_Download_Context));
+   d_ctx->base.type = DOWNLOAD_TYPE_STATIONS;
+   d_ctx->base.ad = ad;
 
    snprintf(url_str, sizeof(url_str), "http://de2.api.radio-browser.info/xml/stations/search?%s=%s",
             search_type, search_term);
@@ -129,19 +155,18 @@ _search_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
    ecore_con_url_get(url);
 }
 
-static Eina_Bool
-_url_progress_cb(void *data, int type, void *event_info)
+static void
+_search_entry_activated_cb(void *data, Evas_Object *obj, void *event_info)
 {
-   return ECORE_CALLBACK_PASS_ON;
+   _search_btn_clicked_cb(data, obj, event_info);
 }
 
-static Eina_Bool
-_url_data_cb(void *data, int type, void *event_info)
+static void
+_handle_station_list_data(Ecore_Con_Event_Url_Data *url_data)
 {
-    Ecore_Con_Event_Url_Data *url_data = event_info;
-    Download_Context *d_ctx = ecore_con_url_data_get(url_data->url_con);
+    Station_Download_Context *d_ctx = ecore_con_url_data_get(url_data->url_con);
 
-    if (!d_ctx) return ECORE_CALLBACK_PASS_ON;
+    if (!d_ctx) return;
 
     if (!d_ctx->ctxt)
       {
@@ -151,40 +176,60 @@ _url_data_cb(void *data, int type, void *event_info)
       }
     else
       xmlParseChunk(d_ctx->ctxt, (const char *)url_data->data, url_data->size, 0);
-
-    return ECORE_CALLBACK_PASS_ON;
 }
 
 static void
-_thumb_load_error_cb(void *data, Evas_Object *obj, void *event_info)
+_handle_icon_data(Ecore_Con_Event_Url_Data *url_data)
 {
-   fprintf(stderr, "ERROR: could not load thumb\n");
+    Icon_Download_Context *icon_ctx = ecore_con_url_data_get(url_data->url_con);
+
+    if (!icon_ctx) return;
+
+    if (!icon_ctx->image_data)
+      icon_ctx->image_data = eina_binbuf_new();
+
+    eina_binbuf_append_length(icon_ctx->image_data, (const unsigned char *)url_data->data, url_data->size);
 }
 
-static Eina_Bool
-_url_complete_cb(void *data, int type, void *event_info)
+static void
+_handle_icon_complete(Ecore_Con_Event_Url_Complete *ev)
 {
-    Ecore_Con_Event_Url_Complete *ev = event_info;
-    Download_Context *d_ctx = ecore_con_url_data_get(ev->url_con);
+    Icon_Download_Context *icon_ctx = ecore_con_url_data_get(ev->url_con);
+
+    if (icon_ctx && icon_ctx->image_data)
+    {
+        Elm_Object_Item *it = icon_ctx->list_item;
+        Evas_Object *icon = elm_object_item_part_content_get(it, "start");
+        const char *ext = strrchr(ecore_con_url_url_get(ev->url_con), '.');
+        if (ext) ext++;
+
+        elm_image_memfile_set(icon, eina_binbuf_string_get(icon_ctx->image_data), eina_binbuf_length_get(icon_ctx->image_data), (char *)ext, NULL);
+    }
+
+    if (icon_ctx)
+    {
+       if (icon_ctx->image_data) eina_binbuf_free(icon_ctx->image_data);
+       free(icon_ctx);
+    }
+}
+
+static void
+_handle_station_list_complete(Ecore_Con_Event_Url_Complete *ev)
+{
+    Station_Download_Context *d_ctx = ecore_con_url_data_get(ev->url_con);
     AppData *ad;
     xmlDocPtr doc;
     xmlXPathContextPtr xpathCtx;
     xmlXPathObjectPtr xpathObj;
 
-    if (!d_ctx)
-      {
-         ecore_con_url_free(ev->url_con);
-         return ECORE_CALLBACK_PASS_ON;
-      }
+    if (!d_ctx) return;
 
-    ad = d_ctx->ad;
+    ad = d_ctx->base.ad;
 
     if (!d_ctx->ctxt)
       {
-         // In case of empty reply, the data callback is not called
          free(d_ctx);
-         ecore_con_url_free(ev->url_con);
-         return ECORE_CALLBACK_PASS_ON;
+         return;
       }
 
     xmlParseChunk(d_ctx->ctxt, "", 0, 1);
@@ -195,18 +240,15 @@ _url_complete_cb(void *data, int type, void *event_info)
     if (doc == NULL)
     {
         printf("Error: could not parse XML\n");
-        ecore_con_url_free(ev->url_con);
-        return ECORE_CALLBACK_PASS_ON;
+        return;
     }
 
-
     xpathCtx = xmlXPathNewContext(doc);
     if (xpathCtx == NULL)
     {
         printf("Error: could not create new XPath context\n");
         xmlFreeDoc(doc);
-        ecore_con_url_free(ev->url_con);
-        return ECORE_CALLBACK_PASS_ON;
+        return;
     }
 
     xpathObj = xmlXPathEvalExpression((xmlChar *)"//station", xpathCtx);
@@ -215,8 +257,7 @@ _url_complete_cb(void *data, int type, void *event_info)
         printf("Error: could not evaluate xpath _expression_\n");
         xmlXPathFreeContext(xpathCtx);
         xmlFreeDoc(doc);
-        ecore_con_url_free(ev->url_con);
-        return ECORE_CALLBACK_PASS_ON;
+        return;
     }
 
     elm_list_clear(ad->list);
@@ -256,29 +297,77 @@ _url_complete_cb(void *data, int type, void *event_info)
           }
         ad->stations = eina_list_append(ad->stations, st);
 
-        Evas_Object *thumb = elm_thumb_add(ad->win);
-        evas_object_smart_callback_add(thumb, "load,error", _thumb_load_error_cb, NULL);
+        Evas_Object *icon = elm_icon_add(ad->win);
+        elm_icon_standard_set(icon, "radio");
+        Elm_Object_Item *li = elm_list_item_append(ad->list, st->name, icon, NULL, _list_item_selected_cb, ad);
+        elm_object_item_data_set(li, st);
+
         if (st->favicon && st->favicon[0])
-          elm_thumb_file_set(thumb, st->favicon, NULL);
-        elm_list_item_append(ad->list, st->name, thumb, NULL, NULL, st);
+          {
+             Ecore_Con_Url *url = ""
+             Icon_Download_Context *icon_ctx = calloc(1, sizeof(Icon_Download_Context));
+             icon_ctx->base.type = DOWNLOAD_TYPE_ICON;
+             icon_ctx->base.ad = ad;
+             icon_ctx->list_item = li;
+             ecore_con_url_data_set(url, icon_ctx);
+             ecore_con_url_get(url);
+          }
     }
     elm_list_go(ad->list);
 
     xmlXPathFreeObject(xpathObj);
     xmlXPathFreeContext(xpathCtx);
     xmlFreeDoc(doc);
-    ecore_con_url_free(ev->url_con);
+}
 
+static Eina_Bool
+_url_data_cb(void *data, int type, void *event_info)
+{
+    Ecore_Con_Event_Url_Data *url_data = event_info;
+    Download_Context *ctx = ecore_con_url_data_get(url_data->url_con);
+
+    if (!ctx) return ECORE_CALLBACK_PASS_ON;
+
+    if (ctx->type == DOWNLOAD_TYPE_STATIONS)
+      _handle_station_list_data(url_data);
+    else if (ctx->type == DOWNLOAD_TYPE_ICON)
+      _handle_icon_data(url_data);
+
+    return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_url_complete_cb(void *data, int type, void *event_info)
+{
+    Ecore_Con_Event_Url_Complete *ev = event_info;
+    Download_Context *ctx = ecore_con_url_data_get(ev->url_con);
+
+    if (!ctx)
+      {
+         ecore_con_url_free(ev->url_con);
+         return ECORE_CALLBACK_PASS_ON;
+      }
+
+    if (ctx->type == DOWNLOAD_TYPE_STATIONS)
+      _handle_station_list_complete(ev);
+    else if (ctx->type == DOWNLOAD_TYPE_ICON)
+      _handle_icon_complete(ev);
+
+    ecore_con_url_free(ev->url_con);
     return ECORE_CALLBACK_PASS_ON;
 }
 
 static void
 _stop_btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
-
 {
    AppData *ad = data;
+   Evas_Object *ic;
+
    emotion_object_play_set(ad->emotion, EINA_FALSE);
    emotion_object_position_set(ad->emotion, 0.0);
+   ad->playing = EINA_FALSE;
+   ic = elm_object_part_content_get(ad->play_pause_btn, "icon");
+   elm_icon_standard_set(ic, "media-playback-start");
 }
 
 static void
@@ -300,11 +389,11 @@ elm_main(int argc, char **argv)
         int dpi = 0;
         ecore_evas_screen_dpi_get(ee, NULL, &dpi);
         if (dpi >= 192)
-          elm_config_scale_set(2.0);
+          elm_config_scale_set(4.0);
      }
 
+
    ecore_con_init();
-   ethumb_client_init();
 
    elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
 
@@ -339,6 +428,7 @@ elm_main(int argc, char **argv)
    elm_object_part_text_set(ad.search_entry, "guide", "Search for stations...");
    elm_box_pack_end(search_hbox, ad.search_entry);
    evas_object_show(ad.search_entry);
+   elm_object_focus_set(ad.search_entry, EINA_TRUE);
 
    ad.search_hoversel = elm_hoversel_add(ad.win);
    elm_hoversel_hover_parent_set(ad.search_hoversel, ad.win);
@@ -372,32 +462,34 @@ elm_main(int argc, char **argv)
    elm_box_pack_end(box, controls_hbox);
    evas_object_show(controls_hbox);
 
-   Evas_Object *play_btn = elm_button_add(ad.win);
-   elm_object_text_set(play_btn, "▶");
-   elm_box_pack_end(controls_hbox, play_btn);
-   evas_object_show(play_btn);
+   Evas_Object *ic;
 
-   Evas_Object *pause_btn = elm_button_add(ad.win);
-   elm_object_text_set(pause_btn, "⏸");
-   elm_box_pack_end(controls_hbox, pause_btn);
-   evas_object_show(pause_btn);
+   ad.play_pause_btn = elm_button_add(ad.win);
+   ic = elm_icon_add(ad.play_pause_btn);
+   elm_icon_standard_set(ic, "media-playback-start");
+   evas_object_size_hint_min_set(ic, 40, 40);
+   elm_object_part_content_set(ad.play_pause_btn, "icon", ic);
+   elm_box_pack_end(controls_hbox, ad.play_pause_btn);
+   evas_object_show(ad.play_pause_btn);
 
    Evas_Object *stop_btn = elm_button_add(ad.win);
-   elm_object_text_set(stop_btn, "⏹");
+   ic = elm_icon_add(stop_btn);
+   elm_icon_standard_set(ic, "media-playback-stop");
+   evas_object_size_hint_min_set(ic, 40, 40);
+   elm_object_part_content_set(stop_btn, "icon", ic);
    elm_box_pack_end(controls_hbox, stop_btn);
    evas_object_show(stop_btn);
 
-   evas_object_smart_callback_add(ad.list, "selected", _list_item_selected_cb, &ad);
-   evas_object_smart_callback_add(play_btn, "clicked", _play_btn_clicked_cb, &ad);
-   evas_object_smart_callback_add(pause_btn, "clicked", _pause_btn_clicked_cb, &ad);
+   evas_object_smart_callback_add(ad.play_pause_btn, "clicked", _play_pause_btn_clicked_cb, &ad);
    evas_object_smart_callback_add(stop_btn, "clicked", _stop_btn_clicked_cb, &ad);
    evas_object_smart_callback_add(search_btn, "clicked", _search_btn_clicked_cb, &ad);
+   evas_object_smart_callback_add(ad.search_entry, "activated", _search_entry_activated_cb, &ad);
+   evas_object_smart_callback_add(ad.list, "selected", _list_item_selected_cb, &ad);
 
    evas_object_resize(ad.win, 400, 600);
    evas_object_show(ad.win);
 
    elm_run();
-   ethumb_client_shutdown();
    ecore_con_shutdown();
    return 0;
 }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to