5 #include <Elementary.h>
15 #include "contacts-ofono-efl.h"
17 #define ALL_MESSAGES "all_messages"
19 #ifndef EET_COMPRESSION_DEFAULT
20 #define EET_COMPRESSION_DEFAULT 1
23 /* This struct hold the content of the messages that will be showed
26 typedef struct _Messages_List
29 Eina_Bool dirty; /* not in eet */
30 Ecore_Poller *save_poller; /* not in eet */
36 unsigned char outgoing;
39 const char *phone; /* phone number - not in eet */
40 int refcount; /* not in eet */
41 void *data; /* not in eet */
42 Elm_Object_Item *it; /* not in eet */
45 typedef struct _Overview
47 Eet_Data_Descriptor *edd_msg_info;
48 Eet_Data_Descriptor *edd_msg_list;
49 Eet_Data_Descriptor *edd_msg;
50 Eet_Data_Descriptor *edd_c_msg;
51 Messages_List *messages;
52 /* Pending conversations, not saved in eet yet */
53 Messages_List *p_conversations;
54 Evas_Object *layout, *genlist;
55 char *msg_path, *base_dir, *msg_bkp;
56 Ecore_Poller *updater;
58 Elm_Genlist_Item_Class *itc;
59 Eina_Hash *pending_sms;
62 /* Messages showed in the main screen */
63 typedef struct _Message_Info
65 const char *sender, *last_msg;
68 Overview *ov; /*not in eet */
69 Elm_Object_Item *it; /* not in eet */
72 static OFono_Callback_List_Incoming_SMS_Node *incoming_sms = NULL;
73 static OFono_Callback_List_Sent_SMS_Node *sent_sms = NULL;
75 static void _overview_messages_save(Overview *ov);
76 static Message_Info *_message_info_search(Overview *ov, const char *sender);
77 static void _message_info_del(Message_Info *m_info);
78 static void _overview_messages_save(Overview *ov);
79 static void _conversation_eet_update_save(Overview *ov, Message *msg);
80 static void _message_free(Message *msg);
82 void message_ref(Message *msg)
84 EINA_SAFETY_ON_NULL_RETURN(msg);
88 static Eina_Bool _overview_messages_save_do(void *data)
92 EINA_SAFETY_ON_NULL_RETURN_VAL(ov->messages, ECORE_CALLBACK_DONE);
94 ov->messages->save_poller = NULL;
95 ov->messages->dirty = EINA_FALSE;
97 ecore_file_unlink(ov->msg_bkp);
98 ecore_file_mv(ov->msg_path, ov->msg_bkp);
99 efile = eet_open(ov->msg_path, EET_FILE_MODE_WRITE);
100 EINA_SAFETY_ON_NULL_GOTO(efile, failed);
102 if (!(eet_data_write(efile,
103 ov->edd_msg_list, ALL_MESSAGES,
104 ov->messages, EET_COMPRESSION_DEFAULT)))
105 ERR("Could in the messages log file");
108 return ECORE_CALLBACK_DONE;
111 ecore_file_mv(ov->msg_bkp, ov->msg_path);
112 return ECORE_CALLBACK_DONE;
115 void overview_genlist_update(Evas_Object *obj, Message *msg,
119 Message_Info *m_info;
121 EINA_SAFETY_ON_NULL_RETURN(obj);
122 ov = evas_object_data_get(obj, "overview.ctx");
123 EINA_SAFETY_ON_NULL_RETURN(ov);
124 EINA_SAFETY_ON_NULL_RETURN(msg);
126 m_info = _message_info_search(ov, contact);
127 EINA_SAFETY_ON_NULL_RETURN(m_info);
129 m_info->time = msg->time;
130 eina_stringshare_replace(&m_info->last_msg, msg->content);
131 _overview_messages_save(ov);
132 elm_genlist_item_update(m_info->it);
135 void message_object_item_set(Message *msg, Elm_Object_Item *it)
137 EINA_SAFETY_ON_NULL_RETURN(msg);
141 Elm_Object_Item *message_object_item_get(const Message *msg)
143 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
147 void message_state_set(Message *msg, unsigned char state)
149 EINA_SAFETY_ON_NULL_RETURN(msg);
153 void *message_data_get(const Message *msg)
155 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
159 void message_data_set(Message *msg, void *data)
161 EINA_SAFETY_ON_NULL_RETURN(msg);
165 static Eina_Bool _message_is_equal(Message *m1, Message *m2)
167 if (strcmp(m1->content, m2->content) != 0)
170 if (m1->outgoing != m2->outgoing)
173 if (m1->state != m2->state)
176 if (m1->time != m2->time)
182 void overview_message_from_file_delete(Evas_Object *obj, Message *msg,
187 char buf[PATH_MAX], bkp[PATH_MAX];
188 Messages_List *messages = NULL;
192 EINA_SAFETY_ON_NULL_RETURN(obj);
193 ov = evas_object_data_get(obj, "overview.ctx");
194 EINA_SAFETY_ON_NULL_RETURN(ov);
195 EINA_SAFETY_ON_NULL_RETURN(msg);
197 snprintf(buf, sizeof(buf), "%s/%s.eet", ov->base_dir, contact);
198 snprintf(bkp, sizeof(bkp), "%s/%s.eet.bkp", ov->base_dir, contact);
200 efile = eet_open(buf, EET_FILE_MODE_READ_WRITE);
203 messages = eet_data_read(efile, ov->edd_c_msg, ALL_MESSAGES);
207 efile = eet_open(bkp, EET_FILE_MODE_READ_WRITE);
209 messages = eet_data_read(efile, ov->edd_c_msg,
217 EINA_LIST_FOREACH(messages->list, l, msg_aux) {
218 if (_message_is_equal(msg, msg_aux)) {
219 _message_free(msg_aux);
220 messages->list = eina_list_remove_list(messages->list,
225 Message_Info *m_info = _message_info_search(ov, contact);
226 EINA_SAFETY_ON_NULL_RETURN(m_info);
228 if (messages->list && eina_list_count(messages->list) != 0) {
229 eet_data_write(efile, ov->edd_c_msg, ALL_MESSAGES, messages,
230 EET_COMPRESSION_DEFAULT);
234 _message_info_del(m_info);
237 EINA_LIST_FREE(messages->list, msg_aux)
238 _message_free(msg_aux);
242 unsigned char message_state_get(const Message *msg)
244 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, '\0');
248 const char * message_content_get(const Message *msg)
250 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
254 const char * message_phone_get(const Message *msg)
256 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
260 unsigned char message_outgoing_get(const Message *msg)
262 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, '\0');
263 return msg->outgoing;
266 long long message_time_get(const Message *msg)
269 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, -1);
273 static Message_Info *_message_info_search(Overview *ov, const char *sender)
276 Message_Info *m_info;
278 EINA_SAFETY_ON_NULL_RETURN_VAL(ov->messages, NULL);
280 EINA_LIST_FOREACH(ov->messages->list, l, m_info) {
281 if (strcmp(sender, m_info->sender) == 0)
288 static void _message_free(Message *msg)
291 eina_stringshare_del(msg->content);
292 eina_stringshare_del(msg->phone);
296 void message_del(Message *msg)
299 EINA_SAFETY_ON_NULL_RETURN(msg);
300 DBG("MSG=%p, refcount=%d", msg, msg->refcount);
301 EINA_SAFETY_ON_TRUE_RETURN(msg->refcount <= 0);
304 if (msg->refcount == 0)
308 static void _message_info_free(Message_Info *m_info)
310 eina_stringshare_del(m_info->sender);
311 eina_stringshare_del(m_info->last_msg);
315 static void _messages_file_delete(char *dir, const char *sender)
318 snprintf(path, sizeof(path), "%s/%s.eet", dir, sender);
319 ecore_file_unlink(path);
320 snprintf(path, sizeof(path), "%s/%s.eet.bkp", dir, sender);
321 ecore_file_unlink(path);
324 static void _message_info_del(Message_Info *m_info)
326 Overview *ctx = m_info->ov;
330 EINA_SAFETY_ON_NULL_RETURN(ctx);
332 elm_object_item_del(m_info->it);
334 ctx->messages->list = eina_list_remove(ctx->messages->list, m_info);
335 ctx->messages->dirty = EINA_TRUE;
337 /* Remove unsaved SMSs */
338 EINA_LIST_FOREACH_SAFE(ctx->p_conversations->list, l, next, msg) {
339 if (msg->phone == m_info->sender) {
340 ctx->p_conversations->list =
341 eina_list_remove(ctx->p_conversations->list,
347 _messages_file_delete(ctx->base_dir, m_info->sender);
348 _overview_messages_save(ctx);
350 if ((!ctx->messages->list) && (ctx->updater)) {
351 ecore_poller_del(ctx->updater);
355 _message_info_free(m_info);
358 static void _on_del(void *data, Evas *e __UNUSED__,
359 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
362 Message_Info *m_info;
365 ofono_incoming_sms_cb_del(incoming_sms);
366 ofono_sent_sms_changed_cb_del(sent_sms);
368 if (ov->messages->save_poller)
369 ecore_poller_del(ov->messages->save_poller);
371 if (ov->p_conversations->save_poller)
372 ecore_poller_del(ov->p_conversations->save_poller);
374 if (ov->messages->dirty)
375 _overview_messages_save_do(ov);
377 eina_hash_free(ov->pending_sms);
379 if (!ov->p_conversations->dirty) {
380 EINA_LIST_FREE(ov->p_conversations->list, msg)
383 EINA_LIST_FREE(ov->p_conversations->list, msg) {
384 _conversation_eet_update_save(ov, msg);
389 EINA_LIST_FREE(ov->messages->list, m_info)
390 _message_info_free(m_info);
392 eet_data_descriptor_free(ov->edd_msg_info);
393 eet_data_descriptor_free(ov->edd_msg_list);
394 eet_data_descriptor_free(ov->edd_msg);
395 eet_data_descriptor_free(ov->edd_c_msg);
397 elm_genlist_item_class_free(ov->itc);
402 free(ov->p_conversations);
406 ecore_file_shutdown();
409 static void _eet_descriptors_init(Eet_Data_Descriptor **messages,
410 Eet_Data_Descriptor **msg_info,
411 Eet_Data_Descriptor **edd_msg,
412 Eet_Data_Descriptor **edd_c_msg)
414 Eet_Data_Descriptor_Class eddc;
415 Eet_Data_Descriptor_Class eddcM;
417 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Message_Info);
418 *msg_info = eet_data_descriptor_stream_new(&eddc);
420 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Messages_List);
421 *messages = eet_data_descriptor_stream_new(&eddc);
423 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddcM, Message);
424 *edd_msg = eet_data_descriptor_stream_new(&eddcM);
426 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddcM, Messages_List);
427 *edd_c_msg = eet_data_descriptor_stream_new(&eddcM);
429 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd_msg, Message,
430 "content", content, EET_T_STRING);
431 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd_msg, Message,
432 "time", time, EET_T_LONG_LONG);
433 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd_msg, Message,
434 "outgoing", outgoing, EET_T_UCHAR);
435 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd_msg, Message,
436 "state", state, EET_T_UCHAR);
438 EET_DATA_DESCRIPTOR_ADD_BASIC(*msg_info, Message_Info,
439 "sender", sender, EET_T_STRING);
440 EET_DATA_DESCRIPTOR_ADD_BASIC(*msg_info, Message_Info,
441 "last_msg", last_msg, EET_T_STRING);
442 EET_DATA_DESCRIPTOR_ADD_BASIC(*msg_info, Message_Info,
443 "time", time, EET_T_LONG_LONG);
444 EET_DATA_DESCRIPTOR_ADD_BASIC(*msg_info, Message_Info,
445 "count", count, EET_T_INT);
447 EET_DATA_DESCRIPTOR_ADD_LIST(*messages, Messages_List, "list", list,
450 EET_DATA_DESCRIPTOR_ADD_LIST(*edd_c_msg, Messages_List, "list", list,
455 static void _overview_messages_save(Overview *ov)
457 if (ov->messages->save_poller)
459 ov->messages->save_poller = ecore_poller_add(ECORE_POLLER_CORE, 32,
460 _overview_messages_save_do,
464 static void _on_item_clicked(void *data, Evas_Object *obj __UNUSED__,
467 Message_Info *m_info = data;
468 Elm_Object_Item *it = event_info;
469 char buf[PATH_MAX], bkp[PATH_MAX];
470 Overview *ov = m_info->ov;
472 Messages_List *messages = NULL;
474 elm_genlist_item_selected_set(it, EINA_FALSE);
476 snprintf(buf, sizeof(buf), "%s/%s.eet", ov->base_dir, m_info->sender);
477 snprintf(bkp, sizeof(bkp), "%s/%s.eet.bkp", ov->base_dir,
480 efile = eet_open(buf, EET_FILE_MODE_READ);
483 messages = eet_data_read(efile, ov->edd_c_msg, ALL_MESSAGES);
488 efile = eet_open(bkp, EET_FILE_MODE_READ);
490 messages = eet_data_read(efile, ov->edd_c_msg,
496 gui_compose_messages_set(messages->list, m_info->sender);
498 /* Compose will free the messages->list for me */
501 INF("Could not read the messages list!");
504 static void _overview_messages_read(Overview *ov)
507 Messages_List *msg_list = NULL;
509 Message_Info *m_info;
512 efile = eet_open(ov->msg_path, EET_FILE_MODE_READ);
515 msg_list = eet_data_read(efile, ov->edd_msg_list, ALL_MESSAGES);
520 efile = eet_open(ov->msg_bkp, EET_FILE_MODE_READ);
522 msg_list = eet_data_read(efile, ov->edd_msg_list,
529 msg_list = calloc(1, sizeof(Messages_List));
531 ov->messages = msg_list;
532 EINA_SAFETY_ON_NULL_RETURN(ov->messages);
534 EINA_LIST_FOREACH(ov->messages->list, l, m_info) {
535 it = elm_genlist_item_append(ov->genlist,
536 ov->itc, m_info, NULL,
537 ELM_GENLIST_ITEM_NONE,
538 _on_item_clicked, m_info);
544 static Eina_Bool _overview_time_updater(void *data)
546 Overview *ctx = data;
547 double now = ecore_loop_time_get();
548 const double interval_threshold = 30.0;
550 const long long update_threshold = time(NULL) - WEEK - DAY;
552 if (!ctx->messages->list) {
557 if (now - ctx->last_update < interval_threshold)
559 ctx->last_update = now;
561 it = elm_genlist_first_item_get(ctx->genlist);
562 for (; it != NULL; it = elm_genlist_item_next_get(it)) {
563 const Message_Info *m_info = elm_object_item_data_get(it);
564 long long t = m_info->time;
565 if (EINA_UNLIKELY(t == 0)) {
568 if (EINA_UNLIKELY(t < update_threshold))
570 elm_genlist_item_update(it);
576 static void _overview_timer_updater_start(Overview *ov)
578 Evas *e = evas_object_evas_get(ov->layout);
579 Eina_Bool win_focused = evas_focus_state_get(e);
580 Eina_Bool obj_visible = evas_object_visible_get(ov->layout);
582 DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
583 ov->updater, win_focused, obj_visible);
586 if (!ov->messages->list)
588 if ((!win_focused) || (!obj_visible))
591 DBG("start poller messages");
592 /* ECORE_POLLER_CORE is 1/8th of second. */
593 ov->updater = ecore_poller_add(ECORE_POLLER_CORE, 8 * 60,
594 _overview_time_updater,
596 _overview_time_updater(ov);
599 static void _overview_time_updater_stop(Overview *ov)
601 Evas *e = evas_object_evas_get(ov->layout);
602 Eina_Bool win_focused = evas_focus_state_get(e);
603 Eina_Bool obj_visible = evas_object_visible_get(ov->layout);
605 DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
606 ov->updater, win_focused, obj_visible);
609 if (win_focused && obj_visible)
612 DBG("delete poller %p", ov->updater);
613 ecore_poller_del(ov->updater);
617 static Message *_message_list_search(Eina_List *list, Message *msg)
622 EINA_LIST_FOREACH(list, l, m) {
623 if ((m->content == msg->content &&
624 m->time == msg->time) ||
625 (msg->content == m->content && m->state != msg->state))
632 static void _conversation_eet_update_save(Overview *ov, Message *msg)
636 char buf[PATH_MAX], bkp[PATH_MAX];
637 Messages_List *messages = NULL;
640 snprintf(buf, sizeof(buf), "%s/%s.eet", ov->base_dir, msg->phone);
641 snprintf(bkp, sizeof(bkp), "%s/%s.eet.bkp", ov->base_dir, msg->phone);
643 efile = eet_open(buf, EET_FILE_MODE_READ);
646 messages = eet_data_read(efile, ov->edd_c_msg, ALL_MESSAGES);
651 efile = eet_open(bkp, EET_FILE_MODE_READ);
653 messages = eet_data_read(efile, ov->edd_c_msg,
661 messages = calloc(1, sizeof(Messages_List));
662 EINA_SAFETY_ON_NULL_RETURN(messages);
665 msg_aux = _message_list_search(messages->list, msg);
668 messages->list = eina_list_append(messages->list, msg);
671 msg_aux->state = msg->state;
673 ecore_file_unlink(bkp);
674 ecore_file_mv(buf, bkp);
676 efile = eet_open(buf, EET_FILE_MODE_WRITE);
677 EINA_SAFETY_ON_NULL_RETURN(efile);
679 eet_data_write(efile, ov->edd_c_msg, ALL_MESSAGES, messages,
680 EET_COMPRESSION_DEFAULT);
683 EINA_LIST_FREE(messages->list, msg_aux) {
686 else /* messages read from eet have no refcount */
687 _message_free(msg_aux);
692 static Eina_Bool _conversation_eet_update_do(void *data)
697 ov->p_conversations->dirty = EINA_FALSE;
698 ov->p_conversations->save_poller = NULL;
700 EINA_LIST_FREE(ov->p_conversations->list, msg) {
701 _conversation_eet_update_save(ov, msg);
704 ov->p_conversations->list = NULL;
705 return ECORE_CALLBACK_DONE;
708 static void _conversation_eet_update(Overview *ov)
710 if (ov->p_conversations->save_poller)
713 ov->p_conversations->save_poller = ecore_poller_add(ECORE_POLLER_CORE,
715 _conversation_eet_update_do,
719 static void _message_info_genlist_update(Overview *ov, time_t timestamp,
723 Message_Info *m_info;
726 m_info = _message_info_search(ov, sender);
729 m_info = calloc(1, sizeof(Message_Info));
730 EINA_SAFETY_ON_NULL_RETURN(m_info);
731 m_info->sender = eina_stringshare_add(sender);
732 ov->messages->list = eina_list_prepend(ov->messages->list,
736 ov->messages->list = eina_list_remove(ov->messages->list,
738 ov->messages->list = eina_list_prepend(ov->messages->list,
741 elm_object_item_del(m_info->it);
745 m_info->time = timestamp;
746 eina_stringshare_replace(&m_info->last_msg, message);
747 ov->messages->dirty = EINA_TRUE;
749 it = elm_genlist_item_prepend(ov->genlist,
750 ov->itc, m_info, NULL,
751 ELM_GENLIST_ITEM_NONE,
752 _on_item_clicked, m_info);
755 elm_genlist_item_show(m_info->it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
756 _overview_timer_updater_start(ov);
757 _overview_messages_save(ov);
760 Message *message_new(time_t timestamp, const char *content,
761 Eina_Bool outgoing, OFono_Sent_SMS_State state)
765 msg = calloc(1, sizeof(Message));
766 EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
767 msg->time = timestamp;
768 msg->outgoing = outgoing;
769 msg->content = eina_stringshare_add(content);
775 static void _incoming_sms_cb(void *data, unsigned int sms_class,
776 time_t timestamp, const char *sender,
782 /* Users can only send class 1. This is OFono/GSM detail */
786 msg = message_new(timestamp, message, EINA_FALSE,
787 OFONO_SENT_SMS_STATE_SENT);
788 EINA_SAFETY_ON_NULL_RETURN(msg);
789 msg->phone = eina_stringshare_add(sender);
791 _message_info_genlist_update(ov, timestamp, sender, message);
793 ov->p_conversations->list = eina_list_append(ov->p_conversations->list,
795 ov->p_conversations->dirty = EINA_TRUE;
796 _conversation_eet_update(ov);
799 static void _on_show(void *data, Evas *e __UNUSED__,
800 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
803 DBG("Overview became visible");
804 _overview_timer_updater_start(ov);
807 static void _on_win_focus_in(void *data, Evas *e __UNUSED__,
808 void *event_info __UNUSED__)
811 DBG("window is focused");
812 _overview_timer_updater_start(ov);
815 static void _on_win_focus_out(void *data, Evas *e __UNUSED__,
816 void *event_info __UNUSED__)
819 DBG("window is unfocused");
820 _overview_time_updater_stop(ov);
823 static void _on_hide(void *data, Evas *e __UNUSED__,
824 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
827 DBG("Overview became hidden");
828 _overview_time_updater_stop(ov);
831 static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__,
834 Message_Info *m_info = data;
836 if (strncmp(part, "elm.text.", strlen("elm.text.")))
838 part += strlen("elm.text.");
840 if (strcmp(part, "name") == 0) {
841 Contact_Info *c_info = gui_contact_search(m_info->sender, NULL);
844 return strdup(m_info->sender);
846 return strdup(contact_info_full_name_get(c_info));
849 if (strcmp(part, "content") == 0)
850 return elm_entry_utf8_to_markup(m_info->last_msg);
852 if (strcmp(part, "time") == 0) {
853 time_t time_msg = m_info->time;
854 return date_short_format(time_msg);
857 ERR("Unexpected text part: %s", part);
861 static void _on_more_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
862 const char *emission __UNUSED__,
863 const char *source __UNUSED__)
865 DBG("TODO - ON MORE CLICKED");
868 static void _on_del_clicked(void *data, Evas_Object *obj __UNUSED__,
869 void *event_info __UNUSED__)
871 Message_Info *m_info = data;
872 _message_info_del(m_info);
875 static Evas_Object *_item_content_get(void *data, Evas_Object *obj,
878 Evas_Object *btn = NULL;
879 Message_Info *msg = data;
881 if (strncmp(part, "elm.swallow.", strlen("elm.swallow.")))
883 part += strlen("elm.swallow.");
885 if (strcmp(part, "more") == 0) {
886 /* We can use the same button here */
887 btn = layout_add(obj, "history/img");
888 EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
889 elm_object_signal_callback_add(btn, "clicked,more", "gui",
890 _on_more_clicked, msg);
891 } else if (strcmp(part, "delete") == 0) {
892 btn = elm_button_add(obj);
893 EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
894 elm_object_style_set(btn, "history-delete");
895 elm_object_text_set(btn, "delete");
896 evas_object_smart_callback_add(btn, "clicked", _on_del_clicked,
898 evas_object_propagate_events_set(btn, EINA_FALSE);
901 ERR("unknown content part '%s'", part);
906 static void _on_list_slide_enter(void *data __UNUSED__,
910 Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
911 DBG("cancel decorated item=%p", it);
913 elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
916 EINA_SAFETY_ON_NULL_RETURN(it);
918 elm_genlist_item_decorate_mode_set(it, "slide", EINA_TRUE);
921 static void _on_list_slide_cancel(void *data __UNUSED__,
923 void *event_info __UNUSED__)
925 Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
928 elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
931 void _overview_messages_clear(Overview *ov)
933 Message_Info *m_info;
934 Eina_List *l, *l_next;
936 EINA_LIST_FOREACH_SAFE(ov->messages->list, l, l_next, m_info)
937 _message_info_del(m_info);
940 static void _on_layout_clicked(void *data, Evas_Object *o,
941 const char *emission, const char *source __UNUSED__)
944 DBG("signal: %s", emission);
946 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
947 emission += strlen("clicked,");
949 if (strcmp(emission, "edit") == 0) {
950 elm_object_signal_emit(o, "toggle,on,edit", "gui");
951 elm_genlist_decorate_mode_set(ov->genlist, EINA_TRUE);
952 } else if (strcmp(emission, "compose") == 0) {
953 elm_object_signal_emit(o, "toggle,on,compose", "gui");
954 elm_object_signal_emit(o, "toggle,off,view", "gui");
956 elm_object_signal_emit(o, "toggle,off,compose", "gui");
957 elm_object_signal_emit(o, "toggle,on,view", "gui");
958 } else if (strcmp(emission, "view") == 0) {
959 elm_object_signal_emit(o, "toggle,off,compose", "gui");
960 elm_object_signal_emit(o, "toggle,on,view", "gui");
961 } else if (strcmp(emission, "edit,done") == 0) {
962 elm_object_signal_emit(o, "toggle,off,edit", "gui");
963 elm_genlist_decorate_mode_set(ov->genlist, EINA_FALSE);
964 } else if (strcmp(emission, "clear") == 0) {
965 _overview_messages_clear(ov);
966 elm_object_signal_emit(o, "toggle,off,edit", "gui");
968 ERR("Unkown emission: %s", emission);
971 static void _sent_sms_cb(void *data, OFono_Error error, OFono_Sent_SMS *sms)
975 OFono_Sent_SMS_State state;
977 const char *dest, *message;
979 if (error != OFONO_ERROR_NONE) {
980 ERR("OFono error - Sending a SMS");
984 state = ofono_sent_sms_state_get(sms);
985 dest = ofono_sent_sms_destination_get(sms);
986 message = ofono_sent_sms_message_get(sms);
987 msg = eina_hash_find(ov->pending_sms, sms);
988 timestamp = ofono_sent_sms_timestamp_get(sms);
990 DBG("SMS Sent to: %s, message: %s, time: %ld", dest, message,
994 msg = message_new(timestamp, message, EINA_TRUE, state);
995 EINA_SAFETY_ON_NULL_RETURN(msg);
996 msg->phone = eina_stringshare_add(dest);
998 _message_info_genlist_update(ov, timestamp, dest, message);
1002 if (state == OFONO_SENT_SMS_STATE_FAILED ||
1003 state == OFONO_SENT_SMS_STATE_SENT)
1004 eina_hash_del_by_key(ov->pending_sms, sms);
1005 else if (state == OFONO_SENT_SMS_STATE_PENDING) {
1007 eina_hash_add(ov->pending_sms, sms, msg);
1008 ov->p_conversations->list = eina_list_append(ov->p_conversations->list,
1010 DBG("Added to pending conversations - msg:%p - to: %s - msg: %s",
1011 msg, dest, message);
1012 ov->p_conversations->dirty = EINA_TRUE;
1015 _conversation_eet_update(ov);
1018 Evas_Object *overview_add(Evas_Object *parent)
1020 Evas_Object *obj, *genlist;
1022 const char *config_path;
1025 Elm_Genlist_Item_Class *itc;
1030 ov = calloc(1, sizeof(Overview));
1031 EINA_SAFETY_ON_NULL_RETURN_VAL(ov, NULL);
1033 ov->p_conversations = calloc(1, sizeof(Messages_List));
1034 EINA_SAFETY_ON_NULL_GOTO(ov->p_conversations, err_conversations);
1036 ov->layout = obj = layout_add(parent, "messages-overview");
1037 EINA_SAFETY_ON_NULL_GOTO(obj, err_obj);
1039 elm_object_signal_callback_add(obj, "clicked,*", "gui",
1040 _on_layout_clicked, ov);
1042 genlist = elm_genlist_add(obj);
1043 EINA_SAFETY_ON_NULL_GOTO(genlist, err_genlist);
1044 elm_object_style_set(genlist, "messages-overview");
1045 elm_genlist_homogeneous_set(genlist, EINA_TRUE);
1047 elm_scroller_policy_set(genlist, ELM_SCROLLER_POLICY_OFF,
1048 ELM_SCROLLER_POLICY_AUTO);
1050 itc = elm_genlist_item_class_new();
1051 EINA_SAFETY_ON_NULL_GOTO(itc, err_itc);
1052 itc->item_style = "messages-overview";
1053 itc->func.text_get = _item_label_get;
1054 itc->func.content_get = _item_content_get;
1055 itc->func.state_get = NULL;
1056 itc->func.del = NULL;
1057 itc->decorate_all_item_style = "messages-overview-delete";
1058 itc->decorate_item_style = "messages-overview-delete";
1059 ov->genlist = genlist;
1062 evas_object_smart_callback_add(genlist, "drag,start,right",
1063 _on_list_slide_enter, ov);
1064 evas_object_smart_callback_add(genlist, "drag,start,left",
1065 _on_list_slide_cancel, ov);
1066 evas_object_smart_callback_add(genlist, "drag,start,down",
1067 _on_list_slide_cancel, ov);
1068 evas_object_smart_callback_add(genlist, "drag,start,up",
1069 _on_list_slide_cancel, ov);
1071 elm_object_part_content_set(obj, "elm.swallow.genlist", genlist);
1073 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
1075 evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide,
1077 evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show,
1080 e = evas_object_evas_get(obj);
1081 evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_OUT,
1082 _on_win_focus_out, ov);
1083 evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_IN,
1084 _on_win_focus_in, ov);
1086 evas_object_data_set(obj, "overview.ctx", ov);
1088 config_path = efreet_config_home_get();
1090 r = asprintf(&ov->base_dir, "%s/%s/messages", config_path,
1096 ecore_file_mkpath(ov->base_dir);
1098 r = asprintf(&ov->msg_path, "%s/%s/messages/messages.eet", config_path,
1104 r = asprintf(&ov->msg_bkp, "%s/%s/messages/messages.eet.bkp",
1105 config_path, PACKAGE_NAME);
1110 _eet_descriptors_init(&ov->edd_msg_list, &ov->edd_msg_info,
1111 &ov->edd_msg, &ov->edd_c_msg);
1112 _overview_messages_read(ov);
1114 ov->pending_sms = eina_hash_pointer_new(EINA_FREE_CB(message_del));
1115 EINA_SAFETY_ON_NULL_GOTO(ov->pending_sms, err_hash);
1117 incoming_sms = ofono_incoming_sms_cb_add(_incoming_sms_cb, ov);
1118 sent_sms = ofono_sent_sms_changed_cb_add(_sent_sms_cb, ov);
1119 elm_object_signal_emit(ov->layout, "toggle,on,view", "gui");
1130 elm_genlist_item_class_free(itc);
1132 evas_object_del(genlist);
1134 evas_object_del(obj);
1136 free(ov->p_conversations);
1139 ecore_file_shutdown();
1144 void overview_all_contact_messages_clear(Evas_Object *obj, const char *contact)
1147 Message_Info *m_info;
1149 EINA_SAFETY_ON_NULL_RETURN(obj);
1150 ov = evas_object_data_get(obj, "overview.ctx");
1151 EINA_SAFETY_ON_NULL_RETURN(ov);
1153 m_info = _message_info_search(ov, contact);
1154 EINA_SAFETY_ON_NULL_RETURN(m_info);
1155 _message_info_del(m_info);