summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <marcel-hollerbach@t-online.de>2016-12-30 14:23:48 +0100
committerMarcel Hollerbach <marcel-hollerbach@t-online.de>2016-12-30 14:25:56 +0100
commitea2d9bea1c3ab6e2bc77430468b7c8ffe4c31e34 (patch)
treef82bb7e509c68b107562615cd0536666470b0bbb
parentc73cfc2106f2f2ab5524ed0c2cf908753175d039 (diff)
polish the extra app!HEADmaster
This brings a few new features: - Data is now transmitted via json and fully parsed. The parser which is used for that is jsmn and is brought in per submodule. You may ask yourself, why is that done. Well, json seemed to be a more stable fileformat than cvs. And using a more scalable file format enables the possibility to send more data to the client. So its more or less a invest into the future. - You have a download button which downloads the file directly into your elementary user theme directory - The data about the theme is displayed What is missing / can be improved: - The layouting of the details section is not THAT good - Mirror the downloadstate of the themes - Mirror the downloaded themes and check for new versions of a theme and send a notification. - Maybe some markup for the details text?
-rw-r--r--.gitmodules3
-rw-r--r--src/bin/extra_main.c116
-rw-r--r--src/lib/Makefile.am5
-rw-r--r--src/lib/extra.c167
-rw-r--r--src/lib/extra.h3
m---------src/lib/jsmn0
6 files changed, 262 insertions, 32 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..70a5e90
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
1[submodule "src/lib/jsmn"]
2 path = src/lib/jsmn
3 url = git@github.com:zserge/jsmn.git
diff --git a/src/bin/extra_main.c b/src/bin/extra_main.c
index 5f413c3..1fb8ee3 100644
--- a/src/bin/extra_main.c
+++ b/src/bin/extra_main.c
@@ -17,9 +17,38 @@
17 17
18#define COPYRIGHT "Copyright © 2016 Andy Williams <andy@andywilliams.me> and various contributors (see AUTHORS)." 18#define COPYRIGHT "Copyright © 2016 Andy Williams <andy@andywilliams.me> and various contributors (see AUTHORS)."
19 19
20typedef struct {
21 Evas_Object *title;
22 Evas_Object *screenshot;
23 Evas_Object *author;
24 Evas_Object *description;
25 Evas_Object *progress;
26} Theme_Ui;
27
20static Elm_Genlist_Item_Class _theme_class; 28static Elm_Genlist_Item_Class _theme_class;
21static Extra_Progress _sync_progress; 29static Extra_Progress _sync_progress;
22static Evas_Object *_sync_popup, *_theme_list; 30static Evas_Object *_sync_popup, *_theme_list;
31static Extra_Theme *selected_theme;
32static Theme_Ui ui;
33
34static void
35extra_win_show(Extra_Theme *theme)
36{
37 char title[1024], author[1024];
38 selected_theme = theme;
39
40 snprintf(title, sizeof(title), "<title>%s</title>", theme->name);
41 elm_object_text_set(ui.title, title);
42
43 snprintf(author, sizeof(author), "<link>%s</link>", theme->author);
44 elm_object_text_set(ui.author, author);
45
46 elm_object_text_set(ui.description, theme->description);
47
48 elm_progressbar_value_set(ui.progress, 0.0);
49 elm_photocam_file_set(ui.screenshot, theme->online_screenshot);
50 evas_object_show(ui.progress);
51}
23 52
24static void 53static void
25_extra_win_del(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) 54_extra_win_del(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
@@ -44,7 +73,7 @@ _theme_select(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UN
44 73
45 theme = (Extra_Theme *)data; 74 theme = (Extra_Theme *)data;
46 75
47 printf("SELECTED %s\n", theme->id); 76 extra_win_show(theme);
48} 77}
49 78
50static void 79static void
@@ -99,10 +128,41 @@ extra_win_sync(Evas_Object *win)
99 extra_sync(&_sync_progress); 128 extra_sync(&_sync_progress);
100} 129}
101 130
131static void
132_download_progress_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
133{
134 Elm_Photocam_Progress *prog = event_info;
135
136 elm_progressbar_value_set(ui.progress, prog->now / prog->total);
137}
138
139static void
140_download_done(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
141{
142 evas_object_hide(ui.progress);
143}
144
145static void
146_theme_download_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
147{
148 Eina_Strbuf *path;
149
150 path = eina_strbuf_new();
151
152 eina_strbuf_append(path, elm_theme_user_dir_get());
153 eina_strbuf_append(path, "/");
154 eina_strbuf_append(path, selected_theme->id);
155 eina_strbuf_append(path, "-");
156 eina_strbuf_append_printf(path, "%d", selected_theme->version);
157 eina_strbuf_append(path, ".edj");
158
159 ecore_file_download(selected_theme->download_url, eina_strbuf_string_steal(path), NULL, NULL, NULL, NULL);
160}
161
102static Evas_Object * 162static Evas_Object *
103extra_win_setup(void) 163extra_win_setup(void)
104{ 164{
105 Evas_Object *win, *list, *pane, *box, *frame; 165 Evas_Object *win, *list, *pane, *box, *frame, *table, *btn, *icon;
106 166
107 win = elm_win_util_standard_add("main", "Extra!"); 167 win = elm_win_util_standard_add("main", "Extra!");
108 if (!win) return NULL; 168 if (!win) return NULL;
@@ -132,12 +192,62 @@ extra_win_setup(void)
132 _theme_list = list; 192 _theme_list = list;
133 193
134 frame = elm_frame_add(pane); 194 frame = elm_frame_add(pane);
135 elm_object_text_set(frame, "Description"); 195 elm_object_text_set(frame, "Theme info");
136 evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); 196 evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
137 evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL); 197 evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
138 evas_object_show(frame); 198 evas_object_show(frame);
139 elm_object_part_content_set(pane, "right", frame); 199 elm_object_part_content_set(pane, "right", frame);
140 200
201 table = elm_table_add(frame);
202 evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
203 evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
204 elm_object_content_set(frame, table);
205 evas_object_show(table);
206
207 ui.title = elm_entry_add(table);
208 elm_entry_editable_set(ui.title, EINA_FALSE);
209 evas_object_size_hint_weight_set(ui.title, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
210 evas_object_size_hint_align_set(ui.title, EVAS_HINT_FILL, EVAS_HINT_FILL);
211 elm_table_pack(table, ui.title, 0, 0, 1, 1);
212 evas_object_show(ui.title);
213
214 btn = elm_button_add(table);
215 icon = elm_icon_add(table);
216 elm_icon_standard_set(icon, "emblem-downloads");
217 elm_object_part_content_set(btn, "icon", icon);
218 elm_table_pack(table, btn, 1, 0, 1, 1);
219 evas_object_show(btn);
220 evas_object_smart_callback_add(btn, "clicked", _theme_download_cb, NULL);
221 evas_object_show(icon);
222
223 ui.screenshot = elm_photocam_add(table);
224 evas_object_smart_callback_add(ui.screenshot, "download,progress", _download_progress_cb, NULL);
225 evas_object_smart_callback_add(ui.screenshot, "download,done", _download_done, NULL);
226 elm_photocam_zoom_mode_set(ui.screenshot, ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT);
227 evas_object_size_hint_weight_set(ui.screenshot, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
228 evas_object_size_hint_align_set(ui.screenshot, EVAS_HINT_FILL, EVAS_HINT_FILL);
229 elm_table_pack(table, ui.screenshot, 0, 1, 2, 2);
230 evas_object_show(ui.screenshot);
231
232 ui.progress = elm_progressbar_add(table);
233 evas_object_size_hint_weight_set(ui.progress, EVAS_HINT_EXPAND, 0.0);
234 evas_object_size_hint_align_set(ui.progress, EVAS_HINT_FILL, 0.0);
235 elm_table_pack(table, ui.progress, 0, 2, 2, 1);
236
237 ui.author = elm_entry_add(table);
238 elm_entry_editable_set(ui.author, EINA_FALSE);
239 evas_object_size_hint_weight_set(ui.author, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
240 evas_object_size_hint_align_set(ui.author, EVAS_HINT_FILL, EVAS_HINT_FILL);
241 elm_table_pack(table, ui.author, 0, 3, 2, 1);
242 evas_object_show(ui.author);
243
244 ui.description = elm_entry_add(table);
245 elm_entry_editable_set(ui.description, EINA_FALSE);
246 evas_object_size_hint_weight_set(ui.description, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
247 evas_object_size_hint_align_set(ui.description, EVAS_HINT_FILL, EVAS_HINT_FILL);
248 elm_table_pack(table, ui.description, 0, 4, 2, 1);
249 evas_object_show(ui.description);
250
141 evas_object_resize(win, 360 * elm_config_scale_get(), 251 evas_object_resize(win, 360 * elm_config_scale_get(),
142 240 * elm_config_scale_get()); 252 240 * elm_config_scale_get());
143 253
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 13d41b2..07f765f 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -13,6 +13,9 @@ lib_LTLIBRARIES = libextra.la
13includes_HEADERS = extra.h 13includes_HEADERS = extra.h
14includesdir = $(includedir)/extra-@VMAJ@ 14includesdir = $(includedir)/extra-@VMAJ@
15 15
16libextra_la_SOURCES = extra.c 16libextra_la_SOURCES = extra.c \
17 jsmn/jsmn.c \
18 jsmn/jsmn.h
19
17libextra_la_LIBADD = @EFL_LIBS@ -lm 20libextra_la_LIBADD = @EFL_LIBS@ -lm
18libextra_la_LDFLAGS = -no-undefined @EFL_LTLIBRARY_FLAGS@ 21libextra_la_LDFLAGS = -no-undefined @EFL_LTLIBRARY_FLAGS@
diff --git a/src/lib/extra.c b/src/lib/extra.c
index 12996a6..3e96127 100644
--- a/src/lib/extra.c
+++ b/src/lib/extra.c
@@ -3,7 +3,7 @@
3#endif 3#endif
4 4
5#include "extra.h" 5#include "extra.h"
6 6#include "jsmn/jsmn.h"
7#include "extra_private.h" 7#include "extra_private.h"
8 8
9static int _extra_init = 0; 9static int _extra_init = 0;
@@ -11,18 +11,27 @@ int _extra_lib_log_dom = -1;
11 11
12Eina_List *_theme_list; 12Eina_List *_theme_list;
13 13
14#define sec_strdup(v) v ? eina_strbuf_string_steal(v) : NULL
15
14static void 16static void
15_extra_theme_add(const char *id, const char *name, const char *author, 17_extra_theme_add(Eina_Strbuf *id, Eina_Strbuf *name,
18 Eina_Strbuf *author, Eina_Strbuf *description,
19 Eina_Strbuf *online_ss, Eina_Strbuf *download_url,
16 int version) 20 int version)
17{ 21{
18 Extra_Theme *theme; 22 Extra_Theme *theme;
19 23
20 theme = malloc(sizeof(*theme)); 24 theme = malloc(sizeof(*theme));
21 theme->id = strdup(id); 25 theme->id = sec_strdup(id);
22 theme->name = strdup(name); 26 theme->name = sec_strdup(name);
23 theme->author = strdup(author); 27 theme->author = sec_strdup(author);
28 theme->description = sec_strdup(description);
29 theme->online_screenshot = sec_strdup(online_ss);
30 theme->download_url = sec_strdup(download_url);
24 theme->version = version; 31 theme->version = version;
25 32
33 printf("VERSION %d\n", version);
34
26 _theme_list = eina_list_append(_theme_list, theme); 35 _theme_list = eina_list_append(_theme_list, theme);
27} 36}
28 37
@@ -74,50 +83,151 @@ extra_shutdown(void)
74 return _extra_init; 83 return _extra_init;
75} 84}
76 85
77static void 86static Eina_Bool
78_url_data_line_cb(char *buf, int len) 87_url_data_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info)
79{ 88{
80 buf[len] = '\0'; 89 Ecore_Con_Event_Url_Data *url_data = event_info;
81 if (buf[0] == '"') 90 Eina_Strbuf *buf = ecore_con_url_data_get(url_data->url_con);
91
92 eina_strbuf_append_n(buf, url_data->data, url_data->size);
93
94 return EINA_TRUE;
95}
96
97static int
98_string_tuple_get(Eina_Strbuf *c, jsmntok_t *array, int i, Eina_Strbuf **name, Eina_Strbuf **value)
99{
100 if (array[i].type != JSMN_STRING || array[i].size != 1)
101 {
102 printf("expected string type with children\n");
103 return 0;
104 }
105
106 *name = eina_strbuf_substr_get(c, array[i].start, array[i].end - array[i].start);
107
108 if ((array[i + 1].type != JSMN_STRING && array[i + 1].type != JSMN_PRIMITIVE) || array[i + 1].size != 0)
82 { 109 {
83 buf[len-1] = '\0'; 110 printf("Expected string type without children\n");
84 _extra_theme_add(buf+1, buf+1, "", 0); 111 return 0;
85 } 112 }
86 else 113 *value = eina_strbuf_substr_get(c, array[i + 1].start, array[i + 1].end - array[i + 1].start);
87 _extra_theme_add(buf, buf, "", 0); 114
115 return 2;
88} 116}
89 117
90static Eina_Bool 118static Eina_Bool
91_url_data_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) 119_fill_themes(Eina_Strbuf *buf)
92{ 120{
93 Ecore_Con_Event_Url_Data *url_data = event_info; 121 jsmn_parser parser;
94 char buf[1024]; 122 jsmntok_t parts[201];
95 int i, start = 0, end = 0; 123 int n, c = 0;
124
125 jsmn_init(&parser);
96 126
97 for (i = 0; i < url_data->size; i++) 127 const char *string = eina_strbuf_string_get(buf);
128 n = jsmn_parse(&parser, string, strlen(string), parts, 201);
129
130 if (n == 0)
131 {
132 printf("No themes received\n");
133 return EINA_FALSE;
134 }
135
136 if (parts[0].type != JSMN_OBJECT)
98 { 137 {
99 if (url_data->data[i] == '\r' || url_data->data[i] == '\n') 138 printf("Root node should be a object\n");
139 return EINA_FALSE;
140 }
141
142 c += 1;
143
144 for (int i = 0; i < parts[0].size; ++i)
145 {
146 Eina_Strbuf *id = NULL, *name = NULL, *version = NULL, *description = NULL, *author = NULL, *download_path = NULL, *online_ss = NULL;
147 int versionNumb;
148 //expect string object tuple
149 if (parts[c].type != JSMN_STRING || parts[c].size != 1)
100 { 150 {
101 if (end == start) 151 printf("Expected String type with one child\n");
102 continue; 152 return EINA_FALSE;
153 }
103 154
104 _url_data_line_cb(buf + start, end - start); 155 c += 1;
105 start = end; 156
157 if (parts[c].type != JSMN_OBJECT || parts[c].size <= 0)
158 {
159 printf("Expected Object type with more than 0 children\n");
160 return EINA_FALSE;
106 } 161 }
107 else 162
163 int max = parts[c].size;
164 c+=1;
165 for (int i2 = 0; i2 < max; ++i2)
108 { 166 {
109 buf[end] = url_data->data[i]; 167 Eina_Strbuf *value = NULL, *property = NULL;
110 end++; 168 const char *v;
169 int j = _string_tuple_get(buf, parts, c, &value, &property);
170
171 if (!j) return EINA_FALSE;
172 c += j;
173
174 v = eina_strbuf_string_steal(value);
175
176 if (!strcmp(v, "description"))
177 description = property;
178 else if (!strcmp(v, "author"))
179 author = property;
180 else if (!strcmp(v, "name"))
181 name = property;
182 else if (!strcmp(v, "version"))
183 version = property;
184 else if (!strcmp(v, "theme_id"))
185 id = property;
186 else
187 eina_strbuf_free(property);
188 eina_strbuf_free(value);
189
111 } 190 }
191
192 download_path = eina_strbuf_new();
193 online_ss = eina_strbuf_new();
194
195 eina_strbuf_append(download_path, "http://" HOSTNAME"/themes/");
196 eina_strbuf_append_buffer(download_path, id);
197 eina_strbuf_append(download_path, "-");
198 eina_strbuf_append_buffer(download_path, version);
199 eina_strbuf_append(download_path, ".edj");
200
201 eina_strbuf_append(online_ss, "http://" HOSTNAME "/themes/preview/");
202 eina_strbuf_append_buffer(online_ss, id);
203 eina_strbuf_append(online_ss, ".png");
204
205 versionNumb = atoi(eina_strbuf_string_steal(version));
206
207 _extra_theme_add(id, name, author, description, online_ss, download_path, versionNumb);
208
209 eina_strbuf_free(id);
210 eina_strbuf_free(name);
211 eina_strbuf_free(author);
212 eina_strbuf_free(description);
213 eina_strbuf_free(version);
214 eina_strbuf_free(download_path);
215 eina_strbuf_free(online_ss);
112 } 216 }
113 217
114 return EINA_TRUE; 218 return EINA_TRUE;
115} 219}
116 220
117static Eina_Bool 221static Eina_Bool
118_url_complete_cb(void *data, int type EINA_UNUSED, void *event_info EINA_UNUSED) 222_url_complete_cb(void *data, int type EINA_UNUSED, void *event_info)
119{ 223{
120 Extra_Progress *progress = data;; 224 Extra_Progress *progress = data;;
225 Ecore_Con_Event_Url_Complete *complete = event_info;
226 Eina_Strbuf *buf;
227
228 buf = ecore_con_url_data_get(complete->url_con);
229
230 _fill_themes(buf);
121 231
122 if (progress->done_cb) 232 if (progress->done_cb)
123 progress->done_cb(); 233 progress->done_cb();
@@ -132,7 +242,8 @@ extra_sync(Extra_Progress *progress)
132 Ecore_Con_Url *url; 242 Ecore_Con_Url *url;
133 243
134 url = ecore_con_url_custom_new("http://" HOSTNAME "/v1/themes/", "GET"); 244 url = ecore_con_url_custom_new("http://" HOSTNAME "/v1/themes/", "GET");
135 ecore_con_url_additional_header_add(url, "Accept", "text/csv"); 245 ecore_con_url_additional_header_add(url, "Accept", "text/json");
246 ecore_con_url_data_set(url, eina_strbuf_new());
136 247
137 progress->url = url; 248 progress->url = url;
138 ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, _url_data_cb, NULL); 249 ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, _url_data_cb, NULL);
diff --git a/src/lib/extra.h b/src/lib/extra.h
index 597262c..2981051 100644
--- a/src/lib/extra.h
+++ b/src/lib/extra.h
@@ -43,6 +43,9 @@ typedef struct _Extra_Theme
43 const char *id; 43 const char *id;
44 const char *name; 44 const char *name;
45 const char *author; 45 const char *author;
46 const char *description;
47 const char *online_screenshot;
48 const char *download_url;
46 int version; 49 int version;
47} Extra_Theme; 50} Extra_Theme;
48 51
diff --git a/src/lib/jsmn b/src/lib/jsmn
new file mode 160000
Subproject 1682c32e9ae5990ddd0f0e907270a0f6dde5cbe