Several changes in the contacts layout tab and accross the App.
[profile/ivi/lemolo.git] / dialer / contacts.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <Elementary.h>
5 #include <Eet.h>
6 #include <Eina.h>
7
8 #include "log.h"
9 #include "gui.h"
10 #include "ofono.h"
11 #include "contacts.h"
12 #include "util.h"
13
14 #ifndef EET_COMPRESSION_DEFAULT
15 #define EET_COMPRESSION_DEFAULT 1
16 #endif
17
18 #define CONTACTS_ENTRY "contacts"
19
20 typedef struct _Contacts_List {
21         Eina_List *list;
22 } Contacts_List;
23
24 typedef struct _Contacts {
25         char *path;
26         Eet_Data_Descriptor *edd;
27         Eet_Data_Descriptor *edd_list;
28         Elm_Genlist_Item_Class *itc, *group;
29         Evas_Object *genlist, *layout, *details;
30         Contacts_List *c_list;
31 } Contacts;
32
33 struct _Contact_Info {
34         const char *name;
35         const char *mobile;
36         const char *home;
37         const char *work;
38         const char *picture;
39         const char *last_name;
40 };
41
42 Contact_Info *contact_search(Evas_Object *obj, const char *number, const char **type)
43 {
44         Contact_Info *c_info;
45         Eina_List *l;
46         Contacts *contacts;
47         char *found_type;
48
49         EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
50         EINA_SAFETY_ON_NULL_RETURN_VAL(number, NULL);
51         contacts = evas_object_data_get(obj, "contacts.ctx");
52         EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
53
54         EINA_LIST_FOREACH(contacts->c_list->list, l, c_info) {
55                 if (!c_info)
56                         continue;
57
58                 if (strcmp(number, c_info->mobile) == 0) {
59                         found_type = "Mobile";
60                         goto found;
61                 }
62                 else if (strcmp(number, c_info->work) == 0) {
63                         found_type = "Work";
64                         goto found;
65                 }
66                 else if (strcmp(number, c_info->home) == 0) {
67                         found_type = "Home";
68                         goto found;
69                 }
70         }
71
72         return NULL;
73 found:
74         if (type)
75                 *type = found_type;
76         return c_info;
77 }
78
79 const char *contact_info_name_get(const Contact_Info *c)
80 {
81         char buf[PATH_MAX];
82         snprintf(buf, sizeof(buf), "%s %s", c->name, c->last_name);
83         return strdup(buf);
84 }
85
86 const char *contact_info_picture_get(const Contact_Info *c)
87 {
88         return c->picture;
89 }
90
91 const char *contact_info_detail_get(const Contact_Info *c, const char *type)
92 {
93         if (strcmp(type, "Mobile") == 0)
94                 return c->mobile;
95         else if (strcmp(type, "Work") == 0)
96                 return c->work;
97         else if (strcmp(type, "Home") == 0)
98                 return c->home;
99         else
100                 return NULL;
101 }
102
103 static void _contacts_info_descriptor_init(Eet_Data_Descriptor **edd,
104                                                 Eet_Data_Descriptor **edd_list)
105 {
106         Eet_Data_Descriptor_Class eddc;
107
108         EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Contact_Info);
109         *edd = eet_data_descriptor_stream_new(&eddc);
110
111         EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Contacts_List);
112         *edd_list = eet_data_descriptor_stream_new(&eddc);
113
114         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Contact_Info,
115                                         "picture", picture, EET_T_STRING);
116         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Contact_Info,
117                                         "work", work, EET_T_STRING);
118         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Contact_Info,
119                                         "home", home, EET_T_STRING);
120         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Contact_Info,
121                                         "mobile", mobile, EET_T_STRING);
122         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Contact_Info,
123                                         "name", name, EET_T_STRING);
124         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Contact_Info,
125                                         "last_name", last_name, EET_T_STRING);
126
127         EET_DATA_DESCRIPTOR_ADD_LIST(*edd_list, Contacts_List, "list", list,
128                                         *edd);
129 }
130
131 static void _contacts_info_free(Contact_Info *c_info)
132 {
133         eina_stringshare_del(c_info->name);
134         eina_stringshare_del(c_info->mobile);
135         eina_stringshare_del(c_info->home);
136         eina_stringshare_del(c_info->work);
137         eina_stringshare_del(c_info->picture);
138         eina_stringshare_del(c_info->last_name);
139         free(c_info);
140 }
141
142 static void _on_del(void *data, Evas *e __UNUSED__,
143                         Evas_Object *obj __UNUSED__, void *event __UNUSED__)
144 {
145         Contacts *contacts = data;
146         Contact_Info *c_info;
147         eet_data_descriptor_free(contacts->edd);
148         eet_data_descriptor_free(contacts->edd_list);
149         EINA_LIST_FREE(contacts->c_list->list, c_info)
150                 _contacts_info_free(c_info);
151         free(contacts->c_list);
152         elm_genlist_item_class_free(contacts->itc);
153         elm_genlist_item_class_free(contacts->group);
154         free(contacts->path);
155         free(contacts);
156         eet_shutdown();
157 }
158
159 static void _on_number_clicked(void *data, Evas_Object *obj __UNUSED__,
160                                 void *event_inf __UNUSED__)
161 {
162         const char *number = data;
163         ofono_dial(number, NULL, NULL, NULL);
164 }
165
166 static void _on_item_click(void *data, Evas_Object *obj __UNUSED__,
167                                 void *event_inf)
168 {
169         Contacts *contacts = data;
170         Elm_Object_Item *item = event_inf;
171         Evas_Object *details, *btn, *photo;
172         Contact_Info *c_info;
173         char *phone;
174
175         details = contacts->details;
176         c_info = elm_object_item_data_get(item);
177         elm_genlist_item_selected_set(item, EINA_FALSE);
178         elm_layout_box_remove_all(details, "box.phones", EINA_TRUE);
179
180         elm_object_part_text_set(details, "text.name", c_info->name);
181         elm_object_part_text_set(details, "text.last.name", c_info->last_name);
182
183         photo = picture_icon_get(details, c_info->picture);
184         elm_object_part_content_set(details, "swallow.photo", photo);
185
186         btn = elm_button_add(details);
187         EINA_SAFETY_ON_NULL_RETURN(btn);
188         elm_object_style_set(btn, "contacts");
189         phone = phone_format(c_info->mobile);
190         elm_object_part_text_set(btn, "elm.text.type", "Mobile");
191         elm_object_part_text_set(btn, "elm.text.phone", phone);
192         free(phone);
193         evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND,
194                                                 EVAS_HINT_EXPAND);
195         evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, EVAS_HINT_FILL);
196         evas_object_show(btn);
197         evas_object_smart_callback_add(btn, "clicked", _on_number_clicked,
198                                         c_info->mobile);
199         elm_layout_box_append(details, "box.phones", btn);
200
201         btn = elm_button_add(details);
202         EINA_SAFETY_ON_NULL_RETURN(btn);
203         elm_object_style_set(btn, "contacts");
204         phone = phone_format(c_info->home);
205         elm_object_part_text_set(btn, "elm.text.type", "Home");
206         elm_object_part_text_set(btn, "elm.text.phone", phone);
207         free(phone);
208         evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND,
209                                                 EVAS_HINT_EXPAND);
210         evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, EVAS_HINT_FILL);
211         evas_object_show(btn);
212         evas_object_smart_callback_add(btn, "clicked", _on_number_clicked,
213                                         c_info->home);
214         elm_layout_box_append(details, "box.phones", btn);
215
216         btn = elm_button_add(details);
217         EINA_SAFETY_ON_NULL_RETURN(btn);
218         elm_object_style_set(btn, "contacts");
219         phone = phone_format(c_info->work);
220         elm_object_part_text_set(btn, "elm.text.type", "Work");
221         elm_object_part_text_set(btn, "elm.text.phone", phone);
222         free(phone);
223         evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND,
224                                                 EVAS_HINT_EXPAND);
225         evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, EVAS_HINT_FILL);
226         evas_object_show(btn);
227         evas_object_smart_callback_add(btn, "clicked", _on_number_clicked,
228                                         c_info->work);
229         elm_layout_box_append(details, "box.phones", btn);
230         elm_object_signal_emit(contacts->layout, "show,details", "gui");
231 }
232
233 static int _sort_by_name_cb(const void *v1, const void *v2)
234 {
235         const Contact_Info *c1, *c2;
236         c1 = v1;
237         c2 = v2;
238
239         if (!c1) return 1;
240         if (!c2) return -1;
241
242         return strcmp(c1->name, c2->name);
243 }
244
245 static void _contacts_read(Contacts *contacts)
246 {
247         Contact_Info *c_info;
248         Eina_List *l;
249         Eet_File *efile;
250         Elm_Object_Item *it = NULL;
251         char group;
252         efile = eet_open(contacts->path, EET_FILE_MODE_READ);
253
254         if (efile) {
255                 contacts->c_list = eet_data_read(efile, contacts->edd_list,
256                                                         CONTACTS_ENTRY);
257                 eet_close(efile);
258         } else
259                 contacts->c_list = calloc(1, sizeof(Contacts_List));
260
261         EINA_SAFETY_ON_NULL_RETURN(contacts->c_list);
262         contacts->c_list->list = eina_list_sort(contacts->c_list->list, 0,
263                                                 _sort_by_name_cb);
264         group = '\0';
265         EINA_LIST_FOREACH(contacts->c_list->list, l, c_info) {
266                 if (!c_info)
267                         continue;
268                 if (group != c_info->name[0]) {
269                         group = c_info->name[0];
270                         it = elm_genlist_item_append(contacts->genlist,
271                                                         contacts->group,
272                                                         c_info, NULL,
273                                                         ELM_GENLIST_ITEM_GROUP,
274                                                         NULL,
275                                                         NULL);
276                         elm_genlist_item_select_mode_set(it, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
277                 }
278                 elm_genlist_item_append(contacts->genlist,contacts->itc,
279                                                 c_info, it,
280                                                 ELM_GENLIST_ITEM_NONE,
281                                                 _on_item_click, contacts);
282         }
283 }
284
285 static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__,
286                                 const char *part)
287 {
288         Contact_Info *c_info = data;
289
290         if (strncmp(part, "text.contacts", strlen("text.contacts")))
291                 return NULL;
292
293         part += strlen("text.contacts.");
294
295         if (strcmp(part, "name") == 0)
296                 return strdup(c_info->name);
297         else if (strcmp(part, "last") == 0)
298                 return strdup(c_info->last_name);
299
300         ERR("Unexpected part name: %s", part);
301         return NULL;
302 }
303
304 static char *_group_label_get(void *data, Evas_Object *obj __UNUSED__,
305                                 const char *part __UNUSED__)
306 {
307         Contact_Info *c_info = data;
308         char buf[2];
309         snprintf(buf, sizeof(buf), "%c", c_info->name[0]);
310         return strdup(buf);
311 }
312
313
314 static Evas_Object *_item_content_get(void *data,
315                                         Evas_Object *obj,
316                                         const char *part)
317 {
318         Contact_Info *c_info = data;
319         Evas_Object *photo;
320
321         if (strncmp(part, "swallow.", strlen("swallow.")))
322                 return NULL;
323
324         part += strlen("swallow.");
325
326         if (strcmp(part, "photo") != 0) {
327                 ERR("Unexpected part name: %s", part);
328                 return NULL;
329         }
330
331         photo = picture_icon_get(obj, c_info->picture);
332
333         return photo;
334 }
335
336 static void _on_back_clicked(void *data, Evas_Object *obj __UNUSED__,
337                                 const char *emission __UNUSED__,
338                                 const char *source __UNUSED__)
339 {
340         Evas_Object *layout = data;
341         elm_object_signal_emit(layout, "hide,details", "gui");
342 }
343
344 Evas_Object *contacts_add(Evas_Object *parent)
345 {
346         int r;
347         const char *config_path;
348         char base_dir[PATH_MAX], *path;
349         Contacts *contacts;
350         Evas_Object *obj, *genlist, *details;
351         Elm_Genlist_Item_Class *itc, *group;
352
353         eet_init();
354         contacts = calloc(1, sizeof(Contacts));
355         EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
356
357
358         details = gui_layout_add(parent, "contacts_details");
359         EINA_SAFETY_ON_NULL_GOTO(details, err_layout);
360
361         obj = gui_layout_add(parent, "contacts_bg");
362         EINA_SAFETY_ON_NULL_GOTO(obj, err_obj);
363
364         genlist = elm_genlist_add(obj);
365         EINA_SAFETY_ON_NULL_GOTO(genlist, err_genlist);
366         elm_object_style_set(genlist, "contacts");
367
368         itc = elm_genlist_item_class_new();
369         EINA_SAFETY_ON_NULL_GOTO(itc, err_genlist);
370         itc->item_style = "contacts";
371         itc->func.text_get =  _item_label_get;
372         itc->func.content_get = _item_content_get;
373         itc->func.state_get = NULL;
374         itc->func.del = NULL;
375
376         group = elm_genlist_item_class_new();
377         EINA_SAFETY_ON_NULL_GOTO(group, err_group);
378         group->item_style = "group_contacts";
379         group->func.text_get = _group_label_get;
380         group->func.content_get = NULL;
381         group->func.state_get = NULL;
382         group->func.del = NULL;
383         contacts->group = group;
384         contacts->genlist = genlist;
385         contacts->itc = itc;
386         contacts->layout = obj;
387         contacts->details = details;
388
389         elm_object_part_content_set(obj, "elm.swallow.genlist", genlist);
390         elm_object_part_content_set(obj, "elm.swallow.details", details);
391
392         elm_object_signal_callback_add(details, "clicked,back", "gui",
393                                         _on_back_clicked, obj);
394
395         config_path = efreet_config_home_get();
396         snprintf(base_dir, sizeof(base_dir), "%s/%s", config_path,
397                         PACKAGE_NAME);
398         ecore_file_mkpath(base_dir);
399
400         r = asprintf(&path,  "%s/%s/contacts.eet", config_path, PACKAGE_NAME);
401
402         if (r < 0)
403                 goto err_path;
404
405         contacts->path = path;
406         _contacts_info_descriptor_init(&contacts->edd, &contacts->edd_list);
407         _contacts_read(contacts);
408         EINA_SAFETY_ON_NULL_GOTO(contacts->c_list, err_read);
409
410         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
411                                         contacts);
412
413         evas_object_data_set(obj, "contacts.ctx", contacts);
414         return obj;
415
416 err_read:
417         eet_data_descriptor_free(contacts->edd);
418         eet_data_descriptor_free(contacts->edd_list);
419         free(path);
420 err_path:
421         elm_genlist_item_class_free(group);
422 err_group:
423         elm_genlist_item_class_free(itc);
424 err_genlist:
425         free(obj);
426 err_obj:
427         free(details);
428 err_layout:
429         free(contacts);
430         eet_shutdown();
431         return NULL;
432 }