messages implementation.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 2 Oct 2012 18:35:23 +0000 (15:35 -0300)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 2 Oct 2012 18:37:35 +0000 (15:37 -0300)
full messages implementation, squashed in a single commit.

27 files changed:
Makefile.am
README
configure.ac
data/themes/default-hd.edc
data/themes/default-sd.edc
data/themes/default.edc
data/themes/images/bg_chat_incoming.png [new file with mode: 0644]
data/themes/images/bg_chat_outgoing.png [new file with mode: 0644]
data/themes/images/ico_ball.png [new file with mode: 0644]
data/themes/images/ico_msg_delivered.png [new file with mode: 0644]
data/themes/includes/compose.edc
data/themes/includes/messages-overview-list.edc [new file with mode: 0644]
data/themes/includes/messages-overview.edc [new file with mode: 0644]
data/themes/includes/messages.edc
data/themes/includes/scroller.edc
messages/compose.c
messages/compose.h
messages/gui.c
messages/gui.h
messages/overview.c [new file with mode: 0644]
messages/overview.h [new file with mode: 0644]
tizen/message_daemon.c [new file with mode: 0644]
utils/contacts-ofono-efl.h
utils/contacts-tizen.c
utils/contacts.c
utils/util.c
utils/util.h

index 1932d51..7976663 100644 (file)
@@ -78,6 +78,8 @@ messages_messages_SOURCES = \
        messages/main.c \
        messages/rc.c \
        messages/rc.h \
+       messages/overview.c \
+       messages/overview.h \
        messages/gui.c \
        messages/gui.h \
        messages/compose.c \
@@ -92,6 +94,7 @@ tizen_answer_daemon_LDADD = @EFL_LIBS@ @TIZEN_LIBS@
 
 if HAVE_TIZEN
 bin_PROGRAMS += \
+       tizen/message_daemon \
        tizen/dialer_open \
        tizen/dialer_daemon
 
@@ -101,6 +104,9 @@ tizen_dialer_open_LDADD = @EFL_LIBS@ @TIZEN_LIBS@
 tizen_dialer_daemon_SOURCES = tizen/dialer_daemon.c
 tizen_dialer_daemon_LDADD = @EFL_LIBS@ @TIZEN_LIBS@
 
+tizen_message_daemon_SOURCES = tizen/message_daemon.c
+tizen_message_daemon_LDADD = @EFL_LIBS@ @TIZEN_LIBS@ utils/libofono-efl-utils.la
+
 %.service: %.service.in Makefile
        sed 's:@bindir[@]:$(bindir):g' $< > $@
 
@@ -161,14 +167,17 @@ am__v_EDJ_ = $(am__v_EDJ_$(AM_DEFAULT_VERBOSITY))
 am__v_EDJ_0 = @echo "  EDJ   " $@;
 
 THEME_IMAGES = \
-data/themes/images/bg_call.jpg \
-data/themes/images/arrow_right.png \
 data/themes/images/arrow_left.png \
+data/themes/images/arrow_right.png \
+data/themes/images/bg_call.jpg \
+data/themes/images/bg_chat_incoming.png \
+data/themes/images/bg_chat_outgoing.png \
 data/themes/images/bg_keypad.jpg \
 data/themes/images/ico_add_call.png \
 data/themes/images/ico_add_contact.png \
 data/themes/images/ico_arrow_right.png \
 data/themes/images/ico_backspace.png \
+data/themes/images/ico_ball.png \
 data/themes/images/ico_call.png \
 data/themes/images/ico_contacts.png \
 data/themes/images/ico_del.png \
@@ -176,6 +185,7 @@ data/themes/images/ico_edit.png \
 data/themes/images/ico_history.png \
 data/themes/images/ico_keypad.png \
 data/themes/images/ico_merge.png \
+data/themes/images/ico_msg_delivered.png \
 data/themes/images/ico_multiparty.png \
 data/themes/images/ico_multiparty_hangup.png \
 data/themes/images/ico_multiparty_private.png \
@@ -206,6 +216,8 @@ data/themes/includes/dialer.edc \
 data/themes/includes/history-bg.edc \
 data/themes/includes/history.edc \
 data/themes/includes/keypad.edc \
+data/themes/includes/messages-overview-list.edc \
+data/themes/includes/messages-overview.edc \
 data/themes/includes/messages.edc \
 data/themes/includes/multiparty-list.edc \
 data/themes/includes/popup.edc \
diff --git a/README b/README
index 596f8e3..f9a3279 100644 (file)
--- a/README
+++ b/README
@@ -19,8 +19,8 @@ To help debug, the following environment variables could be set:
        EINA_LOG_LEVEL=4
                toggles debug (level=4) of whole EFL
 
-       EINA_LOG_LEVELS=dialer:4
-               toggles debug of dialer logging domain.
+       EINA_LOG_LEVELS=dialer:4,messages:4
+               toggles debug of dialer and messages logging domains.
 
        EINA_LOG_ABORT=1
                make it abort on critical errors.
index d452242..d049edb 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ([2.60])
-AC_INIT([ofono-efl], [1])
+AC_INIT([ofono-efl], [2])
 
 AM_INIT_AUTOMAKE([foreign subdir-objects])
 AM_CONFIG_HEADER([config.h])
@@ -52,6 +52,7 @@ if test "$want_tizen" != "no"; then
                         utilX
                         aul
                         appsvc
+                        notification
                 ],
                 [have_tizen="yes"],
                 [have_tizen="no"])
index 4b22f68..4abad67 100644 (file)
 #define CALL_TEXT_OFFSET 32
 #define CALL_PHOTO_SIZE 180
 
+#define MESSAGE_IMG_SENT_SIZE 40
+
+#define MESSAGE_IMG_SENT_Y_OFFSET 0
+
+#define MESSAGE_SEPARATOR_WIDTH 344
+#define MESSAGE_SEPARATOR_HEIGHT 32
+
+#define MULTI_BUTTON_ENTRY_MAX_SIZE 300
+
 #include "default.edc"
index bf229b7..89ba0c5 100644 (file)
 #define CALL_TEXT_OFFSET 16
 #define CALL_PHOTO_SIZE 90
 
+#define MESSAGE_IMG_SENT_SIZE 16
+
+#define MESSAGE_IMG_SENT_Y_OFFSET 0
+
+#define MESSAGE_SEPARATOR_WIDTH 172
+#define MESSAGE_SEPARATOR_HEIGHT 16
+
+#define MULTI_BUTTON_ENTRY_MAX_SIZE 150
+
 #include "default.edc"
index ba2f5c2..ec38bf8 100644 (file)
@@ -17,5 +17,6 @@ collections {
 
 #include "includes/messages.edc"
 #include "includes/compose.edc"
-
+#include "includes/messages-overview.edc"
+#include "includes/messages-overview-list.edc"
 }
diff --git a/data/themes/images/bg_chat_incoming.png b/data/themes/images/bg_chat_incoming.png
new file mode 100644 (file)
index 0000000..64c8904
Binary files /dev/null and b/data/themes/images/bg_chat_incoming.png differ
diff --git a/data/themes/images/bg_chat_outgoing.png b/data/themes/images/bg_chat_outgoing.png
new file mode 100644 (file)
index 0000000..7250640
Binary files /dev/null and b/data/themes/images/bg_chat_outgoing.png differ
diff --git a/data/themes/images/ico_ball.png b/data/themes/images/ico_ball.png
new file mode 100644 (file)
index 0000000..3ba4d2f
Binary files /dev/null and b/data/themes/images/ico_ball.png differ
diff --git a/data/themes/images/ico_msg_delivered.png b/data/themes/images/ico_msg_delivered.png
new file mode 100644 (file)
index 0000000..8a8c88f
Binary files /dev/null and b/data/themes/images/ico_msg_delivered.png differ
index 004cb5e..1906b9f 100644 (file)
@@ -6,20 +6,53 @@ group {
     *
     * Parts:
     *
+    * TEXT: elm.text.name - Name of the contact/number.
+    * TEXT: elm.text.size - Size of the message (number of characters)
+    * SWALLOW: elm.swallow.destination - Text Entry - Contacts that the message will be sent
+    * SWALLOW: elm.swallow.message - Text Entry - Content of the message
+    * SWALLOW: elm.swallow.genlist - Where the message thread is going to appear
+    * IMAGE: elm.img.btn.send - A Button to send the message
+    *
     * Signals:
     *   Emit (source is "gui"):
+    *   clicked,<ID>:  key <ID> was clicked (press and release in the key)
+    *   clicked,edit - When the edit button is cliked
+    *   clicked,edit,done - When The Button "Done" while editing is clicked
+    *   clicked,send_msg - When elm.img.btn.send is clicked
+    *
     *   Listens (source is "gui"):
+    *   show,genlist  - Show the genlist with the current message thread
+    *   hidden,genlist - Hide the genlist
+    *   toggle,on,edit - User is editing
+    *   toggle,off,edit - User finished the editing
+    *
+    * Messages:
+    *   1 - INT_SET: tuple of message size and maximum size.
+    *
+    * Where <ID> is the name of the button
     *
     */
 
+   images {
+      image: "bg_keypad.jpg" COMP;
+      image: "ico_arrow_right.png" COMP;
+      image: "ico_ball.png" COMP;
+   }
+
    parts {
       part {
          name: "bg";
-         type: RECT;
+         type: IMAGE;
          mouse_events: 0;
          description {
             state: "default" 0.0;
-            color: 255 0 0 255; /* TODO */
+            color: 255 255 255 255;
+            color_class: "dark";
+            image {
+               normal: "bg_keypad.jpg";
+               scale_hint: STATIC;
+            }
+            fill.smooth: 1;
          }
       }
 
@@ -37,5 +70,2168 @@ group {
             }
          }
       }
-   }
-}
+
+      part {
+         name: "button.area.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+            rel1.to: "bg.buttons";
+            rel2 {
+               to: "bg.buttons";
+               offset: -1 SEPARATOR_HEIGHT;
+            }
+         }
+      }
+
+      part {
+         name: "button.clipper";
+         type: RECT;
+         clip_to: "button.area.clipper";
+         description {
+            state: "default" 0.0;
+            rel1.to: "button.area.clipper";
+            rel2.to: "button.area.clipper";
+         }
+         description {
+            state: "alternate" 0.0;
+            color: 255 255 255 0;
+            visible: 0;
+         }
+      }
+
+      part {
+         name: "edit-button.clipper";
+         type: RECT;
+         clip_to: "button.area.clipper";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 0;
+            visible: 0;
+            rel1.to: "button.area.clipper";
+            rel2.to: "button.area.clipper";
+         }
+         description {
+            state: "alternate" 0.0;
+            color: 255 255 255 255;
+            visible: 1;
+         }
+      }
+
+      part {
+         name: "edit.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+            rel1.to: "bg.edit";
+            rel2 {
+               to: "bg.edit";
+               offset: -1 SEPARATOR_HEIGHT;
+            }
+         }
+      }
+
+      part {
+         name: "bg.buttons";
+         type: RECT;
+         mouse_events: 0;
+         clip_to: "button.clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            fixed: 1 1;
+            min: 0 (ACTION_HEIGHT / 2);
+            rel1 {
+               to: "notification.bar";
+               relative: 0.0 1.0;
+            }
+            rel2 {
+               to_x: "bg.edit";
+               to_y: "notification.bar";
+               relative: 0.0 1.0;
+               offset: (-ITEM_PADDING - 1) (ACTION_HEIGHT / 2 - 1);
+            }
+         }
+         description {
+            state: "compose" 0.0;
+            inherit: "default" 0.0;
+            rel2 {
+               to: "notification.bar";
+               relative: 1.0 1.0;
+               offset: -1 (ACTION_HEIGHT / 2 - 1);
+            }
+         }
+      }
+
+      part {
+         name: "header.name.bg";
+         type: RECT;
+         mouse_events: 0;
+         clip_to: "button.clipper";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "action";
+            rel1.to: "bg.buttons";
+            rel2.to: "bg.buttons";
+         }
+      }
+
+      part {
+         name: "elm.text.name";
+         type: TEXT;
+         mouse_events: 0;
+         clip_to: "button.clipper";
+         api: "name" "message destination name";
+         description {
+            state: "default" 0.0;
+            color: 16 16 16 255;
+            color_class: "action";
+            rel1 {
+               to: "bg.buttons";
+               offset: ITEM_PADDING 0;
+            }
+            rel2 {
+               to: "bg.buttons";
+               offset: (-ITEM_PADDING - 1) -1;
+            }
+            text {
+               font: FONT_NORMAL;
+               size: SIZE_LARGE;
+               align: 0.5 0.5;
+               ellipsis: 0.0;
+            }
+         }
+      }
+
+      part {
+         name: "bg.edit";
+         type: RECT;
+         mouse_events: 0;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            min: 0 (ACTION_HEIGHT / 2);
+            rel1 {
+               to: "notification.bar";
+               relative: 1.0 1.0;
+               offset: (-LIST_ICON_SIZE - ITEM_PADDING - BORDER_PADDING) 0;
+            }
+            rel2 {
+               to: "notification.bar";
+               relative: 1.0 1.0;
+               offset: -1 (ACTION_HEIGHT / 2 - 1);
+            }
+         }
+      }
+
+#define SEPARATOR(id, clip, rely, offy, relto)                          \
+      part {                                                            \
+         name: "separator.dark."##id;                                   \
+         type: RECT;                                                    \
+         mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: "dark";                                        \
+            rel1 {                                                      \
+               relative: 0.0 rely;                                      \
+               offset: 0 offy;                                          \
+               to_y: relto;                                             \
+            }                                                           \
+            rel2 {                                                      \
+               relative: 1.0 rely;                                      \
+               offset: -1 (offy + SEPARATOR_HEIGHT / 2);                \
+               to_y: relto;                                             \
+            }                                                           \
+         }                                                              \
+      }                                                                 \
+      part {                                                            \
+         name: "separator.bg."##id;                                     \
+         type: RECT;                                                    \
+         mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: "bg";                                          \
+            rel1 {                                                      \
+               relative: 0.0 rely;                                      \
+               offset: 0 (offy + SEPARATOR_HEIGHT / 2);                 \
+               to_y: relto;                                             \
+            }                                                           \
+            rel2 {                                                      \
+               relative: 1.0 rely;                                      \
+               offset: -1 (offy + SEPARATOR_HEIGHT);                    \
+               to_y: relto;                                             \
+            }                                                           \
+         }                                                              \
+      }
+
+      SEPARATOR("button", "button.area.clipper", 1.0, 0, "bg.buttons");
+      SEPARATOR("edit-button", "button.area.clipper", 1.0, 0, "bg.buttons");
+      SEPARATOR("edit", "edit.clipper", 1.0, 0, "bg.edit");
+#undef SEPARATOR
+
+
+#define BUTTON(id, label, ccls, clip, r1, r2)                           \
+      part {                                                            \
+         name: "button."##id;                                           \
+         type: RECT;                                                    \
+         mouse_events: 1;                                               \
+         clip_to: clip;                                                 \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 0;                                       \
+            color_class: "action";                                      \
+            rel1 {                                                      \
+               to: "bg.buttons";                                        \
+               relative: r1;                                            \
+            }                                                           \
+            rel2 {                                                      \
+               to: "bg.buttons";                                        \
+               relative: r2;                                            \
+            }                                                           \
+         }                                                              \
+         description {                                                  \
+            state: "pressed" 0.0;                                       \
+            inherit: "default" 0.0;                                     \
+            color: 255 255 255 255;                                     \
+         }                                                              \
+      }                                                                 \
+      part {                                                            \
+         name: "label."##id;                                            \
+         type: TEXT;                                                    \
+         mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: ccls;                                          \
+            rel1.to: "button."##id;                                     \
+            rel2 {                                                      \
+               to: "button."##id;                                       \
+            }                                                           \
+            text {                                                      \
+               text: label;                                             \
+               font: FONT_NORMAL;                                       \
+               size: SIZE_MEDIUM;                                       \
+               align: 0.5 0.5;                                          \
+            }                                                           \
+         }                                                              \
+         description {                                                  \
+            state: "pressed" 0.0;                                       \
+            inherit: "default" 0.0;                                     \
+            color: 16 16 16 255;                                        \
+         }                                                              \
+      }                                                                 \
+                                                                        \
+      programs {                                                        \
+         program {                                                      \
+            signal: "toggle,on,"##id;                                   \
+            source: "gui";                                              \
+            action: STATE_SET "pressed" 0.0;                            \
+            target: "button."##id;                                      \
+            target: "label."##id;                                       \
+         }                                                              \
+         program {                                                      \
+            signal: "toggle,off,"##id;                                  \
+            source: "gui";                                              \
+            action: STATE_SET "default" 0.0;                            \
+            target: "button."##id;                                      \
+            target: "label."##id;                                       \
+         }                                                              \
+         program {                                                      \
+            signal: "mouse,clicked,1";                                  \
+            source: "button."##id;                                      \
+            action: SIGNAL_EMIT "clicked,"##id "gui";                   \
+            api: id"_clicked" id" was clicked";                         \
+         }                                                              \
+      }
+
+      BUTTON("clear",     "Clear", "caution", "edit-button.clipper", 0.0 0.0, 0.5 1.0);
+      BUTTON("edit,done", "Done",  "action", "edit-button.clipper", 0.5 0.0, 1.0 1.0);
+#undef BUTTON
+
+      part {
+         name: "button.edit";
+         type: RECT;
+         mouse_events: 1;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 0;
+            color_class: "caution";
+            rel1.to: "bg.edit";
+            rel2.to: "bg.edit";
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 255;
+         }
+         description {
+            state: "compose" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      part {
+         name: "ico.edit";
+         type: IMAGE;
+         mouse_events: 0;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            min: LIST_ICON_SIZE LIST_ICON_SIZE;
+            max: LIST_ICON_SIZE LIST_ICON_SIZE;
+            align: 0.0 0.5;
+            color: 255 255 255 255;
+            color_class: "caution";
+            rel1 {
+               to: "button.edit";
+               offset: ITEM_PADDING 0;
+            }
+            rel2 {
+               to: "button.edit";
+               offset: (-BORDER_PADDING - 1) -1;
+            }
+            image {
+               normal: "ico_del.png";
+               scale_hint: STATIC;
+            }
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            color: 16 16 16 255;
+         }
+         description {
+            state: "compose" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      part {
+         name: "button.over.edit";
+         type: RECT;
+         mouse_events: 1;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            visible: 0;
+            rel1.to: "bg.edit";
+            rel2.to: "bg.edit";
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+         }
+         description {
+            state: "compose" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+
+      part {
+         name: "ico.ball";
+         type: IMAGE;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            visible: 0;
+            color: 255 255 255 255;
+            color_class: "action";
+            rel1.to: "bg.edit";
+            rel2.to: "bg.edit";
+            min: LIST_ICON_SIZE LIST_ICON_SIZE;
+            max: LIST_ICON_SIZE LIST_ICON_SIZE;
+            image {
+               normal: "ico_ball.png";
+               scale_hint: STATIC;
+            }
+         }
+         description {
+            state: "visible" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+         }
+      }
+
+      part {
+         name: "elm.text.names_count";
+         type: TEXT;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 255;
+            visible: 0;
+            rel1.to: "ico.ball";
+            rel2.to: "ico.ball";
+            text {
+               font: FONT_NORMAL;
+               size: SIZE_LARGE;
+               size_range: SIZE_SMALL SIZE_LARGE;
+               fit: 1 1;
+               align: 0.5 0.5;
+            }
+         }
+         description {
+            state: "visible" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+         }
+      }
+
+      part {
+         name: "elm.swallow.destination";
+         type: SWALLOW;
+         api: "destination" "where to swallow destination field";
+         description {
+            state: "default" 0.0;
+            visible: 1;
+            rel1 {
+               to_y: "separator.bg.button";
+               relative: 0.0 1.0;
+               offset: BORDER_PADDING 0;
+            }
+            rel2 {
+               to: "separator.bg.button";
+               relative: 0.0 1.0;
+               offset: (WIDTH -2 * BORDER_PADDING) ACTION_HEIGHT;
+            }
+         }
+         description {
+            state: "hidden" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+
+      part {
+         name: "clipper.contacts.visible";
+         type: RECT;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            visible: 1;
+         }
+         description {
+            state: "alternate" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+            color: 255 255 255 0;
+         }
+      }
+
+      part {
+         name: "elm.swallow.genlist";
+         type: SWALLOW;
+         api: "genlist" "where to swallow list of messages";
+         clip_to: "clipper.contacts.visible";
+         description {
+            state: "default" 0.0;
+            visible: 0;
+            rel1 {
+               to_y: "separator.bg.button";
+               relative: 0.0 1.0;
+            }
+            rel2 {
+               to: "bg.entry.msg";
+               relative: 1.0 0.0;
+               offset: -1 -1;
+            }
+         }
+         description {
+            state: "visible" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+         }
+      }
+
+      part {
+         name: "bg.entry.msg";
+         type: RECT;
+         mouse_events: 0;
+         clip_to: "clipper.contacts.visible";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 255;
+            rel1 {
+               to: "separator.dark.back";
+               relative: 0.0 0.0;
+               offset: 0 (-ACTION_HEIGHT);
+            }
+            rel2 {
+               to: "separator.dark.back";
+               relative: 1.0 0.0;
+               offset: 0 -1;
+            }
+         }
+      }
+
+      part {
+         name: "elm.swallow.message";
+         type: SWALLOW;
+         api: "message" "where to swallow the message editor";
+         clip_to: "clipper.contacts.visible";
+         description {
+            state: "default" 0.0;
+            rel1 {
+               to: "bg.entry.msg";
+               relative: 0.0 0.0;
+            }
+            rel2 {
+               to_x: "elm.img.btn.send";
+               to_y: "bg.entry.msg";
+               relative: 0.0 0.6;
+               offset: -ITEM_PADDING -1;
+            }
+         }
+      }
+
+      part {
+         name: "elm.img.btn.send";
+         type: IMAGE;
+         clip_to: "clipper.contacts.visible";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "action";
+            min: LIST_ICON_SIZE LIST_ICON_SIZE;
+            max: LIST_ICON_SIZE LIST_ICON_SIZE;
+            align: 1.0 0.5;
+            fixed: 1 1;
+            rel1 {
+               to: "bg.entry.msg";
+               relative: 1.0 0.0;
+               offset: -BORDER_PADDING 0;
+            }
+            rel2 {
+               to: "bg.entry.msg";
+               relative: 1.0 1.0;
+               offset: -BORDER_PADDING -1;
+            }
+            image {
+               normal: "ico_arrow_right.png";
+            }
+         }
+      }
+
+      part {
+         name: "elm.text.size";
+         type: TEXT;
+         mouse_events: 0;
+         api: "size" "message size (in characters)";
+         clip_to: "clipper.contacts.visible";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "light";
+            fixed: 1 1;
+            rel1 {
+               to: "elm.text.separator_size";
+               relative: 0.0 0.0;
+               offset: (-ITEM_PADDING - 1 - ITEM_PADDING) 0;
+            }
+            rel2 {
+               to: "elm.text.separator_size";
+               relative: 0.0 1.0;
+               offset: 0 -1;
+            }
+            text {
+               text: "999";
+               font: FONT_NORMAL;
+               size: SIZE_SMALL;
+               min: 1 0;
+            }
+         }
+      }
+
+      part {
+         name: "elm.text.separator_size";
+         type: TEXT;
+         mouse_events: 0;
+         clip_to: "clipper.contacts.visible";
+         api: "separator" "A separator for size and max size";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "light";
+            fixed: 1 1;
+            rel1 {
+               to: "elm.img.btn.send";
+               relative: 0.5 1.0;
+               offset: 0 ITEM_PADDING;
+            }
+            rel2 {
+               to_x: "elm.img.btn.send";
+               to_y: "bg.entry.msg";
+               relative: 0.5 1.0;
+            }
+            text {
+               text: "/";
+               font: FONT_NORMAL;
+               size: SIZE_SMALL;
+               min: 1 0;
+            }
+         }
+      }
+
+      part {
+         name: "elm.text.max_size";
+         type: TEXT;
+         mouse_events: 0;
+         api: "max size" "max size of the SMS";
+         clip_to: "clipper.contacts.visible";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "light";
+            rel1 {
+               to: "elm.text.separator_size";
+               relative: 1.0 0.0;
+            }
+            rel2 {
+               to: "bg.entry.msg";
+               relative: 1.0 1.0;
+            }
+            text {
+               text: "160";
+               font: FONT_NORMAL;
+               size: SIZE_SMALL;
+               align: 0.0 0.5;
+            }
+         }
+      }
+
+#define SEPARATOR(id, rely, offy, relto)                               \
+      part {                                                            \
+         name: "separator.dark."##id;                                   \
+         type: RECT;                                                    \
+         mouse_events: 0;                                               \
+         clip_to: "clipper.contacts.visible";                           \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: "dark";                                        \
+            rel1 {                                                      \
+               relative: 0.0 rely;                                      \
+               offset: 0 offy;                                          \
+               to_y: relto;                                             \
+            }                                                           \
+            rel2 {                                                      \
+               relative: 1.0 rely;                                      \
+               offset: -1 (offy + SEPARATOR_HEIGHT / 2);                \
+               to_y: relto;                                             \
+            }                                                           \
+         }                                                              \
+      }                                                                 \
+      part {                                                            \
+         name: "separator.bg."##id;                                     \
+         type: RECT;                                                    \
+         clip_to: "clipper.contacts.visible";                           \
+         mouse_events: 0;                                               \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: "bg";                                          \
+            rel1 {                                                      \
+               relative: 0.0 rely;                                      \
+               offset: 0 (offy + SEPARATOR_HEIGHT / 2);                 \
+               to_y: relto;                                             \
+            }                                                           \
+            rel2 {                                                      \
+               relative: 1.0 rely;                                      \
+               offset: -1 (offy + SEPARATOR_HEIGHT);                    \
+               to_y: relto;                                             \
+            }                                                           \
+         }                                                              \
+      }
+
+      SEPARATOR("back", 0.0, -SEPARATOR_HEIGHT, "bg.buttons.back");
+#undef SEPARATOR
+
+      part {
+         name: "bg.buttons.back";
+         type: RECT;
+         mouse_events: 0;
+         clip_to: "clipper.contacts.visible";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            min: WIDTH ACTION_HEIGHT;
+            max: 99999 99999; /* keep it tight centered */
+            rel1 {
+               relative: 0.0 1.0;
+               offset: 0 -ACTION_HEIGHT;
+            }
+         }
+      }
+#define BUTTON(id, label, ccls, r1, r2)                                 \
+      part {                                                            \
+         name: "button."##id;                                           \
+         type: RECT;                                                    \
+         clip_to: "clipper.contacts.visible";                           \
+         mouse_events: 1;                                               \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 0;                                       \
+            color_class: "action";                                      \
+            rel1 {                                                      \
+           to: "bg.buttons.back";                                      \
+               relative: r1;                                            \
+            }                                                           \
+            rel2 {                                                      \
+           to: "bg.buttons.back";                                      \
+               relative: r2;                                            \
+            }                                                           \
+         }                                                              \
+         description {                                                  \
+            state: "pressed" 0.0;                                       \
+            inherit: "default" 0.0;                                     \
+            color: 255 255 255 255;                                     \
+         }                                                              \
+      }                                                                 \
+      part {                                                            \
+         name: "label."##id;                                            \
+         type: TEXT;                                                    \
+         clip_to: "clipper.contacts.visible";                           \
+         mouse_events: 0;                                               \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: ccls;                                          \
+            rel1.to: "button."##id;                                     \
+            rel2 {                                                      \
+               to: "button."##id;                                       \
+            }                                                           \
+            text {                                                      \
+               text: label;                                             \
+               font: FONT_NORMAL;                                       \
+               size: SIZE_HUGE;                                         \
+               align: 0.5 0.5;                                          \
+            }                                                           \
+         }                                                              \
+         description {                                                  \
+            state: "pressed" 0.0;                                       \
+            inherit: "default" 0.0;                                     \
+            color: 16 16 16 255;                                        \
+         }                                                              \
+      }                                                                 \
+                                                                        \
+      programs {                                                        \
+         program {                                                      \
+            signal: "mouse,up,1";                                       \
+            source: "button."##id;                                      \
+            action: SIGNAL_EMIT "released,"##id "keypad";               \
+            after: "show_up_"##id;                                      \
+            api: id"_released" id" was released";                       \
+         }                                                              \
+         program {                                                      \
+            name: "show_up_"##id;                                       \
+            action: STATE_SET "default" 0.0;                            \
+            transition: DECELERATE 0.1;                                 \
+            target: "button."##id;                                      \
+            target: "label."##id;                                       \
+         }                                                              \
+         program {                                                      \
+            signal: "mouse,down,1";                                     \
+            source: "button."##id;                                      \
+            after: "show_down_"##id;                                    \
+            action: SIGNAL_EMIT "pressed,"##id "keypad";                \
+            api: id"_pressed" id" was pressed";                         \
+         }                                                              \
+         program {                                                      \
+            name: "show_down_"##id;                                     \
+            action: STATE_SET "pressed" 0.0;                            \
+            transition: ACCELERATE 0.1;                                 \
+            target: "button."##id;                                      \
+            target: "label."##id;                                       \
+         }                                                              \
+         program {                                                      \
+            signal: "mouse,clicked,1";                                  \
+            source: "button."##id;                                      \
+            action: SIGNAL_EMIT "clicked,"##id "gui";                   \
+            api: id"_clicked" id" was clicked";                         \
+         }                                                              \
+      }
+
+      BUTTON("back",    "Back",    "action", 0.0 0.0, 1.0 1.0);
+#undef BUTTON
+
+      part {
+         name: "elm.swallow.genlist.contacts";
+         type: SWALLOW;
+         api: "contacts genlist" "A genlist to be filled with contacts";
+         description {
+            state: "default" 0.0;
+            visible: 0;
+            rel1 {
+               to_y: "elm.swallow.destination";
+               relative: 0.0 1.0;
+               offset: 0 ITEM_PADDING;
+            }
+         }
+         description {
+            state: "alternate" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+         }
+      }
+   }
+   programs {
+
+      program {
+         signal: "contacts,hidden";
+         source: "gui";
+         action: STATE_SET "default" 0.0;
+         target: "elm.swallow.genlist.contacts";
+         target: "clipper.contacts.visible";
+      }
+      program {
+         signal: "contacts,show";
+         source: "gui";
+         action: STATE_SET "alternate" 0.0;
+         target: "elm.swallow.genlist.contacts";
+         target: "clipper.contacts.visible";
+      }
+      program {
+         signal: "show,genlist";
+         source: "gui";
+         after: "hide,entry,to";
+         after: "show,genlist";
+      }
+      program {
+         signal: "hidden,genlist";
+         source: "gui";
+         after: "show,entry,to";
+         after: "hide,genlist";
+      }
+      program {
+         name: "hide,entry,to";
+         action: STATE_SET "hidden" 0.0;
+         target: "elm.swallow.destination";
+      }
+      program {
+         name: "show,entry,to";
+         action: STATE_SET "default" 0.0;
+         target: "elm.swallow.destination";
+      }
+      program {
+         name: "hide,genlist";
+         action: STATE_SET "default" 0.0;
+         target: "elm.swallow.genlist";
+      }
+      program {
+         name: "show,genlist";
+         action: STATE_SET "visible" 0.0;
+         target: "elm.swallow.genlist";
+      }
+      program {
+         signal: "mouse,clicked,1";
+         source: "elm.img.btn.send";
+         action: SIGNAL_EMIT "clicked,send_msg" "gui";
+      }
+      program {
+         signal: "toggle,on,edit";
+         source: "gui";
+         action: STATE_SET "pressed" 0.0;
+         target: "button.edit";
+         target: "button.over.edit";
+         target: "ico.edit";
+         after: "show_edit_buttons";
+      }
+      program {
+         name: "show_edit_buttons";
+         action: STATE_SET "alternate" 0.0;
+         transition: ACCELERATE 0.3;
+         target: "button.clipper";
+         target: "edit-button.clipper";
+      }
+
+      program {
+         signal: "toggle,off,edit";
+         source: "gui";
+         action: STATE_SET "default" 0.0;
+         target: "button.edit";
+         target: "button.over.edit";
+         target: "ico.edit";
+         after: "hide_edit_buttons";
+      }
+      program {
+         name: "hide_edit_buttons";
+         action: STATE_SET "default" 0.0;
+         transition: ACCELERATE 0.3;
+         target: "button.clipper";
+         target: "edit-button.clipper";
+      }
+
+      program {
+         signal: "mouse,clicked,1";
+         source: "button.edit";
+         action: SIGNAL_EMIT "clicked,edit" "gui";
+         api: "edit was clicked";
+      }
+      program {
+         signal: "mouse,clicked,1";
+         source: "button.over.edit";
+         action: SIGNAL_EMIT "clicked,edit,done" "gui";
+         api: "edit_done was clicked";
+      }
+      program {
+         signal: "composing";
+         source: "gui";
+         action: STATE_SET "compose" 0.0;
+         target: "bg.buttons";
+         target: "button.edit";
+         target: "ico.edit";
+         target: "button.over.edit";
+      }
+      program {
+         signal: "viewing";
+         source: "gui";
+         action: STATE_SET "default" 0.0;
+         target: "bg.buttons";
+         target: "button.edit";
+         target: "ico.edit";
+         target: "button.over.edit";
+      }
+      program {
+         signal: "names_count,show";
+         source: "gui";
+         action: STATE_SET "default" 0.0;
+         target: "bg.buttons";
+         after: "names_count.visible";
+      }
+      program {
+         name: "names_count.visible";
+         action: STATE_SET "visible" 0.0;
+         target: "elm.text.names_count";
+         target: "ico.ball";
+      }
+      program {
+         signal: "names_count,hidden";
+         source: "gui";
+         action: STATE_SET "default" 0.0;
+         target: "elm.text.names_count";
+         target: "ico.ball";
+      }
+
+   }
+}
+
+group {
+   name: "elm/genlist/item_compress/messages-outgoing/default";
+
+    data {
+       item: "texts" "text.msg.content text.msg.time";
+       item: "states" "sent failed";
+       item: "contents" "swallow.btn.resend";
+    }
+
+    images {
+       image: "bg_chat_outgoing.png" COMP;
+       image: "ico_msg_delivered.png" COMP;
+    }
+
+    styles {
+       style {
+          name: "entry_textblock_style_outgoing";
+          base: "font="FONT_NORMAL" font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_LIGHT" wrap=mixed valign=top align=right";
+          tag: "br" "\n";
+       }
+       style {
+          name: "entry_textblock_style_outgoing_failed";
+          base: "font="FONT_NORMAL" font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_CAUTION" wrap=mixed valign=top align=right";
+          tag: "br" "\n";
+       }
+    }
+
+    parts {
+       part {
+          name: "bg";
+          type: RECT;
+          mouse_events: 1;
+          description {
+             state: "default" 0.0;
+             color: 255 255 255 0;
+             color_class: "action";
+          }
+          description {
+             state: "selected" 0.0;
+             inherit: "default" 0.0;
+             color: 255 255 255 255;
+          }
+       }
+
+       part {
+          name: "text.msg.content";
+          type: TEXTBLOCK;
+          mouse_events: 0;
+          description {
+             state: "default" 0.0;
+             align: 0.0 0.0;
+             rel1 {
+                relative: 0.25 0.0;
+                offset: 0 ITEM_PADDING;
+             }
+             rel2 {
+                offset: (-BORDER_PADDING - ITEM_PADDING - 1) (-MESSAGE_IMG_SENT_SIZE -MESSAGE_SEPARATOR_HEIGHT -ITEM_PADDING -1);
+             }
+             text {
+                style: "entry_textblock_style_outgoing";
+                min: 0 1;
+             }
+          }
+          description {
+             state: "failed" 0.0;
+             inherit: "default" 0.0;
+             text {
+                min: 0 1;
+                style: "entry_textblock_style_outgoing_failed";
+             }
+          }
+       }
+
+       part {
+          name: "img.msg.separator";
+          type: IMAGE;
+          mouse_events: 0;
+          description {
+             state: "default" 0.0;
+             color: 255 255 255 255;
+             color_class: "light";
+             min: MESSAGE_SEPARATOR_WIDTH MESSAGE_SEPARATOR_HEIGHT;
+             max: MESSAGE_SEPARATOR_WIDTH MESSAGE_SEPARATOR_HEIGHT;
+             align: 1.0 1.0;
+             rel1 {
+                relative: 1.0 1.0;
+                offset: (-ITEM_PADDING -ITEM_PADDING - 1) (-MESSAGE_IMG_SENT_SIZE - ITEM_PADDING - 1);
+             }
+             rel2 {
+                relative: 1.0 1.0;
+                offset: (-ITEM_PADDING -ITEM_PADDING - 1) (-MESSAGE_IMG_SENT_SIZE - ITEM_PADDING - 1);
+             }
+             image.normal: "bg_chat_outgoing.png";
+          }
+          description {
+             state: "failed" 0.0;
+             inherit: "default" 0.0;
+             color_class: "caution";
+          }
+       }
+
+       part {
+          name: "text.msg.time";
+          type: TEXT;
+          mouse_events: 0;
+          description {
+             state: "default" 0.0;
+             color: 255 255 255 128;
+             color_class: "light";
+             align: 0.0 0.0;
+             fixed: 1 1;
+             rel1 {
+                to_x: "img.msg.separator";
+                to_y: "text.msg.content";
+                relative: 0.0 1.0;
+                offset: 0 SEPARATOR_HEIGHT;
+             }
+             rel2 {
+                relative: 1.0 1.0;
+                offset: (-MESSAGE_IMG_SENT_SIZE - 2 * BORDER_PADDING - ITEM_PADDING - 1) (-ITEM_PADDING -1);
+             }
+             text {
+                text: "time";
+                font: FONT_NORMAL;
+                size: SIZE_MEDIUM;
+                align: 0.0 0.0;
+                max: 1 0;
+             }
+          }
+          description {
+             state: "failed" 0.0;
+             inherit: "default" 0.0;
+             visible: 0;
+          }
+       }
+
+       part {
+          name: "swallow.btn.resend";
+          type: SWALLOW;
+          description {
+             state: "default" 0.0;
+             color: 255 255 255 128;
+             color_class: "caution";
+             align: 0.0 0.0;
+             fixed: 1 1;
+             visible: 0;
+             rel1 {
+                to_x: "img.msg.separator";
+                to_y: "text.msg.content";
+                relative: 0.0 1.0;
+                offset: 0 SEPARATOR_HEIGHT;
+             }
+             rel2 {
+                to: "img.msg.separator";
+                relative: 1.0 1.0;
+                offset: -ITEM_PADDING ITEM_PADDING;
+             }
+          }
+          description {
+             state: "failed" 0.0;
+             inherit: "default" 0.0;
+             visible: 1;
+          }
+       }
+
+       part {
+          name: "img.sent";
+          type: IMAGE;
+          description {
+             color: 255 255 255 255;
+             color_class: "light";
+             min: MESSAGE_IMG_SENT_SIZE MESSAGE_IMG_SENT_SIZE;
+             max: MESSAGE_IMG_SENT_SIZE MESSAGE_IMG_SENT_SIZE;
+             visible: 0;
+             align: 0.0 0.0;
+             rel1 {
+                to: "text.msg.time";
+                relative: 1.0 0.0;
+                offset: ITEM_PADDING -MESSAGE_IMG_SENT_Y_OFFSET;
+             }
+             image.normal: "ico_msg_delivered.png";
+          }
+          description {
+             state: "visible" 0.0;
+             inherit: "default" 0.0;
+             visible: 1;
+          }
+       }
+    }
+
+    programs {
+       program {
+          signal: "elm,state,sent,active";
+          source: "elm";
+          action: STATE_SET "visible" 0.0;
+          target: "img.sent";
+       }
+       program {
+          signal: "elm,state,sent,passive";
+          source: "elm";
+          action: STATE_SET "default" 0.0;
+          target: "img.sent";
+       }
+       program {
+          signal: "elm,state,failed,active";
+          source: "elm";
+          action: STATE_SET "failed" 0.0;
+          target: "img.msg.separator";
+          target: "text.msg.content";
+          target: "swallow.btn.resend";
+          target: "text.msg.time";
+       }
+       program {
+          signal: "elm,state,failed,passive";
+          source: "elm";
+          action: STATE_SET "default" 0.0;
+          target: "img.msg.separator";
+          target: "text.msg.content";
+          target: "swallow.btn.resend";
+          target: "text.msg.time";
+       }
+    }
+}
+
+group {
+   name: "elm/genlist/item_compress/messages-incoming/default";
+    data {
+       item: "texts" "text.msg.content text.msg.time";
+    }
+    images {
+       image: "bg_chat_incoming.png" COMP;
+    }
+
+    styles {
+       style {
+          name: "entry_textblock_style_incoming";
+          base: "font="FONT_NORMAL" font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_ACTION" wrap=mixed valign=top align=left";
+          tag: "br" "\n";
+       }
+    }
+
+    parts {
+       part {
+          name: "bg";
+          type: RECT;
+          mouse_events: 1;
+          description {
+             state: "default" 0.0;
+             color: 255 255 255 0;
+             color_class: "action";
+          }
+          description {
+             state: "selected" 0.0;
+             inherit: "default" 0.0;
+             color: 255 255 255 255;
+          }
+       }
+
+       part {
+          name: "text.msg.content";
+          type: TEXTBLOCK;
+          mouse_events: 0;
+          description {
+             state: "default" 0.0;
+             align: 0.0 0.0;
+             rel1.offset: BORDER_PADDING ITEM_PADDING;
+             rel2 {
+                relative: 0.75 1.0;
+                offset: 0 (-MESSAGE_IMG_SENT_SIZE -MESSAGE_SEPARATOR_HEIGHT -ITEM_PADDING -1);
+             }
+             text {
+                style: "entry_textblock_style_incoming";
+                min: 0 1;
+             }
+          }
+       }
+
+       part {
+          name: "img.msg.separator";
+          type: IMAGE;
+          mouse_events: 0;
+          description {
+             state: "default" 0.0;
+             color: 255 255 255 255;
+             color_class: "action";
+             min: MESSAGE_SEPARATOR_WIDTH MESSAGE_SEPARATOR_HEIGHT;
+             max: MESSAGE_SEPARATOR_WIDTH MESSAGE_SEPARATOR_HEIGHT;
+             align: 0.0 0.0;
+             rel1 {
+                to_y: "text.msg.content";
+                relative: 0.0 1.0;
+                offset: ITEM_PADDING 0;
+             }
+             rel2 {
+                relative: 0.0 1.0;
+                offset: (ITEM_PADDING + MESSAGE_SEPARATOR_WIDTH) -1;
+             }
+             image.normal: "bg_chat_incoming.png";
+          }
+       }
+
+       part {
+          name: "text.msg.time";
+          type: TEXT;
+          mouse_events: 0;
+          description {
+             state: "default" 0.0;
+             color: 255 255 255 128;
+             color_class: "action";
+             align: 1.0 0.0;
+             fixed: 1 1;
+             rel1 {
+                to_x: "img.msg.separator";
+                to_y: "text.msg.content";
+                relative: 0.0 1.0;
+                offset: BORDER_PADDING SEPARATOR_HEIGHT;
+             }
+             rel2.to_x: "img.msg.separator";
+             text {
+                text: "time";
+                font: FONT_NORMAL;
+                size: SIZE_MEDIUM;
+                align: 1.0 0.0;
+                max: 1 0;
+             }
+          }
+       }
+    }
+}
+
+group {
+   name: "elm/genlist/item/contacts-compose/default";
+   data.item: "texts" "text.contact.name text.contact.number text.contact.type";
+
+   parts {
+      part {
+          name: "bg";
+          type: RECT;
+          mouse_events: 1;
+          description {
+             state: "default" 0.0;
+             color: 255 255 255 0;
+             color_class: "action";
+             min: ACTION_WIDTH LIST_ITEM_HEIGHT;
+          }
+          description {
+             state: "selected" 0.0;
+             inherit: "default" 0.0;
+             color: 255 255 255 255;
+          }
+       }
+
+      part{
+         name: "text.contact.name";
+         type: TEXT;
+         mouse_events: 0;
+         description {
+            color: 255 255 255 255;
+            color_class: "action";
+            rel1 {
+               relative: 0.0 0.0;
+               offset: BORDER_PADDING ITEM_PADDING;
+            }
+            rel2 {
+               relative: 1.0 0.5;
+               offset: (-BORDER_PADDING - 1) 0;
+            }
+            text {
+               text: "James Bond";
+               font: FONT_NORMAL;
+               size: SIZE_LARGE;
+               align: 0.0 0.5;
+            }
+         }
+         description {
+            state: "selected" 0.0;
+            inherit: "default" 0.0;
+            color_class: "bg";
+         }
+      }
+
+      part{
+         name: "text.contact.number";
+         type: TEXT;
+         mouse_events: 0;
+         description {
+            color: 255 255 255 255;
+            color_class: "light";
+            rel1 {
+               to: "text.contact.name";
+               relative: 0.0 1.0;
+               offset: 0 (ITEM_PADDING + 1);
+            }
+            rel2 {
+               to_y: "bg";
+               to_x: "text.contact.type";
+               relative: 0.0 1.0;
+               offset: (-ITEM_PADDING - 1) (-ITEM_PADDING - 1);
+            }
+            text {
+               text: "0000007";
+               font: FONT_NORMAL;
+               size: SIZE_MEDIUM;
+               align: 0.0 0.5;
+            }
+         }
+         description {
+            state: "selected" 0.0;
+            inherit: "default" 0.0;
+            color_class: "bg";
+         }
+      }
+
+      part{
+         name: "text.contact.type";
+         type: TEXT;
+         mouse_events: 0;
+         description {
+            color: 255 255 255 255;
+            color_class: "light";
+            align: 1.0 0.5;
+            fixed: 1 1;
+            rel1 {
+               to_y: "text.contact.name";
+               to_x: "bg";
+               relative: 1.0 1.0;
+               offset: (-BORDER_PADDING - 1) ITEM_PADDING;
+            }
+            rel2 {
+               to: "bg";
+               relative: 1.0 1.0;
+               offset: (-BORDER_PADDING - 1) (-ITEM_PADDING - 1);
+            }
+            text {
+               text: "0000007";
+               font: FONT_NORMAL;
+               size: SIZE_MEDIUM;
+               min: 1 0;
+               align: 1.0 0.5;
+            }
+         }
+         description {
+            state: "selected" 0.0;
+            inherit: "default" 0.0;
+            color_class: "bg";
+         }
+      }
+
+   }
+
+   programs {
+      program {
+         signal:  "elm,state,selected";
+         source:  "elm";
+         after: "show_selected";
+      }
+      program {
+         signal:  "elm,state,unselected";
+         source:  "elm";
+         after: "show_default";
+      }
+      program {
+         name: "show_selected";
+         action: STATE_SET "selected" 0.0;
+         target: "text.contact.number";
+         target: "text.contact.name";
+         target: "text.contact.type";
+         target: "bg";
+      }
+      program {
+         name: "show_default";
+         action: STATE_SET "default" 0.0;
+         target: "text.contact.number";
+         target: "text.contact.name";
+         target: "text.contact.type";
+         target: "bg";
+      }
+   }
+}
+
+group {
+   name: "elm/genlist/item_compress/outgoing-delete/default";
+   alias: "elm/genlist/item_compress_odd/outoing-delete/default";
+
+   data {
+      item: "contents" "msg.swallow.delete";
+      item: "mode_part" "elm.swallow.decorate.content";
+   }
+
+   parts {
+      part {
+         name: "content.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+         }
+         description {
+            state: "decorated" 0.0;
+            inherit: "default" 0.0;
+            rel1 {
+               offset: (-BORDER_PADDING - LIST_ICON_SIZE - ITEM_PADDING - 1) -1;
+            }
+         }
+      }
+
+      part {
+         name: "elm.swallow.decorate.content";
+         type: SWALLOW;
+         mouse_events: 1;
+         scale: 1;
+         clip_to: "content.clipper";
+         description {
+            state: "default" 0.0;
+         }
+      }
+
+      part {
+         name: "msg.swallow.delete";
+         type: SWALLOW;
+         mouse_events: 1;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            visible: 0;
+            fixed: 1 0;
+            align: 1.0 0.0;
+            rel1 {
+               relative: 0.0 0.0;
+               offset: 0 0;
+            }
+            rel2 {
+               relative: 0.0 1.0;
+               offset: 0 0;
+            }
+         }
+         description {
+            state: "decorated" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+            align: 0.0 0.0;
+            rel1 {
+               relative: 0.0 0.0;
+               offset: BORDER_PADDING 0;
+            }
+            rel2 {
+               relative: 0.0 1.0;
+               offset: BORDER_PADDING 0;
+            }
+         }
+      }
+
+      programs {
+         program {
+            name: "animate_decorated";
+            signal: "elm,state,decorate,enabled,effect";
+            source: "elm";
+            action: STATE_SET "decorated" 0.0;
+            target: "content.clipper";
+            after: "animate_decorated2";
+         }
+         program {
+            name: "animate_decorated2";
+            action: STATE_SET "decorated" 0.0;
+            transition: ACCELERATE 0.15;
+            target: "msg.swallow.delete";
+         }
+
+         program {
+            name: "animate_default";
+            signal: "elm,state,decorate,disabled,effect";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            transition: ACCELERATE 0.15;
+            target: "msg.swallow.delete";
+            after: "animate_default2";
+         }
+         program {
+            name: "animate_default2";
+            action: STATE_SET "default" 0.0;
+            target: "content.clipper";
+         }
+
+         program {
+            signal: "elm,state,decorate,enabled";
+            source: "elm";
+            action: STATE_SET "decorated" 0.0;
+            target: "content.clipper";
+            target: "msg.swallow.delete";
+         }
+         program {
+            signal: "elm,state,decorate,disabled";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            target: "content.clipper";
+            target: "msg.swallow.delete";
+         }
+
+         program {
+            signal: "elm,state,slide,active";
+            source: "elm";
+            after: "animate_decorated";
+         }
+         program {
+            signal: "elm,state,slide,passive";
+            source: "elm";
+            after: "animate_default";
+         }
+      }
+   }
+}
+
+group {
+   name: "elm/genlist/item_compress/incoming-delete/default";
+   alias: "elm/genlist/item_compress_odd/incoming-delete/default";
+
+   data {
+      item: "contents" "msg.swallow.delete";
+      item: "mode_part" "elm.swallow.decorate.content";
+   }
+
+   parts {
+      part {
+         name: "content.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+         }
+         description {
+            state: "decorated" 0.0;
+            inherit: "default" 0.0;
+            rel2 {
+               offset: (-BORDER_PADDING - LIST_ICON_SIZE - ITEM_PADDING - 1) -1;
+            }
+         }
+      }
+
+      part {
+         name: "elm.swallow.decorate.content";
+         type: SWALLOW;
+         mouse_events: 1;
+         scale: 1;
+         clip_to: "content.clipper";
+         description {
+            state: "default" 0.0;
+         }
+      }
+
+      part {
+         name: "msg.swallow.delete";
+         type: SWALLOW;
+         mouse_events: 1;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            visible: 0;
+            fixed: 1 0;
+            align: 0.0 0.5;
+            rel1 {
+               relative: 1.0 0.0;
+            }
+         }
+         description {
+            state: "decorated" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+            align: 1.0 0.5;
+            rel1 {
+               relative: 1.0 0.0;
+               offset: -BORDER_PADDING 0;
+            }
+            rel2 {
+               relative: 1.0 1.0;
+               offset: -BORDER_PADDING -1;
+            }
+         }
+      }
+
+      programs {
+         program {
+            name: "animate_decorated";
+            signal: "elm,state,decorate,enabled,effect";
+            source: "elm";
+            action: STATE_SET "decorated" 0.0;
+            target: "content.clipper";
+            after: "animate_decorated2";
+         }
+         program {
+            name: "animate_decorated2";
+            action: STATE_SET "decorated" 0.0;
+            transition: ACCELERATE 0.15;
+            target: "msg.swallow.delete";
+         }
+
+         program {
+            name: "animate_default";
+            signal: "elm,state,decorate,disabled,effect";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            transition: ACCELERATE 0.15;
+            target: "msg.swallow.delete";
+            after: "animate_default2";
+         }
+         program {
+            name: "animate_default2";
+            action: STATE_SET "default" 0.0;
+            target: "content.clipper";
+         }
+
+         program {
+            signal: "elm,state,decorate,enabled";
+            source: "elm";
+            action: STATE_SET "decorated" 0.0;
+            target: "content.clipper";
+            target: "msg.swallow.delete";
+         }
+         program {
+            signal: "elm,state,decorate,disabled";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            target: "content.clipper";
+            target: "msg.swallow.delete";
+         }
+
+         program {
+            signal: "elm,state,slide,active";
+            source: "elm";
+            after: "animate_decorated";
+         }
+         program {
+            signal: "elm,state,slide,passive";
+            source: "elm";
+            after: "animate_default";
+         }
+      }
+   }
+}
+
+group {
+   name: "elm/entry/base/compose";
+
+   styles {
+      style {
+         name: "compose_textblock_style";
+         base: "font="FONT_NORMAL" font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_ACTION" wrap=mixed valign=top align=auto";
+         tag: "br" "\n";
+      }
+      style {
+         name: "compose_textblock_disabled_style";
+         base: "font="FONT_NORMAL" font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_ACTION" wrap=mixed valign=top align=auto";
+         tag: "br" "\n";
+      }
+   }
+
+   parts {
+      part {
+         name: "elm.text";
+         type: TEXTBLOCK;
+         mouse_events: 1;
+         scale: 1;
+         entry_mode: EDITABLE;
+         select_mode: EXPLICIT;
+         source: "elm/entry/selection/dialer";
+         source4: "elm/entry/cursor/dialer";
+         multiline: 1;
+         description {
+            state: "default" 0.0;
+            align: 0.0 0.0;
+            rel1.offset: BORDER_PADDING 0;
+            text {
+               style: "compose_textblock_style";
+               min: 0 1;
+               max: 1 1;
+               align: -1.0 0.0;
+            }
+         }
+         description {
+            state: "disabled" 0.0;
+            inherit: "default" 0.0;
+            text {
+               style: "compose_textblock_disabled_style";
+            }
+         }
+      }
+   }
+
+   programs {
+      program {
+         signal: "load";
+         source: "";
+         action: FOCUS_SET;
+         target: "elm.text";
+      }
+      program {
+         signal: "elm,state,disabled";
+         source: "elm";
+         action: STATE_SET "disabled" 0.0;
+         target: "elm.text";
+      }
+      program {
+         signal: "elm,state,enabled";
+         source: "elm";
+         action: STATE_SET "default" 0.0;
+         target: "elm.text";
+      }
+   }
+}
+
+group {
+   name: "elm/button/base/compose-resend";
+
+   parts {
+      part {
+         name: "elm.text";
+         type: TEXT;
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "caution";
+            text {
+               text: "A Label";
+               font: FONT_NORMAL;
+               size: SIZE_MEDIUM;
+               size_range: SIZE_MEDIUM SIZE_HUGE;
+               fit: 1 1;
+            }
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 128;
+         }
+      }
+   }
+   programs {
+      program {
+         signal: "mouse,down,1";
+         source: "elm.text";
+         action: SIGNAL_EMIT "elm,action,press" "";
+      }
+      program {
+         signal: "mouse,up,1";
+         source: "elm.text";
+         action: SIGNAL_EMIT "elm,action,unpress" "";
+      }
+      program {
+         signal: "mouse,clicked,1";
+         source: "elm.text";
+         action: SIGNAL_EMIT "elm,action,click" "";
+      }
+
+      program {
+         signal: "mouse,up,1";
+         source: "elm.text";
+         action: STATE_SET "default" 0.0;
+         transition: ACCELERATE 0.1;
+         target: "elm.text";
+      }
+
+      program {
+         signal: "mouse,down,1";
+         source: "elm.text";
+         action: STATE_SET "pressed" 0.0;
+         transition: ACCELERATE 0.1;
+         target: "elm.text";
+      }
+   }
+}
+
+group {
+   name: "elm/entry/base-single/default";
+   inherit: "elm/entry/base/compose";
+   styles
+   {
+      style {
+         name: "entry_single_textblock_compose_guide_style";
+         base: "font="FONT_NORMAL" font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_ACTION" wrap=mixed text_class=entry left_margin=2 right_margin=2 ellipsis=0.0";
+      }
+   }
+   parts {
+      part {
+         name: "elm.guide";
+         type: TEXTBLOCK;
+         mouse_events: 0;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            rel1.to: "elm.text";
+            rel2.to: "elm.text";
+            text {
+               style: "entry_single_textblock_compose_guide_style";
+               min: 0 1;
+               align: 0.0 0.0;
+            }
+         }
+         description {
+            state: "hidden" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      part {
+         name: "elm.text";
+         multiline: 0;
+         description {
+            state: "default" 0.0;
+            text {
+               style: "compose_textblock_style";
+               min: 1 1;
+               max: 0 0;
+               align: 0.0 0.5;
+            }
+         }
+         description {
+            state: "disabled" 0.0;
+            inherit: "default" 0.0;
+            text {
+               style: "compose_textblock_disabled_style";
+            }
+         }
+      }
+   }
+}
+
+group {
+   name: "elm/multibuttonentry/base/compose";
+   data.item: "closed_button_type" "image"; /* image, label, default : label */
+   data.item: "closed_height" 46;
+   parts {
+      part {
+         name: "box.swallow";
+         type: SWALLOW;
+         description {
+            state: "default" 0.0;
+            align: 0.0 0.0;
+         }
+      }
+   }
+}
+
+
+group {
+   name: "elm/multibuttonentry/guidetext/compose";
+   parts {
+      part {
+         name: "elm.text.bg";
+         type: RECT;
+         mouse_events: 0;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            visible: 0;
+            rel1.to: "elm.text";
+            rel2.to: "elm.text";
+         }
+      }
+      part {
+         name: "elm.text";
+         type: TEXT;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "light";
+            rel1.offset: BORDER_PADDING 0;
+            text {
+               font: FONT_NORMAL;
+               size: SIZE_MEDIUM;
+               min: 0 1;
+               align: 0.0 0.5;
+            }
+         }
+      }
+   }
+}
+
+
+group {
+   name: "elm/multibuttonentry/btn/compose";
+   data.item: "button_max_size" MULTI_BUTTON_ENTRY_MAX_SIZE;
+   styles {
+      style { name: "multibuttonentry_textblock_style";
+         base: "font="FONT_NORMAL" align=0.5 font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_ACTION" text_class=label ellipsis=1.0";
+         tag:  "br" "\n";
+         tag:  "ps" "ps";
+         tag:  "hilight" "+ font="FONT_BOLD"";
+         tag:  "b" "+ font="FONT_BOLD"";
+         tag:  "tab" "\t";
+      }
+   }
+
+   parts {
+      part {
+         name: "elm.base";
+         type: RECT;
+         mouse_events: 1;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            min: 0 LIST_ICON_SIZE;
+            max: 5000 LIST_ICON_SIZE;
+            fixed: 1 1;
+            color: 0 0 0 0;
+         }
+      }
+      part {
+         name: "right.padding";
+         type: RECT;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            min : ITEM_PADDING 0;
+            rel1.relative: 1.0 0.0;
+            rel2.relative: 1.0 1.0;
+            color: 0 0 0 0;
+            align: 1 1;
+         }
+      }
+      part {
+         name: "elm.btn.bg";
+         type: RECT;
+         mouse_events: 1;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            min : ITEM_PADDING LIST_ICON_SIZE;
+            rel2 {
+               relative: 0.0 1.0;
+               to_x: "right.padding";
+            }
+            color: 255 255 255 0;
+            color_class: "light";
+         }
+         description {
+            state: "focused" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 255;
+         }
+      }
+      part {
+         name: "elm.btn.text";
+         type: TEXTBLOCK;
+         mouse_events: 1;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            min: ITEM_PADDING LIST_ICON_SIZE;
+            max: (MULTI_BUTTON_ENTRY_MAX_SIZE -2 * ITEM_PADDING) LIST_ICON_SIZE;
+            fixed: 0 1;
+            text {
+               text: "Auto Resized textblock";
+               style: "multibuttonentry_textblock_style";
+               min: 1 0;
+               align: 0.5 0.5;
+            }
+            rel1 {
+               to: "elm.btn.bg";
+               offset: ITEM_PADDING 0;
+            }
+            rel2 {
+               to: "elm.btn.bg";
+               offset: (-ITEM_PADDING -1) -1;
+            }
+
+         }
+      }
+   }
+   programs {
+      program {
+         name: "clicked";
+         signal: "mouse,clicked,1";
+         source: "elm.btn.bg";
+         action: SIGNAL_EMIT "clicked" "elm";
+      }
+      program {
+         name: "default";
+         signal: "default";
+         action: STATE_SET "default" 0.0;
+         target: "elm.btn.bg";
+      }
+      program {
+         name: "focused";
+         signal: "focused";
+         action: STATE_SET "focused" 0.0;
+         target: "elm.btn.bg";
+      }
+   }
+}
+
+
+group {
+   name: "elm/multibuttonentry/label/default";
+   parts {
+      part {
+         name: "mbe.label.bg";
+         type: RECT;
+         scale: 1;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            min: 0 0;
+            fixed: 1 1;
+         }
+         description {
+            state: "no_text" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      part {
+         name: "mbe.label.left.padding";
+         type: RECT;
+         mouse_events: 0;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            min: 3 0;
+            fixed: 1 1;
+            rel1.to: "mbe.label.bg";
+            rel2 {
+               to: "mbe.label.bg";
+               relative: 0.0 1.0;
+            }
+            align: 0 0.5;
+         }
+         description {
+            state: "no_text" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      part {
+         name: "mbe.label.right.padding";
+         type: RECT;
+         mouse_events: 0;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            min: 3 0;
+            fixed: 1 1;
+            rel1 {
+               to: "mbe.label.bg";
+               relative: 1.0 0.0;
+            }
+            rel2.to: "mbe.label.bg";
+            align: 1 1.0;
+         }
+         description {
+            state: "no_text" 0.0;
+            inherit: "default" 0.0;
+            visible: 0;
+         }
+      }
+      part {
+         name: "mbe.label";
+         type: TEXT;
+         mouse_events: 0;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "action";
+            min: 0 33;
+            fixed: 1 1;
+            text {
+               font: FONT_NORMAL;
+               size: SIZE_MEDIUM;
+               min: 1 1;
+               align: 0.0 0.428;
+            }
+            rel1 { relative: 1.0 1.0; to: "mbe.label.left.padding"; }
+            rel2 { relative: 0.0 0.0; to: "mbe.label.right.padding"; }
+         }
+         description {
+            state: "no_text" 0.0;
+            inherit: "default" 0.0;
+            min: 6 33;
+         }
+      }
+   }
+   programs {
+      program {
+         name: "has_text";
+         signal: "elm,mbe,set_text";
+         source: "";
+         action: STATE_SET "default" 0.0;
+         target: "mbe.label.bg";
+         target: "mbe.label.left.padding";
+         target: "mbe.label.right.padding";
+         target: "mbe.label";
+      }
+      program {
+         name: "no_text";
+         signal: "elm,mbe,clear_text";
+         source: "";
+         action: STATE_SET "no_text" 0.0;
+         target: "mbe.label.bg";
+         target: "mbe.label.left.padding";
+         target: "mbe.label.right.padding";
+         target: "mbe.label";
+      }
+   }
+}
+
+
diff --git a/data/themes/includes/messages-overview-list.edc b/data/themes/includes/messages-overview-list.edc
new file mode 100644 (file)
index 0000000..413be88
--- /dev/null
@@ -0,0 +1,332 @@
+group {
+   name: "elm/genlist/item/messages-overview/default";
+
+   data {
+      item: "texts" "elm.text.name elm.text.content elm.text.time";
+      item: "contents" "elm.swallow.more";
+   }
+
+   images {
+      image: "ico_arrow_right.png" COMP;
+      image: "ico_del.png" COMP;
+   }
+
+   parts {
+      part {
+         name: "bg";
+         type: RECT;
+         mouse_events: 1;
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 0;
+            color_class: "action";
+            min: WIDTH LIST_CONTACT_HEIGHT;
+         }
+         description {
+            state: "selected" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 255;
+         }
+      }
+
+      part {
+         name: "msg.img.more";
+         type: IMAGE;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            rel1.to: "elm.swallow.more";
+            rel2.to: "elm.swallow.more";
+            color_class: "action";
+            image {
+               normal: "ico_arrow_right.png";
+               scale_hint: STATIC;
+            }
+         }
+         description {
+            state: "selected" 0.0;
+            inherit: "default" 0.0;
+            color_class: "bg";
+         }
+      }
+
+      part {
+         name: "elm.swallow.more";
+         type: SWALLOW;
+         mouse_events: 1;
+         description {
+            state: "default" 0.0;
+            min: LIST_ICON_SIZE LIST_ICON_SIZE;
+            max: LIST_ICON_SIZE LIST_ICON_SIZE;
+            align: 1.0 0.5;
+            fixed: 1 1;
+            rel1 {
+               relative: 1.0 0.0;
+               offset: -BORDER_PADDING 0;
+            }
+            rel2 {
+               relative: 1.0 1.0;
+               offset: -BORDER_PADDING -1;
+            }
+         }
+      }
+
+      part {
+         name: "elm.text.name";
+         type: TEXT;
+         scale: 1;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "action";
+            rel1 {
+               relative: 0.0 0.0;
+               offset: BORDER_PADDING ITEM_PADDING;
+            }
+            rel2 {
+               to_x: "elm.text.time";
+               relative: 0.0 0.5;
+               offset: -ITEM_PADDING -1;
+            }
+            text {
+               font: FONT_NORMAL;
+               size: SIZE_LARGE;
+               align: 0.0 1.0;
+               ellipsis: 0.0;
+            }
+         }
+         description {
+            state: "selected" 0.0;
+            inherit: "default" 0.0;
+            color_class: "bg";
+         }
+      }
+
+      part {
+         name: "elm.text.content";
+         type: TEXT;
+         scale: 1;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 128;
+            color_class: "action";
+            fixed: 1 1;
+            rel1 {
+               to: "elm.text.name";
+               relative: 0.0 1.0;
+               offset: 0 0;
+            }
+            rel2 {
+               to: "elm.swallow.more";
+               relative: 0.0 1.0;
+               offset: -ITEM_PADDING -ITEM_PADDING;
+            }
+            text {
+               font: FONT_NORMAL;
+               size: SIZE_MEDIUM;
+               align: 0.0 0.0;
+               ellipsis: 0.0;
+            }
+         }
+         description {
+            state: "selected" 0.0;
+            inherit: "default" 0.0;
+            color_class: "bg";
+         }
+      }
+
+      part {
+         name: "elm.text.time";
+         type: TEXT;
+         scale: 1;
+         mouse_events: 0;
+         description {
+            fixed: 1 1;
+            state: "default" 0.0;
+            color: 255 255 255 128;
+            color_class: "action";
+            align: 1.0 0.5;
+            rel1 {
+               to_x: "elm.swallow.more";
+               relative: 0.0 0.0;
+               offset: -ITEM_PADDING ITEM_PADDING;
+            }
+            rel2 {
+               to_x: "elm.swallow.more";
+               relative: 0.0 0.5;
+               offset: -ITEM_PADDING -1;
+            }
+            text {
+               font: FONT_NORMAL;
+               size: SIZE_MEDIUM;
+               align: 1.0 1.0;
+               ellipsis: 0.0;
+               min: 1 0;
+            }
+         }
+         description {
+            state: "selected" 0.0;
+            inherit: "default" 0.0;
+            color_class: "bg";
+         }
+      }
+   }
+   programs {
+      program {
+         signal:  "elm,state,selected";
+         source:  "elm";
+         after: "show_selected";
+      }
+      program {
+         signal:  "elm,state,unselected";
+         source:  "elm";
+         after: "show_default";
+      }
+      program {
+         name: "show_default";
+         action: STATE_SET "default" 0.0;
+         target: "bg";
+         target: "elm.text.name";
+         target: "elm.text.time";
+         target: "elm.text.content";
+         target: "msg.img.more";
+      }
+      program {
+         name: "show_selected";
+         action: STATE_SET "selected" 0.0;
+         target: "bg";
+         target: "elm.text.name";
+         target: "elm.text.time";
+         target: "elm.text.content";
+         target: "msg.img.more";
+      }
+   }
+}
+
+group {
+   name: "elm/genlist/item/messages-overview-delete/default";
+   alias: "elm/genlist/item_odd/messages-overview-delete/default";
+
+   data {
+      item: "contents" "elm.swallow.delete";
+      item: "mode_part" "elm.swallow.decorate.content";
+   }
+
+   parts {
+      part {
+         name: "content.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+         }
+         description {
+            state: "decorated" 0.0;
+            inherit: "default" 0.0;
+            rel2 {
+               offset: (-BORDER_PADDING - LIST_ICON_SIZE - ITEM_PADDING - 1) -1;
+            }
+         }
+      }
+
+      part {
+         name: "elm.swallow.decorate.content";
+         type: SWALLOW;
+         mouse_events: 1;
+         scale: 1;
+         clip_to: "content.clipper";
+         description {
+            state: "default" 0.0;
+         }
+      }
+
+      part {
+         name: "elm.swallow.delete";
+         type: SWALLOW;
+         mouse_events: 1;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            visible: 0;
+            fixed: 1 0;
+            align: 0.0 0.5;
+            rel1 {
+               relative: 1.0 0.0;
+            }
+         }
+         description {
+            state: "decorated" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+            align: 1.0 0.5;
+            rel1 {
+               relative: 1.0 0.0;
+               offset: -BORDER_PADDING 0;
+            }
+            rel2 {
+               relative: 1.0 1.0;
+               offset: -BORDER_PADDING -1;
+            }
+         }
+      }
+
+      programs {
+         program {
+            name: "animate_decorated";
+            signal: "elm,state,decorate,enabled,effect";
+            source: "elm";
+            action: STATE_SET "decorated" 0.0;
+            target: "content.clipper";
+            after: "animate_decorated2";
+         }
+         program {
+            name: "animate_decorated2";
+            action: STATE_SET "decorated" 0.0;
+            transition: ACCELERATE 0.15;
+            target: "elm.swallow.delete";
+         }
+
+         program {
+            name: "animate_default";
+            signal: "elm,state,decorate,disabled,effect";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            transition: ACCELERATE 0.15;
+            target: "elm.swallow.delete";
+            after: "animate_default2";
+         }
+         program {
+            name: "animate_default2";
+            action: STATE_SET "default" 0.0;
+            target: "content.clipper";
+         }
+
+         program {
+            signal: "elm,state,decorate,enabled";
+            source: "elm";
+            action: STATE_SET "decorated" 0.0;
+            target: "content.clipper";
+            target: "elm.swallow.delete";
+         }
+         program {
+            signal: "elm,state,decorate,disabled";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            target: "content.clipper";
+            target: "elm.swallow.delete";
+         }
+
+         program {
+            signal: "elm,state,slide,active";
+            source: "elm";
+            after: "animate_decorated";
+         }
+         program {
+            signal: "elm,state,slide,passive";
+            source: "elm";
+            after: "animate_default";
+         }
+      }
+   }
+}
diff --git a/data/themes/includes/messages-overview.edc b/data/themes/includes/messages-overview.edc
new file mode 100644 (file)
index 0000000..108a51e
--- /dev/null
@@ -0,0 +1,430 @@
+group {
+   name: "elm/layout/ofono-efl/messages-overview";
+
+   /*
+    * Represents the messages compose layout with actions and swallows.
+    *
+    * Parts:
+    *
+    * SWALLOW: elm.swallow.genlist - Where all the conversations will appear
+    *
+    * Signals:
+    *   Emit (source is "gui"):
+    *   clicked,edit - When the edit button is cliked
+    *   clicked,edit,done - When The Button "Done" while editing is clicked
+    *
+    *   Listens (source is "gui"):
+    *   show,genlist  - Show the genlist with the current message thread
+    *   hidden,genlist - Hide the genlist
+    *   toggle,on,edit - User is editing
+    *   toggle,off,edit - User finished the editing
+    *
+    * Where <ID> is the name of the button
+    *
+    */
+
+   images {
+      image: "bg_keypad.jpg" COMP;
+   }
+
+   parts {
+      part {
+         name: "bg";
+         type: IMAGE;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "dark";
+            image {
+               normal: "bg_keypad.jpg";
+               scale_hint: STATIC;
+            }
+            fill.smooth: 1;
+
+         }
+      }
+
+      part {
+         name: "notification.bar";
+         type: RECT;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 255;
+            rel1.relative: 0.0 0.0;
+            rel2 {
+               relative: 1.0 0.0;
+               offset: -1 NOTIFICATION_BAR_HEIGHT;
+            }
+         }
+      }
+
+      part {
+         name: "button.area.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+            rel1.to: "bg.buttons";
+            rel2 {
+               to: "bg.buttons";
+               offset: -1 SEPARATOR_HEIGHT;
+            }
+         }
+      }
+
+
+      part {
+         name: "button.clipper";
+         type: RECT;
+         clip_to: "button.area.clipper";
+         description {
+            state: "default" 0.0;
+            rel1.to: "button.area.clipper";
+            rel2.to: "button.area.clipper";
+         }
+         description {
+            state: "alternate" 0.0;
+            color: 255 255 255 0;
+            visible: 0;
+         }
+      }
+
+      part {
+         name: "edit-button.clipper";
+         type: RECT;
+         clip_to: "button.area.clipper";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 0;
+            visible: 0;
+            rel1.to: "button.area.clipper";
+            rel2.to: "button.area.clipper";
+         }
+         description {
+            state: "alternate" 0.0;
+            color: 255 255 255 255;
+            visible: 1;
+         }
+      }
+
+      part {
+         name: "edit.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+            rel1.to: "bg.edit";
+            rel2 {
+               to: "bg.edit";
+               offset: -1 SEPARATOR_HEIGHT;
+            }
+         }
+      }
+
+      part {
+         name: "bg.buttons";
+         type: RECT;
+         mouse_events: 0;
+         clip_to: "button.clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            fixed: 1 1;
+            min: 0 (ACTION_HEIGHT / 2);
+            rel1 {
+               to: "notification.bar";
+               relative: 0.0 1.0;
+            }
+            rel2 {
+               to_x: "bg.edit";
+               to_y: "notification.bar";
+               relative: 0.0 1.0;
+               offset: (-ITEM_PADDING - 1) (ACTION_HEIGHT / 2 - 1);
+            }
+         }
+      }
+
+      part {
+         name: "bg.edit";
+         type: RECT;
+         mouse_events: 0;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            min: 0 (ACTION_HEIGHT / 2);
+            rel1 {
+               to: "notification.bar";
+               relative: 1.0 1.0;
+               offset: (-LIST_ICON_SIZE - ITEM_PADDING - BORDER_PADDING) 0;
+            }
+            rel2 {
+               to: "notification.bar";
+               relative: 1.0 1.0;
+               offset: -1 (ACTION_HEIGHT / 2 - 1);
+            }
+         }
+      }
+
+#define SEPARATOR(id, clip, rely, offy, relto)                          \
+      part {                                                            \
+         name: "separator.dark."##id;                                   \
+         type: RECT;                                                    \
+         mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: "dark";                                        \
+            rel1 {                                                      \
+               relative: 0.0 rely;                                      \
+               offset: 0 offy;                                          \
+               to_y: relto;                                             \
+            }                                                           \
+            rel2 {                                                      \
+               relative: 1.0 rely;                                      \
+               offset: -1 (offy + SEPARATOR_HEIGHT / 2);                \
+               to_y: relto;                                             \
+            }                                                           \
+         }                                                              \
+      }                                                                 \
+      part {                                                            \
+         name: "separator.bg."##id;                                     \
+         type: RECT;                                                    \
+         mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: "bg";                                          \
+            rel1 {                                                      \
+               relative: 0.0 rely;                                      \
+               offset: 0 (offy + SEPARATOR_HEIGHT / 2);                 \
+               to_y: relto;                                             \
+            }                                                           \
+            rel2 {                                                      \
+               relative: 1.0 rely;                                      \
+               offset: -1 (offy + SEPARATOR_HEIGHT);                    \
+               to_y: relto;                                             \
+            }                                                           \
+         }                                                              \
+      }
+
+      SEPARATOR("button", "button.area.clipper", 1.0, 0, "bg.buttons");
+      SEPARATOR("edit-button", "button.area.clipper", 1.0, 0, "bg.buttons");
+      SEPARATOR("edit", "edit.clipper", 1.0, 0, "bg.edit");
+#undef SEPARATOR
+
+
+#define BUTTON(id, label, ccls, clip, r1, r2)                           \
+      part {                                                            \
+         name: "button."##id;                                           \
+         type: RECT;                                                    \
+         mouse_events: 1;                                               \
+         clip_to: clip;                                                 \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 0;                                       \
+            color_class: "action";                                      \
+            rel1 {                                                      \
+               to: "bg.buttons";                                        \
+               relative: r1;                                            \
+            }                                                           \
+            rel2 {                                                      \
+               to: "bg.buttons";                                        \
+               relative: r2;                                            \
+            }                                                           \
+         }                                                              \
+         description {                                                  \
+            state: "pressed" 0.0;                                       \
+            inherit: "default" 0.0;                                     \
+            color: 255 255 255 255;                                     \
+         }                                                              \
+      }                                                                 \
+      part {                                                            \
+         name: "label."##id;                                            \
+         type: TEXT;                                                    \
+         mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
+         description {                                                  \
+            state: "default" 0.0;                                       \
+            color: 255 255 255 255;                                     \
+            color_class: ccls;                                          \
+            rel1.to: "button."##id;                                     \
+            rel2 {                                                      \
+               to: "button."##id;                                       \
+            }                                                           \
+            text {                                                      \
+               text: label;                                             \
+               font: FONT_NORMAL;                                       \
+               size: SIZE_MEDIUM;                                       \
+               align: 0.5 0.5;                                          \
+            }                                                           \
+         }                                                              \
+         description {                                                  \
+            state: "pressed" 0.0;                                       \
+            inherit: "default" 0.0;                                     \
+            color: 16 16 16 255;                                        \
+         }                                                              \
+      }                                                                 \
+                                                                        \
+      programs {                                                        \
+         program {                                                      \
+            signal: "toggle,on,"##id;                                   \
+            source: "gui";                                              \
+            action: STATE_SET "pressed" 0.0;                            \
+            target: "button."##id;                                      \
+            target: "label."##id;                                       \
+         }                                                              \
+         program {                                                      \
+            signal: "toggle,off,"##id;                                  \
+            source: "gui";                                              \
+            action: STATE_SET "default" 0.0;                            \
+            target: "button."##id;                                      \
+            target: "label."##id;                                       \
+         }                                                              \
+         program {                                                      \
+            signal: "mouse,clicked,1";                                  \
+            source: "button."##id;                                      \
+            action: SIGNAL_EMIT "clicked,"##id "gui";                   \
+            api: id"_clicked" id" was clicked";                         \
+         }                                                              \
+      }
+
+      BUTTON("view",    "View",    "action", "button.clipper", 0.0 0.0, 0.5 1.0);
+      BUTTON("compose", "Compose", "action", "button.clipper", 0.5 0.0, 1.0 1.0);
+
+      BUTTON("clear",     "Clear", "caution", "edit-button.clipper", 0.0 0.0, 0.5 1.0);
+      BUTTON("edit,done", "Done",  "action", "edit-button.clipper", 0.5 0.0, 1.0 1.0);
+#undef BUTTON
+
+      part {
+         name: "button.edit";
+         type: RECT;
+         mouse_events: 1;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 0;
+            color_class: "caution";
+            rel1.to: "bg.edit";
+            rel2.to: "bg.edit";
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 255;
+         }
+      }
+      part {
+         name: "ico.edit";
+         type: IMAGE;
+         mouse_events: 0;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            min: LIST_ICON_SIZE LIST_ICON_SIZE;
+            max: LIST_ICON_SIZE LIST_ICON_SIZE;
+            align: 0.0 0.5;
+            color: 255 255 255 255;
+            color_class: "caution";
+            rel1 {
+               to: "button.edit";
+               offset: ITEM_PADDING 0;
+            }
+            rel2 {
+               to: "button.edit";
+               offset: (-BORDER_PADDING - 1) -1;
+            }
+            image {
+               normal: "ico_del.png";
+               scale_hint: STATIC;
+            }
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            color: 16 16 16 255;
+         }
+      }
+      part {
+         name: "button.over.edit";
+         type: RECT;
+         mouse_events: 1;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            visible: 0;
+            rel1.to: "bg.edit";
+            rel2.to: "bg.edit";
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+         }
+      }
+
+      part {
+         name: "elm.swallow.genlist";
+         type: SWALLOW;
+         description {
+            state: "default" 0.0;
+            rel1 {
+               to_y: "separator.bg.button";
+               relative: 0.0 1.0;
+            }
+         }
+      }
+   }
+
+   programs {
+      program {
+         signal: "toggle,on,edit";
+         source: "gui";
+         action: STATE_SET "pressed" 0.0;
+         target: "button.edit";
+         target: "button.over.edit";
+         target: "ico.edit";
+         after: "show_edit_buttons";
+      }
+      program {
+         name: "show_edit_buttons";
+         action: STATE_SET "alternate" 0.0;
+         transition: ACCELERATE 0.3;
+         target: "button.clipper";
+         target: "edit-button.clipper";
+      }
+
+      program {
+         signal: "toggle,off,edit";
+         source: "gui";
+         action: STATE_SET "default" 0.0;
+         target: "button.edit";
+         target: "button.over.edit";
+         target: "ico.edit";
+         after: "hide_edit_buttons";
+      }
+      program {
+         name: "hide_edit_buttons";
+         action: STATE_SET "default" 0.0;
+         transition: ACCELERATE 0.3;
+         target: "button.clipper";
+         target: "edit-button.clipper";
+      }
+
+      program {
+         signal: "mouse,clicked,1";
+         source: "button.edit";
+         action: SIGNAL_EMIT "clicked,edit" "gui";
+         api: "edit was clicked";
+      }
+      program {
+         signal: "mouse,clicked,1";
+         source: "button.over.edit";
+         action: SIGNAL_EMIT "clicked,edit,done" "gui";
+         api: "edit_done was clicked";
+      }
+   }
+}
index 5cb8252..fb08ab3 100644 (file)
@@ -14,6 +14,10 @@ group {
     *
     */
 
+   images {
+      image: "ico_edit.png" COMP;
+   }
+
    parts {
       part {
          name: "bg";
@@ -39,5 +43,17 @@ group {
             }
          }
       }
+
+      part {
+         name: "elm.swallow.overview";
+         type: SWALLOW;
+         description {
+            state: "default" 0.0;
+            rel1 {
+               to_y: "notification.bar";
+               relative: 0.0 1.0;
+            }
+         }
+      }
    }
 }
index 9237ba4..c652b08 100644 (file)
@@ -2,6 +2,9 @@ group {
    name: "elm/scroller/base/multiparty-details";
    alias: "elm/genlist/base/history";
    alias: "elm/genlist/base/contacts";
+   alias: "elm/genlist/base/messages-overview";
+   alias: "elm/scroller/entry/compose";
+   alias: "elm/genlist/base/compose";
 
    script {
       public sbvis_v, sbalways_v, sbvis_timer;
@@ -31,6 +34,16 @@ group {
       }
 
       part {
+         name: "bg";
+         type: RECT;
+         clip_to: "clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+         }
+      }
+
+      part {
          name: "elm.swallow.content";
          clip_to: "clipper";
          type: SWALLOW;
index f1d1f94..825ab66 100644 (file)
 #include "config.h"
 #endif
 #include <Elementary.h>
+#include <Ecore.h>
+#include <string.h>
+#include <ctype.h>
 #include "log.h"
 #include "util.h"
+#include "gui.h"
+#include "overview.h"
+#include "ofono.h"
 
 typedef struct _Compose
 {
        Evas_Object *layout;
+       Evas_Object *entry_msg;
+       Evas_Object *mb_entry;
+       Evas_Object *genlist;
+       Evas_Object *genlist_contacts;
+       Elm_Genlist_Item_Class *itc_inc;
+       Elm_Genlist_Item_Class *itc_out;
+       Elm_Genlist_Item_Class *itc_c_name;
+       Eina_Bool composing;
+       Eina_List *current_thread;
+       const char *number;
+       Eina_List *composing_numbers;
+       Ecore_Poller *updater;
+       double last_update;
 } Compose;
 
+typedef struct _Contact_Genlist {
+       const char *name;
+       const char *number;
+       const char *type;
+       const char *picture;
+       Compose *compose;
+} Contact_Genlist;
+
+static OFono_Callback_List_Incoming_SMS_Node *incoming_sms = NULL;
+static OFono_Callback_List_Sent_SMS_Node *sent_sms = NULL;
+
+static void _send_sms(Compose *compose);
+static void _compose_timer_updater_start(Compose *compose);
+
+static void _message_remove_from_genlist(Message *msg)
+{
+       Elm_Object_Item *it;
+
+       it = message_object_item_get(msg);
+       EINA_SAFETY_ON_NULL_RETURN(it);
+       elm_object_item_del(it);
+}
+
+static void _message_from_file_delete(Compose *compose, Message *msg,
+                                       const char *contact)
+{
+       Message *msg_aux;
+       Eina_List *last;
+
+       gui_message_from_file_delete(msg, contact);
+       _message_remove_from_genlist(msg);
+
+       last = eina_list_last(compose->current_thread);
+       msg_aux = eina_list_data_get(last);
+
+       if (msg_aux == msg) {
+               msg_aux = eina_list_data_get(eina_list_prev(last));
+               if (msg_aux != NULL)
+                       gui_overview_genlist_update(msg_aux, contact);
+       }
+       compose->current_thread = eina_list_remove(compose->current_thread,
+                                                       msg);
+       message_del(msg);
+}
+
 static void _on_del(void *data, Evas *e __UNUSED__,
                        Evas_Object *obj __UNUSED__, void *event __UNUSED__)
 {
        Compose *compose = data;
+       Message *msg;
+       const char *number;
+
+       ofono_incoming_sms_cb_del(incoming_sms);
+       ofono_sent_sms_changed_cb_del(sent_sms);
+       elm_genlist_item_class_free(compose->itc_inc);
+       elm_genlist_item_class_free(compose->itc_out);
+       elm_genlist_item_class_free(compose->itc_c_name);
+       EINA_LIST_FREE(compose->current_thread, msg)
+               message_del(msg);
+
+       EINA_LIST_FREE(compose->composing_numbers, number)
+               eina_stringshare_del(number);
+
+       eina_stringshare_del(compose->number);
        free(compose);
 }
 
+static void _compose_exit(Compose *compose)
+{
+       Message *msg;
+       const char *number;
+
+       compose->composing = EINA_TRUE;
+       eina_stringshare_replace(&(compose->number), NULL);
+       elm_object_part_text_set(compose->layout, "elm.text.name",
+                                       "New Message");
+       elm_object_signal_emit(compose->layout, "hidden,genlist", "gui");
+       elm_object_signal_emit(compose->layout, "composing", "gui");
+       elm_genlist_clear(compose->genlist);
+       elm_genlist_clear(compose->genlist_contacts);
+
+       EINA_LIST_FREE(compose->current_thread, msg)
+               message_del(msg);
+
+       EINA_LIST_FREE(compose->composing_numbers, number)
+               eina_stringshare_del(number);
+
+       elm_object_part_text_set(compose->entry_msg, NULL, "");
+       elm_genlist_decorate_mode_set(compose->genlist, EINA_FALSE);
+       elm_multibuttonentry_clear(compose->mb_entry);
+       elm_object_signal_emit(compose->layout, "contacts,hidden", "gui");
+       elm_object_signal_emit(compose->layout, "names_count,hidden", "gui");
+       gui_compose_exit();
+}
+
+static void _on_layout_clicked(void *data, Evas_Object *o,
+                       const char *emission, const char *source __UNUSED__)
+{
+       Compose *compose = data;
+       DBG("signal: %s", emission);
+
+       EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
+       emission += strlen("clicked,");
+
+       if (strcmp(emission, "back") == 0)
+               _compose_exit(compose);
+       else if (strcmp(emission, "send_msg") == 0)
+               _send_sms(compose);
+       else if (strcmp(emission, "edit") == 0) {
+               elm_object_signal_emit(o, "toggle,on,edit", "gui");
+               elm_genlist_decorate_mode_set(compose->genlist, EINA_TRUE);
+       } else if (strcmp(emission, "edit,done") == 0) {
+               elm_object_signal_emit(o, "toggle,off,edit", "gui");
+               elm_genlist_decorate_mode_set(compose->genlist, EINA_FALSE);
+       } else if (strcmp(emission, "clear") == 0) {
+               const char *contact = compose->number;
+               gui_overview_all_contact_messages_clear(contact);
+               Message *msg;
+               EINA_LIST_FREE(compose->current_thread, msg) {
+                       _message_remove_from_genlist(msg);
+                       message_del(msg);
+               }
+               elm_object_signal_emit(o, "toggle,off,edit", "gui");
+       } else
+               ERR("Unkown emission: %s", emission);
+}
+
+static void _send_sms_reply(void *data __UNUSED__, OFono_Error error,
+                               OFono_Sent_SMS *sms)
+{
+       if (error != OFONO_ERROR_NONE) {
+               ERR("Error when trying to send a new message");
+               return;
+       }
+
+       DBG("SMS Sent to: %s, message: %s", ofono_sent_sms_destination_get(sms),
+               ofono_sent_sms_message_get(sms));
+}
+
+static void _send_sms(Compose *compose)
+{
+       const char *msg_content;
+       char *msg_utf;
+       Message *msg;
+       Elm_Object_Item *it;
+       Contact_Info *c_info;
+       const char *to;
+       Eina_List *l;
+
+       if (elm_entry_is_empty(compose->entry_msg)) {
+               DBG("Returning, empty message");
+               return;
+       }
+
+       if (compose->composing && (!compose->composing_numbers)) {
+               DBG("Returning, no contacts to send");
+               return;
+       }
+
+       msg_content = elm_object_part_text_get(compose->entry_msg, NULL);
+
+       msg_utf = elm_entry_markup_to_utf8(msg_content);
+
+       msg = message_new(time(NULL), msg_utf,
+                               EINA_FALSE, OFONO_SENT_SMS_STATE_PENDING);
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+       message_data_set(msg, compose);
+       it = elm_genlist_item_append(compose->genlist, compose->itc_out,
+                                       msg, NULL, ELM_GENLIST_ITEM_NONE, NULL,
+                                       NULL);
+       elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_IN);
+       message_object_item_set(msg, it);
+       elm_object_signal_emit(compose->layout, "show,genlist", "gui");
+
+       compose->current_thread =
+               eina_list_append(compose->current_thread, msg);
+       elm_object_part_text_set(compose->entry_msg, NULL, "");
+
+       _compose_timer_updater_start(compose);
+
+       if (!compose->composing) {
+               ofono_sms_send(compose->number, msg_utf, _send_sms_reply, NULL);
+               DBG("New Message to: %s content: %s", compose->number, msg_utf);
+               c_info = gui_contact_search(compose->number, NULL);
+
+               if (!c_info)
+                       elm_object_part_text_set(compose->layout,
+                                                       "elm.text.name",
+                                                       compose->number);
+               else {
+                       to = contact_info_full_name_get(c_info);
+                       elm_object_part_text_set(compose->layout,
+                                                       "elm.text.name",
+                                                       to);
+               }
+       } else {
+               const char *names = NULL, *name;
+               char size[5];
+               const Eina_List *items;
+               int i = 0;
+               items = elm_multibuttonentry_items_get(compose->mb_entry);
+               EINA_SAFETY_ON_NULL_GOTO(items, exit);
+
+               EINA_LIST_FOREACH(compose->composing_numbers, l, to) {
+                       ofono_sms_send(to, msg_utf, _send_sms_reply, NULL);
+                       DBG("New Message to: %s content: %s", to, msg_utf);
+                       it = eina_list_nth(items, i);
+                       name = elm_object_item_part_text_get(it, NULL);
+                       if (i == 0)
+                               names = eina_stringshare_add(name);
+                       else
+                               names = eina_stringshare_printf("%s, %s",
+                                                               names, name);
+                       i++;
+               }
+
+               elm_object_part_text_set(compose->layout,
+                                               "elm.text.name", names);
+               snprintf(size, sizeof(size), "%d",
+                               eina_list_count(compose->composing_numbers));
+               elm_object_signal_emit(compose->layout, "names_count,show",
+                                       "gui");
+               elm_object_part_text_set(compose->layout,
+                                               "elm.text.names_count",
+                                               size);
+               eina_stringshare_del(names);
+       }
+exit:
+       free(msg_utf);
+}
+
+static char *_item_c_name_label_get(void *data, Evas_Object *obj __UNUSED__,
+                                       const char *part)
+{
+       Contact_Genlist *c_genlist = data;
+
+       if (strncmp(part, "text.contact.", strlen("text.contact.")))
+               return NULL;
+
+       part += strlen("text.contact.");
+
+       if (strcmp(part, "name") == 0)
+               return strdup(c_genlist->name);
+       else if (strcmp(part, "number") == 0)
+               return strdup(c_genlist->number);
+       else if (strcmp(part, "type") == 0)
+               return strdup(c_genlist->type);
+
+       ERR("Unexpected text part: %s", part);
+       return NULL;
+}
+
+static Evas_Object *_item_c_name_content_get(void *data, Evas_Object *obj,
+                                               const char *part)
+{
+       Contact_Genlist *c_genlist = data;
+
+       if (strncmp(part, "elm.swallow.", strlen("elm.swallow.")))
+               return NULL;
+
+       part += strlen("elm.swallow.");
+
+       if (strcmp(part, "photo") == 0)
+               return picture_icon_get(obj, c_genlist->picture);
+
+       ERR("Unexpected part name: %s", part);
+       return NULL;
+}
+
+
+static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__,
+                               const char *part)
+{
+       Message *msg = data;
+
+       if (strncmp(part, "text.msg.", strlen("text.msg.")))
+               return NULL;
+
+       part += strlen("text.msg.");
+
+       if (strcmp(part, "content") == 0) {
+               const char *content = message_content_get(msg);
+               if (!content)
+                       return NULL;
+               return elm_entry_utf8_to_markup(content);
+       }
+
+       if (strcmp(part, "time") == 0) {
+               time_t t_msg = message_time_get(msg);
+               if (t_msg == -1)
+                       return NULL;
+               return date_format(t_msg);
+       }
+
+       ERR("Unexpected text part: %s", part);
+       return NULL;
+}
+
+static Eina_Bool _item_state_get(void *data, Evas_Object *obj __UNUSED__,
+               const char *part)
+{
+       Message *msg = data;
+
+       if (strcmp(part, "sent") == 0) {
+               if (message_state_get(msg) == OFONO_SENT_SMS_STATE_SENT)
+                       return EINA_TRUE;
+               return EINA_FALSE;
+       } else if (strcmp(part, "failed") == 0) {
+               if (message_state_get(msg) ==  OFONO_SENT_SMS_STATE_FAILED)
+                       return EINA_TRUE;
+               return EINA_FALSE;
+       }
+
+       ERR("Unexpected state part: %s", part);
+       return EINA_FALSE;
+}
+
+static void _sms_size_calc(const char *str, int *size, int *max)
+{
+       Eina_Bool all_isprint = EINA_TRUE;
+       const char *s;
+
+        for (s = str; *s != '\0'; s++) {
+                if (!isprint(*s)) {
+                        all_isprint = EINA_FALSE;
+                        break;
+                }
+        }
+
+       *size = strlen(str);
+
+        if (all_isprint) {
+                if (*size <= 160)
+                        *max = 160;
+               else
+                       *max = ((*size / 153) + 1) * 153;
+        } else {
+                if (*size <= 70)
+                        *max = 70;
+               else
+                       *max = ((*size / 67) + 1) * 67;
+        }
+}
+
+static void _on_text_changed(void *data, Evas_Object *obj,
+                       void *event_info __UNUSED__)
+{
+       Compose *compose = data;
+       const char *msg = elm_object_part_text_get(obj, NULL);
+       Evas_Object *ed;
+       char *msg_utf8;
+       int size, max;
+       char buf[PATH_MAX];
+       Edje_Message_Int_Set *ed_msg;
+
+       if (!msg)
+               return;
+
+       msg_utf8 = elm_entry_markup_to_utf8(msg);
+       _sms_size_calc(msg_utf8, &size, &max);
+       snprintf(buf,sizeof(buf), "%d", size);
+       elm_object_part_text_set(compose->layout, "elm.text.size", buf);
+       snprintf(buf,sizeof(buf), "%d", max);
+       elm_object_part_text_set(compose->layout, "elm.text.max_size", buf);
+       free(msg_utf8);
+
+       ed_msg = alloca(sizeof(Edje_Message_Float_Set) + sizeof(int));
+       ed_msg->count = 2;
+       ed_msg->val[0] = size;
+       ed_msg->val[1] = max;
+       ed = elm_layout_edje_get(compose->layout);
+       edje_object_message_send(ed, EDJE_MESSAGE_INT_SET, 1, ed_msg);
+}
+
+static void _incoming_sms_cb(void *data, unsigned int sms_class,
+                               time_t timestamp, const char *sender,
+                               const char *message)
+{
+       Compose *compose = data;
+       Message *msg;
+       Elm_Object_Item *it;
+
+       /* Users can only send class 1. This is OFono/GSM detail */
+       if (sms_class != 1)
+               return;
+
+       if (compose->number && strcmp(compose->number, sender) != 0)
+               return;
+
+       msg = message_new(timestamp, message, EINA_FALSE,
+                               OFONO_SENT_SMS_STATE_SENT);
+
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+       message_data_set(msg, compose);
+       it = elm_genlist_item_append(compose->genlist, compose->itc_inc, msg,
+                                       NULL, ELM_GENLIST_ITEM_NONE, NULL,
+                                       NULL);
+       elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
+       message_object_item_set(msg, it);
+       compose->current_thread =
+               eina_list_append(compose->current_thread, msg);
+
+       _compose_timer_updater_start(compose);
+}
+
+static Eina_Bool _compose_time_updater(void *data)
+{
+       Compose *ctx = data;
+       double now = ecore_loop_time_get();
+       const double interval_threshold = 30.0;
+       Elm_Object_Item *it;
+       const long long update_threshold = time(NULL) - WEEK - DAY;
+
+       if (!ctx->current_thread) {
+               ctx->updater = NULL;
+               return EINA_FALSE;
+       }
+
+       if (now - ctx->last_update < interval_threshold)
+               return EINA_TRUE;
+       ctx->last_update = now;
+
+       it = elm_genlist_first_item_get(ctx->genlist);
+       for (; it != NULL; it = elm_genlist_item_next_get(it)) {
+               Message *msg = elm_object_item_data_get(it);
+               long long t = message_time_get(msg);
+               if (EINA_UNLIKELY(t == 0)) {
+                       t = message_time_get(msg);
+               }
+               if (EINA_UNLIKELY(t < update_threshold))
+                       break;
+               elm_genlist_item_update(it);
+       }
+
+       return EINA_TRUE;
+}
+
+static void _compose_timer_updater_start(Compose *compose)
+{
+       Evas *e = evas_object_evas_get(compose->layout);
+       Eina_Bool win_focused = evas_focus_state_get(e);
+       Eina_Bool obj_visible = evas_object_visible_get(compose->layout);
+
+       DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
+               compose->updater, win_focused, obj_visible);
+       if (compose->updater)
+               return;
+       if (!compose->current_thread)
+               return;
+       if ((!win_focused) || (!obj_visible))
+               return;
+
+       DBG("start poller messages");
+       /* ECORE_POLLER_CORE is 1/8th of second. */
+       compose->updater = ecore_poller_add(ECORE_POLLER_CORE, 8 * 60,
+                                               _compose_time_updater,
+                                               compose);
+       _compose_time_updater(compose);
+}
+
+static void _compose_time_updater_stop(Compose *compose)
+{
+       Evas *e = evas_object_evas_get(compose->layout);
+       Eina_Bool win_focused = evas_focus_state_get(e);
+       Eina_Bool obj_visible = evas_object_visible_get(compose->layout);
+
+       DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
+               compose->updater, win_focused, obj_visible);
+       if (!compose->updater)
+               return;
+       if (win_focused && obj_visible)
+               return;
+
+       DBG("delete poller %p", compose->updater);
+       ecore_poller_del(compose->updater);
+       compose->updater = NULL;
+}
+
+static void _on_show(void *data, Evas *e __UNUSED__,
+                       Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+       Compose *compose = data;
+       DBG("Overview became visible");
+       _compose_timer_updater_start(compose);
+}
+
+static void _on_win_focus_in(void *data, Evas *e __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       Compose *compose = data;
+       DBG("window is focused");
+       _compose_timer_updater_start(compose);
+}
+
+static void _on_win_focus_out(void *data, Evas *e __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       Compose *compose = data;
+       DBG("window is unfocused");
+       _compose_time_updater_stop(compose);
+}
+
+static void _on_hide(void *data, Evas *e __UNUSED__,
+                       Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+       Compose *compose = data;
+       DBG("Overview became hidden");
+       _compose_time_updater_stop(compose);
+}
+
+static void _on_del_clicked(void *data, Evas_Object *obj __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       Message *msg = data;
+       Compose *compose = message_data_get(msg);
+
+       EINA_SAFETY_ON_NULL_RETURN(compose);
+       _message_from_file_delete(compose, msg, compose->number);
+}
+
+static void _on_resend_clicked(void *data, Evas_Object *obj __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       Message *msg = data;
+       const char *content, *number;
+       Compose *compose = message_data_get(msg);
+
+       EINA_SAFETY_ON_NULL_RETURN(compose);
+
+       content = message_content_get(msg);
+       EINA_SAFETY_ON_NULL_RETURN(content);
+       number = message_phone_get(msg);
+       EINA_SAFETY_ON_NULL_RETURN(number);
+
+       INF("%s %s", number, content);
+       ofono_sms_send(number, content, _send_sms_reply, NULL);
+}
+
+static Evas_Object *_item_content_get(void *data, Evas_Object *obj,
+                               const char *part)
+{
+       Evas_Object *btn = NULL;
+       Message *msg = data;
+
+       if (strcmp(part, "msg.swallow.delete") == 0) {
+               btn = elm_button_add(obj);
+               EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
+               elm_object_style_set(btn, "history-delete");
+               elm_object_text_set(btn, "delete");
+               evas_object_smart_callback_add(btn, "clicked", _on_del_clicked,
+                                               msg);
+               evas_object_propagate_events_set(btn, EINA_FALSE);
+       } else if (strcmp(part, "swallow.btn.resend") == 0) {
+               btn = elm_button_add(obj);
+               EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
+               elm_object_style_set(btn, "compose-resend");
+               elm_object_text_set(btn, "Failed. Try Again?");
+               evas_object_smart_callback_add(btn, "clicked", _on_resend_clicked,
+                                               msg);
+               evas_object_propagate_events_set(btn, EINA_FALSE);
+       } else
+               ERR("unknown content part '%s'", part);
+
+       return btn;
+}
+
+static void _sent_sms_cb(void *data, OFono_Error error, OFono_Sent_SMS *sms)
+{
+       Compose *compose = data;
+       Eina_List *l;
+       Message *msg;
+
+       if (error != OFONO_ERROR_NONE) {
+               ERR("OFono error - Sending a SMS");
+               return;
+       }
+
+       EINA_LIST_FOREACH(compose->current_thread, l, msg) {
+               const char *m_sms, *m_msg;
+               time_t t_msg, t_sms;
+               unsigned char state;
+
+               m_sms = ofono_sent_sms_message_get(sms);
+               m_msg = message_content_get(msg);
+               t_msg = message_time_get(msg);
+               state = message_state_get(msg);
+               t_sms = ofono_sent_sms_timestamp_get(sms);
+
+               if ((m_sms == m_msg && t_msg == t_sms) ||
+                       (m_sms == m_msg && state == OFONO_SENT_SMS_STATE_FAILED)) {
+                       message_state_set(msg, ofono_sent_sms_state_get(sms));
+                       elm_genlist_item_update(message_object_item_get(msg));
+                       break;
+               }
+       }
+}
+
+static void _on_c_genlist_clicked(void *data, Evas_Object *obj __UNUSED__,
+                                       void *event_info)
+{
+       Elm_Object_Item *it = event_info;
+       Contact_Genlist *c_genlist = data;
+       Compose *compose = c_genlist->compose;
+
+       elm_genlist_item_selected_set(it, EINA_FALSE);
+       /* It will be used in _item_filter_cb so we will know if this
+        * number was added already
+        */
+       elm_multibuttonentry_item_prepend(compose->mb_entry, c_genlist->number,
+                                               NULL, NULL);
+}
+
+Contact_Genlist *_contact_genlist_new(const char *name,
+                                       const char *number,
+                                       const char *type,
+                                       const char *picture,
+                                       Compose *compose)
+{
+       Contact_Genlist *c_genlist = calloc(1, sizeof(Contact_Genlist));
+       EINA_SAFETY_ON_NULL_RETURN_VAL(c_genlist, NULL);
+       c_genlist->name = eina_stringshare_add(name);
+       c_genlist->number = eina_stringshare_add(number);
+       c_genlist->type = eina_stringshare_add(type);
+       c_genlist->picture = eina_stringshare_add(picture);
+       c_genlist->compose = compose;
+       return c_genlist;
+}
+
+static void _on_text_mb_entry_changed(void *data, Evas_Object *obj,
+                       void *event_info __UNUSED__)
+{
+       Compose *compose = data;
+       Contact_Partial_Match *pm;
+       Eina_List *result, *l;
+       const char *query;
+
+       query = elm_object_part_text_get(obj, NULL);
+
+       elm_genlist_clear(compose->genlist_contacts);
+
+       if ((!query) || (*query == '\0')) {
+               elm_object_signal_emit(compose->layout,
+                                       "contacts,hidden", "gui");
+               return;
+       }
+
+       DBG("Searching for contact with number: %s", query);
+
+       result = gui_contact_partial_match_search(query);
+       if (!result) {
+               DBG("No contact match: '%s'", query);
+               elm_object_signal_emit(compose->layout,
+                                       "contacts,hidden", "gui");
+               return;
+       }
+
+       EINA_LIST_FOREACH(result, l, pm) {
+               const Contact_Info *c_info;
+               const char *type, *name, *number, *picture;
+               Contact_Genlist *c_genlist;
+
+               type = contact_partial_match_type_get(pm);
+               c_info = contact_partial_match_info_get(pm);
+               name = contact_info_full_name_get(c_info);
+               number = contact_info_detail_get(c_info, type);
+               picture = contact_info_picture_get(c_info);
+
+               c_genlist = _contact_genlist_new(name, number, type,
+                                                       picture, compose);
+               EINA_SAFETY_ON_NULL_RETURN(c_genlist);
+               elm_genlist_item_append(compose->genlist_contacts,
+                                       compose->itc_c_name,
+                                       c_genlist, NULL,
+                                       ELM_GENLIST_ITEM_NONE,
+                                       _on_c_genlist_clicked,
+                                       c_genlist);
+       }
+       contact_partial_match_search_free(result);
+
+       elm_object_signal_emit(compose->layout, "contacts,show", "gui");
+}
+
+static void _on_item_added(void *data, Evas_Object *obj __UNUSED__,
+                                       void *event_info)
+{
+       Compose *compose = data;
+       const char *number, *name;
+       Contact_Info *c_info;
+       Elm_Object_Item *it = event_info;
+
+       number = elm_object_item_part_text_get(it, NULL);
+       DBG("Item added number = %s", number);
+
+       elm_object_signal_emit(compose->layout, "contacts,hidden", "gui");
+
+       if (!number)
+               return;
+
+       c_info = gui_contact_search(number, NULL);
+
+       if (!c_info) {
+               DBG("No contact found");
+               return;
+       }
+
+       name = contact_info_full_name_get(c_info);
+       DBG("Number=%s Name=%s", number, name);
+       elm_object_item_part_text_set(it, NULL, name);
+}
+
+static Eina_Bool entry_is_number(const char *str)
+{
+       int i;
+
+       for(i = 0; str[i] != '\0'; i++) {
+               if (isdigit(str[i]) == 0)
+                       return EINA_FALSE;
+       }
+
+       return EINA_TRUE;
+}
+
+static Eina_Bool _item_filter_cb(Evas_Object *obj, const char* item_label,
+                                       void *item_data __UNUSED__,
+                                       void *data)
+{
+       Evas_Object *entry;
+       Compose *compose = data;
+       const char *number;
+       Eina_List *l;
+
+       /* Did the user entered a phone number? */
+       if (entry_is_number(item_label)) {
+               EINA_LIST_FOREACH(compose->composing_numbers, l, number) {
+                       DBG("current= %s, number= %s", number, item_label);
+                       if (strcmp(number, item_label) == 0) {
+                               entry = elm_multibuttonentry_entry_get(obj);
+                               elm_object_part_text_set(entry, NULL, "");
+                               DBG("Filtered, number already in.");
+                               return EINA_FALSE;
+                       }
+               }
+               number =  eina_stringshare_add(item_label);
+               compose->composing_numbers =
+                       eina_list_append(compose->composing_numbers, number);
+               return EINA_TRUE;
+       }
+
+       return EINA_FALSE;
+}
+
+static void _item_c_genlist_del(void *data, Evas_Object *obj __UNUSED__)
+{
+       Contact_Genlist *c_genlist = data;
+
+       DBG("Deleting item: %p name: %s number: %s", c_genlist,
+               c_genlist->name, c_genlist->number);
+       eina_stringshare_del(c_genlist->name);
+       eina_stringshare_del(c_genlist->number);
+       eina_stringshare_del(c_genlist->type);
+       eina_stringshare_del(c_genlist->picture);
+       free(c_genlist);
+}
+
 Evas_Object *compose_add(Evas_Object *parent)
 {
        Compose *compose;
-       Evas_Object *obj;
+       Evas_Object *obj, *entry, *genlist, *mb_entry;
+       Evas *e;
 
        compose = calloc(1, sizeof(Compose));
        EINA_SAFETY_ON_NULL_RETURN_VAL(compose, NULL);
@@ -31,9 +808,132 @@ Evas_Object *compose_add(Evas_Object *parent)
        evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
                                        compose);
 
+       elm_object_signal_callback_add(obj, "clicked,*", "gui",
+                                       _on_layout_clicked, compose);
+
        evas_object_data_set(obj, "compose.ctx", compose);
+
+       entry = elm_entry_add(obj);
+       EINA_SAFETY_ON_NULL_GOTO(entry, err_entry);
+       elm_object_part_content_set(obj, "elm.swallow.message", entry);
+       evas_object_smart_callback_add(entry, "changed", _on_text_changed,
+                                       compose);
+       elm_object_style_set(entry, "compose");
+       elm_entry_editable_set(entry, EINA_TRUE);
+       elm_entry_scrollable_set(entry, EINA_TRUE);
+       compose->entry_msg = entry;
+
+       mb_entry = elm_multibuttonentry_add(obj);
+       EINA_SAFETY_ON_NULL_GOTO(mb_entry, err_entry);
+       elm_object_part_content_set(obj, "elm.swallow.destination", mb_entry);
+       elm_object_style_set(mb_entry, "compose");
+       elm_object_text_set(mb_entry, "To: ");
+       elm_object_part_text_set(mb_entry, "guide", "Tap to add recipient");
+       compose->mb_entry = mb_entry;
+
+       evas_object_smart_callback_add(mb_entry, "item,added",
+                                       _on_item_added, compose);
+       /* Don't let equal numbers be added */
+       elm_multibuttonentry_item_filter_append(mb_entry, _item_filter_cb,
+                                               compose);
+
+       entry = elm_multibuttonentry_entry_get(mb_entry);
+       EINA_SAFETY_ON_NULL_GOTO(entry, err_entry);
+       evas_object_smart_callback_add(entry, "changed",
+                                       _on_text_mb_entry_changed,
+                                       compose);
+
+       genlist = elm_genlist_add(obj);
+       EINA_SAFETY_ON_NULL_GOTO(genlist, err_genlist);
+       elm_genlist_mode_set(genlist, ELM_LIST_COMPRESS);
+       elm_object_style_set(genlist, "compose");
+       elm_object_part_content_set(obj, "elm.swallow.genlist", genlist);
+       compose->genlist = genlist;
+
+       genlist = elm_genlist_add(obj);
+       EINA_SAFETY_ON_NULL_GOTO(genlist, err_genlist);
+       elm_object_style_set(genlist, "compose");
+       elm_object_part_content_set(obj, "elm.swallow.genlist.contacts",
+                                       genlist);
+       compose->genlist_contacts = genlist;
+       elm_object_focus_allow_set(genlist, EINA_FALSE);
+
+#ifdef HAVE_TIZEN
+       elm_genlist_scroller_policy_set(compose->genlist,
+                                       ELM_SCROLLER_POLICY_OFF,
+                                       ELM_SCROLLER_POLICY_AUTO);
+       elm_genlist_scroller_policy_set(compose->genlist_contacts,
+                                       ELM_SCROLLER_POLICY_OFF,
+                                       ELM_SCROLLER_POLICY_AUTO);
+#else
+       elm_scroller_policy_set(compose->genlist,
+                               ELM_SCROLLER_POLICY_OFF,
+                               ELM_SCROLLER_POLICY_AUTO);
+       elm_scroller_policy_set(compose->genlist_contacts,
+                               ELM_SCROLLER_POLICY_OFF,
+                               ELM_SCROLLER_POLICY_AUTO);
+#endif
+
+       compose->itc_inc = elm_genlist_item_class_new();
+       EINA_SAFETY_ON_NULL_GOTO(compose->itc_inc, err_itc);
+       compose->itc_inc->item_style = "messages-incoming";
+       compose->itc_inc->func.text_get = _item_label_get;
+       compose->itc_inc->func.content_get = _item_content_get;
+       compose->itc_inc->func.state_get = NULL;
+       compose->itc_inc->func.del = NULL;
+       compose->itc_inc->decorate_all_item_style = "incoming-delete";
+       compose->itc_inc->decorate_item_style = "incoming-delete";
+
+       compose->itc_out = elm_genlist_item_class_new();
+       EINA_SAFETY_ON_NULL_GOTO(compose->itc_out, err_itc_out);
+       compose->itc_out->item_style = "messages-outgoing";
+       compose->itc_out->func.text_get = _item_label_get;
+       compose->itc_out->func.content_get = _item_content_get;
+       compose->itc_out->func.state_get = _item_state_get;
+       compose->itc_out->func.del = NULL;
+       compose->itc_out->decorate_all_item_style = "outgoing-delete";
+       compose->itc_out->decorate_item_style = "outgoing-delete";
+
+       compose->itc_c_name = elm_genlist_item_class_new();
+       EINA_SAFETY_ON_NULL_GOTO(compose->itc_c_name, err_names);
+       compose->itc_c_name->item_style = "contacts-compose";
+       compose->itc_c_name->func.text_get = _item_c_name_label_get;
+       compose->itc_c_name->func.content_get = _item_c_name_content_get;
+       compose->itc_c_name->func.state_get = NULL;
+       compose->itc_c_name->func.del = _item_c_genlist_del;
+
+       elm_object_part_text_set(compose->layout, "elm.text.name",
+                                       "New Message");
+       elm_object_signal_emit(compose->layout, "hide,genlist", "gui");
+       compose->composing = EINA_TRUE;
+       elm_object_signal_emit(compose->layout, "composing", "gui");
+
+       incoming_sms = ofono_incoming_sms_cb_add(_incoming_sms_cb, compose);
+       sent_sms = ofono_sent_sms_changed_cb_add(_sent_sms_cb, compose);
+
+       evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide,
+                                       compose);
+       evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show,
+                                       compose);
+
+       e = evas_object_evas_get(obj);
+       evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_OUT,
+                               _on_win_focus_out, compose);
+       evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_IN,
+                               _on_win_focus_in, compose);
+
        return obj;
 
+err_names:
+       elm_genlist_item_class_free(compose->itc_out);
+err_itc_out:
+       elm_genlist_item_class_free(compose->itc_inc);
+err_itc:
+       evas_object_del(genlist);
+err_genlist:
+       evas_object_del(entry);
+err_entry:
+       evas_object_del(obj);
 err_obj:
        free(compose);
        return NULL;
@@ -53,3 +953,54 @@ void compose_set(Evas_Object *obj, const char *number, const char *message,
 
        ERR("TODO '%s' '%s' %d", number, message, do_auto);
 }
+
+void compose_messages_set(Evas_Object *obj, Eina_List *list, const char *number)
+{
+       Compose *compose;
+       Message *msg;
+       Eina_List *l;
+       Elm_Genlist_Item_Class *itc;
+       Elm_Object_Item *it = NULL;
+       Contact_Info *c_info;
+
+       EINA_SAFETY_ON_NULL_RETURN(obj);
+       compose = evas_object_data_get(obj, "compose.ctx");
+       EINA_SAFETY_ON_NULL_RETURN(compose);
+
+       eina_stringshare_replace(&(compose->number), number);
+
+       elm_genlist_clear(compose->genlist);
+
+       EINA_LIST_FOREACH(list, l, msg) {
+               Eina_Bool outgoing = message_outgoing_get(msg);
+
+               if (outgoing)
+                       itc = compose->itc_out;
+               else
+                       itc = compose->itc_inc;
+               message_data_set(msg, compose);
+               it = elm_genlist_item_append(compose->genlist, itc, msg, NULL,
+                                               ELM_GENLIST_ITEM_NONE, NULL,
+                                               NULL);
+               message_object_item_set(msg, it);
+               message_ref(msg);
+       }
+       if (it)
+               elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_IN);
+
+       compose->current_thread = list;
+       elm_object_signal_emit(compose->layout, "show,genlist", "gui");
+
+       c_info = gui_contact_search(number, NULL);
+
+       if (!c_info)
+               elm_object_part_text_set(compose->layout, "elm.text.name",
+                                               number);
+       else
+               elm_object_part_text_set(compose->layout, "elm.text.name",
+                                           contact_info_full_name_get(c_info));
+
+       compose->composing = EINA_FALSE;
+       _compose_timer_updater_start(compose);
+       elm_object_signal_emit(compose->layout, "viewing", "gui");
+}
index 5da0083..72a7ea1 100644 (file)
@@ -6,4 +6,6 @@ Evas_Object *compose_add(Evas_Object *parent);
 void compose_set(Evas_Object *obj, const char *number, const char *message,
                        Eina_Bool do_auto);
 
+void compose_messages_set(Evas_Object *obj, Eina_List *list, const char *number);
+
 #endif
index 86a2173..20d75f4 100644 (file)
@@ -8,6 +8,7 @@
 #include "compose.h"
 #include "util.h"
 #include "simple-popup.h"
+#include "contacts-ofono-efl.h"
 
 #ifdef HAVE_TIZEN
 #include <appcore-efl.h>
@@ -19,11 +20,43 @@ static Evas_Object *win = NULL;
 static Evas_Object *main_layout = NULL;
 static Evas_Object *cs = NULL;
 static Evas_Object *flip = NULL;
+static Evas_Object *ov = NULL;
+static Evas_Object *contacts = NULL;
 
 /* XXX elm_flip should just do the right thing, but it does not */
 static Eina_Bool in_compose = EINA_FALSE;
 static Eina_Bool in_flip_anim = EINA_FALSE;
 
+Eina_List * gui_contact_partial_match_search(const char *query)
+{
+       return contact_partial_match_search(contacts, query);
+}
+
+void gui_overview_genlist_update(Message *msg, const char *contact)
+{
+       overview_genlist_update(ov, msg, contact);
+}
+
+void gui_overview_all_contact_messages_clear(const char *contact)
+{
+       overview_all_contact_messages_clear(ov, contact);
+}
+
+void gui_message_from_file_delete(Message *msg, const char *contact)
+{
+       overview_message_from_file_delete(ov, msg, contact);
+}
+
+void gui_compose_messages_set(Eina_List *list, const char *number)
+{
+       compose_messages_set(cs, list, number);
+}
+
+Contact_Info *gui_contact_search(const char *number, const char **type)
+{
+       return contact_search(contacts, number, type);
+}
+
 Evas_Object *gui_simple_popup(const char *title, const char *message)
 {
        return simple_popup_add(win, title, message);
@@ -86,13 +119,11 @@ static void _on_clicked(void *data __UNUSED__, Evas_Object *o __UNUSED__,
 
        EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
        emission += strlen("clicked,");
-
-       ERR("TODO: %s", emission);
 }
 
 Eina_Bool gui_init(void)
 {
-       Evas_Object *lay, *obj;
+       Evas_Object *lay, *obj, *conform;
        Evas_Coord w, h;
 
        /* messages should never, ever quit */
@@ -101,6 +132,7 @@ Eina_Bool gui_init(void)
        win = elm_win_util_standard_add("ofono-messages", "oFono Messages");
        EINA_SAFETY_ON_NULL_RETURN_VAL(win, EINA_FALSE);
        elm_win_autodel_set(win, EINA_FALSE);
+       elm_win_conformant_set(win, EINA_TRUE);
 
 #ifdef HAVE_TIZEN
        appcore_set_i18n("ofono-efl", "en-US");
@@ -127,14 +159,29 @@ Eina_Bool gui_init(void)
        elm_object_signal_callback_add(lay, "clicked,*", "gui",
                                        _on_clicked, NULL);
 
+       contacts = obj = contacts_add(win);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, EINA_FALSE);
+
        cs = obj = compose_add(win);
        EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
        evas_object_size_hint_weight_set(obj,
                                EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
        evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
-       elm_object_part_content_set(flip, "back", obj);
        evas_object_show(obj);
 
+       ov = obj = overview_add(win);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
+       elm_object_part_content_set(lay, "elm.swallow.overview", obj);
+       evas_object_show(ov);
+
+       conform = elm_conformant_add(win);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(conform, EINA_FALSE);
+       elm_win_resize_object_add(win, conform);
+       evas_object_size_hint_weight_set(conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+       evas_object_show(conform);
+       elm_object_content_set(conform, cs);
+       elm_object_part_content_set(flip, "back", conform);
+
        /* TODO: make it match better with Tizen: icon and other properties */
        obj = elm_layout_edje_get(lay);
        edje_object_size_min_get(obj, &w, &h);
index 8e3e2db..b9207a5 100644 (file)
@@ -3,6 +3,8 @@
 
 #include "contacts-ofono-efl.h"
 #include "ofono.h"
+#include "overview.h"
+#include <Eina.h>
 
 Evas_Object *gui_simple_popup(const char *title, const char *message);
 
@@ -15,4 +17,16 @@ void gui_compose_exit(void);
 Eina_Bool gui_init(void);
 void gui_shutdown(void);
 
+Contact_Info *gui_contact_search(const char *number, const char **type);
+
+void gui_compose_messages_set(Eina_List *list, const char *number);
+
+void gui_message_from_file_delete(Message *msg, const char *contact);
+
+void gui_overview_genlist_update(Message *msg, const char *contact);
+
+void gui_overview_all_contact_messages_clear(const char *contact);
+
+Eina_List *gui_contact_partial_match_search(const char *query);
+
 #endif
diff --git a/messages/overview.c b/messages/overview.c
new file mode 100644 (file)
index 0000000..795aec5
--- /dev/null
@@ -0,0 +1,1162 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Elementary.h>
+#include <Eet.h>
+#include <Eina.h>
+#include <stdio.h>
+#include <Ecore.h>
+
+#include "overview.h"
+#include "log.h"
+#include "util.h"
+#include "gui.h"
+#include "contacts-ofono-efl.h"
+
+#define ALL_MESSAGES "all_messages"
+
+#ifndef EET_COMPRESSION_DEFAULT
+#define EET_COMPRESSION_DEFAULT 1
+#endif
+
+/* This struct hold the content of the messages that will be showed
+ * in the main screen
+ */
+typedef struct _Messages_List
+{
+       Eina_List *list;
+       Eina_Bool dirty; /* not in eet */
+       Ecore_Poller *save_poller; /* not in eet */
+} Messages_List;
+
+struct _Message
+{
+       const char *content;
+       unsigned char outgoing;
+       unsigned char state;
+       long long time;
+       const char *phone; /* phone number -  not in eet */
+       int refcount; /* not in eet */
+       void *data; /* not in eet */
+       Elm_Object_Item *it; /* not in eet */
+};
+
+typedef struct _Overview
+{
+       Eet_Data_Descriptor *edd_msg_info;
+       Eet_Data_Descriptor *edd_msg_list;
+       Eet_Data_Descriptor *edd_msg;
+       Eet_Data_Descriptor *edd_c_msg;
+       Messages_List *messages;
+       /* Pending conversations, not saved in eet yet */
+       Messages_List *p_conversations;
+       Evas_Object *layout, *genlist;
+       char *msg_path, *base_dir, *msg_bkp;
+       Ecore_Poller *updater;
+       double last_update;
+       Elm_Genlist_Item_Class *itc;
+       Eina_Hash *pending_sms;
+} Overview;
+
+/* Messages showed in the main screen */
+typedef struct _Message_Info
+{
+       const char *sender, *last_msg;
+       long long time;
+       int count;
+       Overview *ov; /*not in eet */
+       Elm_Object_Item *it; /* not in eet */
+} Message_Info;
+
+static OFono_Callback_List_Incoming_SMS_Node *incoming_sms = NULL;
+static OFono_Callback_List_Sent_SMS_Node *sent_sms = NULL;
+
+static void _overview_messages_save(Overview *ov);
+static Message_Info *_message_info_search(Overview *ov, const char *sender);
+static void _message_info_del(Message_Info *m_info);
+static void _overview_messages_save(Overview *ov);
+static void _conversation_eet_update_save(Overview *ov, Message *msg);
+static void _message_free(Message *msg);
+
+void message_ref(Message *msg)
+{
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+       msg->refcount++;
+}
+
+static Eina_Bool _overview_messages_save_do(void *data)
+{
+       Overview *ov = data;
+       Eet_File *efile;
+       EINA_SAFETY_ON_NULL_RETURN_VAL(ov->messages, ECORE_CALLBACK_DONE);
+
+       ov->messages->save_poller = NULL;
+       ov->messages->dirty = EINA_FALSE;
+
+       ecore_file_unlink(ov->msg_bkp);
+       ecore_file_mv(ov->msg_path, ov->msg_bkp);
+       efile = eet_open(ov->msg_path, EET_FILE_MODE_WRITE);
+       EINA_SAFETY_ON_NULL_GOTO(efile, failed);
+
+       if (!(eet_data_write(efile,
+                               ov->edd_msg_list, ALL_MESSAGES,
+                               ov->messages, EET_COMPRESSION_DEFAULT)))
+               ERR("Could in the messages log file");
+
+       eet_close(efile);
+       return ECORE_CALLBACK_DONE;
+
+failed:
+       ecore_file_mv(ov->msg_bkp, ov->msg_path);
+       return ECORE_CALLBACK_DONE;
+}
+
+void overview_genlist_update(Evas_Object *obj, Message *msg,
+                               const char *contact)
+{
+       Overview *ov;
+       Message_Info *m_info;
+
+       EINA_SAFETY_ON_NULL_RETURN(obj);
+       ov = evas_object_data_get(obj, "overview.ctx");
+       EINA_SAFETY_ON_NULL_RETURN(ov);
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+
+       m_info = _message_info_search(ov, contact);
+       EINA_SAFETY_ON_NULL_RETURN(m_info);
+
+       m_info->time = msg->time;
+       eina_stringshare_replace(&m_info->last_msg, msg->content);
+       _overview_messages_save(ov);
+       elm_genlist_item_update(m_info->it);
+}
+
+void message_object_item_set(Message *msg, Elm_Object_Item *it)
+{
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+       msg->it = it;
+}
+
+Elm_Object_Item *message_object_item_get(const Message *msg)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+       return msg->it;
+}
+
+void message_state_set(Message *msg, unsigned char state)
+{
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+       msg->state = state;
+}
+
+void *message_data_get(const Message *msg)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+       return msg->data;
+}
+
+void message_data_set(Message *msg, void *data)
+{
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+       msg->data = data;
+}
+
+static Eina_Bool _message_is_equal(Message *m1, Message *m2)
+{
+       if (strcmp(m1->content, m2->content) != 0)
+               return EINA_FALSE;
+
+       if (m1->outgoing != m2->outgoing)
+               return EINA_FALSE;
+
+       if (m1->state != m2->state)
+               return EINA_FALSE;
+
+       if (m1->time != m2->time)
+               return EINA_FALSE;
+
+       return EINA_TRUE;
+}
+
+void overview_message_from_file_delete(Evas_Object *obj, Message *msg,
+                                       const char *contact)
+{
+       Eet_File *efile;
+       Overview *ov;
+       char buf[PATH_MAX], bkp[PATH_MAX];
+       Messages_List *messages = NULL;
+       Eina_List *l;
+       Message *msg_aux;
+
+       EINA_SAFETY_ON_NULL_RETURN(obj);
+       ov = evas_object_data_get(obj, "overview.ctx");
+       EINA_SAFETY_ON_NULL_RETURN(ov);
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+
+       snprintf(buf, sizeof(buf), "%s/%s.eet", ov->base_dir, contact);
+       snprintf(bkp, sizeof(bkp), "%s/%s.eet.bkp", ov->base_dir, contact);
+
+       efile = eet_open(buf, EET_FILE_MODE_READ_WRITE);
+
+       if (efile) {
+               messages = eet_data_read(efile, ov->edd_c_msg, ALL_MESSAGES);
+       }
+
+       if (!messages) {
+               efile = eet_open(bkp, EET_FILE_MODE_READ_WRITE);
+               if (efile) {
+                       messages = eet_data_read(efile, ov->edd_c_msg,
+                                                       ALL_MESSAGES);
+               }
+       }
+
+       if (!messages)
+               return;
+
+       EINA_LIST_FOREACH(messages->list, l, msg_aux) {
+               if (_message_is_equal(msg, msg_aux)) {
+                       _message_free(msg_aux);
+                       messages->list = eina_list_remove_list(messages->list,
+                                                               l);
+                       break;
+               }
+       }
+       Message_Info *m_info = _message_info_search(ov, contact);
+       EINA_SAFETY_ON_NULL_RETURN(m_info);
+       m_info->count--;
+       if (messages->list && eina_list_count(messages->list) != 0) {
+               eet_data_write(efile, ov->edd_c_msg, ALL_MESSAGES, messages,
+                               EET_COMPRESSION_DEFAULT);
+               eet_close(efile);
+       } else {
+               eet_close(efile);
+               _message_info_del(m_info);
+       }
+
+       EINA_LIST_FREE(messages->list, msg_aux)
+               _message_free(msg_aux);
+       free(messages);
+}
+
+unsigned char message_state_get(const Message *msg)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, '\0');
+       return msg->state;
+}
+
+const char * message_content_get(const Message *msg)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+       return msg->content;
+}
+
+const char * message_phone_get(const Message *msg)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+       return msg->phone;
+}
+
+unsigned char message_outgoing_get(const Message *msg)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, '\0');
+       return msg->outgoing;
+}
+
+long long message_time_get(const Message *msg)
+{
+
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, -1);
+       return msg->time;
+}
+
+static Message_Info *_message_info_search(Overview *ov, const char *sender)
+{
+       Eina_List *l;
+       Message_Info *m_info;
+
+       EINA_SAFETY_ON_NULL_RETURN_VAL(ov->messages, NULL);
+
+       EINA_LIST_FOREACH(ov->messages->list, l, m_info) {
+               if (strcmp(sender, m_info->sender) == 0)
+                       return m_info;
+       }
+
+       return NULL;
+}
+
+static void _message_free(Message *msg)
+{
+       DBG("MSG=%p", msg);
+       eina_stringshare_del(msg->content);
+       eina_stringshare_del(msg->phone);
+       free(msg);
+}
+
+void message_del(Message *msg)
+{
+
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+       DBG("MSG=%p, refcount=%d", msg, msg->refcount);
+       EINA_SAFETY_ON_TRUE_RETURN(msg->refcount <= 0);
+       msg->refcount--;
+
+       if (msg->refcount == 0)
+               _message_free(msg);
+}
+
+static void _message_info_free(Message_Info *m_info)
+{
+       eina_stringshare_del(m_info->sender);
+       eina_stringshare_del(m_info->last_msg);
+       free(m_info);
+}
+
+static void _messages_file_delete(char *dir, const char *sender)
+{
+       char path[PATH_MAX];
+       snprintf(path, sizeof(path), "%s/%s.eet", dir, sender);
+       ecore_file_unlink(path);
+       snprintf(path, sizeof(path), "%s/%s.eet.bkp", dir, sender);
+       ecore_file_unlink(path);
+}
+
+static void _message_info_del(Message_Info *m_info)
+{
+       Overview *ctx = m_info->ov;
+       Eina_List *l, *next;
+       Message *msg;
+
+       EINA_SAFETY_ON_NULL_RETURN(ctx);
+
+       elm_object_item_del(m_info->it);
+
+       ctx->messages->list = eina_list_remove(ctx->messages->list, m_info);
+       ctx->messages->dirty = EINA_TRUE;
+
+       /* Remove unsaved SMSs */
+       EINA_LIST_FOREACH_SAFE(ctx->p_conversations->list, l, next, msg) {
+               if (msg->phone == m_info->sender) {
+                       ctx->p_conversations->list =
+                               eina_list_remove(ctx->p_conversations->list,
+                                                       msg);
+                       message_del(msg);
+               }
+       }
+
+       _messages_file_delete(ctx->base_dir, m_info->sender);
+       _overview_messages_save(ctx);
+
+       if ((!ctx->messages->list) && (ctx->updater)) {
+               ecore_poller_del(ctx->updater);
+               ctx->updater = NULL;
+       }
+
+       _message_info_free(m_info);
+}
+
+static void _on_del(void *data, Evas *e __UNUSED__,
+                       Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+       Overview *ov = data;
+       Message_Info *m_info;
+       Message *msg;
+
+       ofono_incoming_sms_cb_del(incoming_sms);
+       ofono_sent_sms_changed_cb_del(sent_sms);
+
+       if (ov->messages->save_poller)
+               ecore_poller_del(ov->messages->save_poller);
+
+       if (ov->p_conversations->save_poller)
+               ecore_poller_del(ov->p_conversations->save_poller);
+
+       if (ov->messages->dirty)
+               _overview_messages_save_do(ov);
+
+       eina_hash_free(ov->pending_sms);
+
+       if (!ov->p_conversations->dirty) {
+               EINA_LIST_FREE(ov->p_conversations->list, msg)
+                       message_del(msg);
+       } else {
+               EINA_LIST_FREE(ov->p_conversations->list, msg) {
+                       _conversation_eet_update_save(ov, msg);
+                       message_del(msg);
+               }
+       }
+
+       EINA_LIST_FREE(ov->messages->list, m_info)
+               _message_info_free(m_info);
+
+       eet_data_descriptor_free(ov->edd_msg_info);
+       eet_data_descriptor_free(ov->edd_msg_list);
+       eet_data_descriptor_free(ov->edd_msg);
+       eet_data_descriptor_free(ov->edd_c_msg);
+
+       elm_genlist_item_class_free(ov->itc);
+       free(ov->messages);
+       free(ov->msg_path);
+       free(ov->base_dir);
+       free(ov->msg_bkp);
+       free(ov->p_conversations);
+       free(ov);
+
+       eet_shutdown();
+       ecore_file_shutdown();
+}
+
+static void _eet_descriptors_init(Eet_Data_Descriptor **messages,
+                                       Eet_Data_Descriptor **msg_info,
+                                       Eet_Data_Descriptor **edd_msg,
+                                       Eet_Data_Descriptor **edd_c_msg)
+{
+       Eet_Data_Descriptor_Class eddc;
+       Eet_Data_Descriptor_Class eddcM;
+
+       EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Message_Info);
+       *msg_info = eet_data_descriptor_stream_new(&eddc);
+
+       EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Messages_List);
+       *messages = eet_data_descriptor_stream_new(&eddc);
+
+       EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddcM, Message);
+       *edd_msg = eet_data_descriptor_stream_new(&eddcM);
+
+       EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddcM, Messages_List);
+       *edd_c_msg = eet_data_descriptor_stream_new(&eddcM);
+
+       EET_DATA_DESCRIPTOR_ADD_BASIC(*edd_msg, Message,
+                                       "content", content, EET_T_STRING);
+       EET_DATA_DESCRIPTOR_ADD_BASIC(*edd_msg, Message,
+                                       "time", time, EET_T_LONG_LONG);
+       EET_DATA_DESCRIPTOR_ADD_BASIC(*edd_msg, Message,
+                                       "outgoing", outgoing, EET_T_UCHAR);
+       EET_DATA_DESCRIPTOR_ADD_BASIC(*edd_msg, Message,
+                                       "state", state, EET_T_UCHAR);
+
+       EET_DATA_DESCRIPTOR_ADD_BASIC(*msg_info, Message_Info,
+                                       "sender", sender, EET_T_STRING);
+       EET_DATA_DESCRIPTOR_ADD_BASIC(*msg_info, Message_Info,
+                                       "last_msg", last_msg, EET_T_STRING);
+       EET_DATA_DESCRIPTOR_ADD_BASIC(*msg_info, Message_Info,
+                                       "time", time, EET_T_LONG_LONG);
+       EET_DATA_DESCRIPTOR_ADD_BASIC(*msg_info, Message_Info,
+                                       "count", count, EET_T_INT);
+
+       EET_DATA_DESCRIPTOR_ADD_LIST(*messages, Messages_List, "list", list,
+                                       *msg_info);
+
+       EET_DATA_DESCRIPTOR_ADD_LIST(*edd_c_msg, Messages_List, "list", list,
+                                       *edd_msg);
+
+}
+
+static void _overview_messages_save(Overview *ov)
+{
+       if (ov->messages->save_poller)
+               return;
+       ov->messages->save_poller = ecore_poller_add(ECORE_POLLER_CORE, 32,
+                                                    _overview_messages_save_do,
+                                                       ov);
+}
+
+static void _on_item_clicked(void *data, Evas_Object *obj __UNUSED__,
+                               void *event_info)
+{
+       Message_Info *m_info = data;
+       Elm_Object_Item *it = event_info;
+       char buf[PATH_MAX], bkp[PATH_MAX];
+       Overview *ov = m_info->ov;
+       Eet_File *efile;
+       Messages_List *messages = NULL;
+
+       elm_genlist_item_selected_set(it, EINA_FALSE);
+
+       snprintf(buf, sizeof(buf), "%s/%s.eet", ov->base_dir, m_info->sender);
+       snprintf(bkp, sizeof(bkp), "%s/%s.eet.bkp", ov->base_dir,
+                       m_info->sender);
+
+       efile = eet_open(buf, EET_FILE_MODE_READ);
+
+       if (efile) {
+               messages = eet_data_read(efile, ov->edd_c_msg, ALL_MESSAGES);
+               eet_close(efile);
+       }
+
+       if (!messages) {
+               efile = eet_open(bkp, EET_FILE_MODE_READ);
+               if (efile) {
+                       messages = eet_data_read(efile, ov->edd_c_msg,
+                                                       ALL_MESSAGES);
+                       eet_close(efile);
+               }
+       }
+       if (messages) {
+               gui_compose_messages_set(messages->list, m_info->sender);
+               gui_compose_enter();
+               /* Compose will free the messages->list for me */
+               free(messages);
+       } else
+               INF("Could not read the messages list!");
+}
+
+static void _overview_messages_read(Overview *ov)
+{
+       Eet_File *efile;
+       Messages_List *msg_list = NULL;
+       Eina_List *l;
+       Message_Info *m_info;
+       Elm_Object_Item *it;
+
+       efile = eet_open(ov->msg_path, EET_FILE_MODE_READ);
+
+       if (efile) {
+               msg_list = eet_data_read(efile, ov->edd_msg_list, ALL_MESSAGES);
+               eet_close(efile);
+       }
+
+       if (!msg_list) {
+               efile = eet_open(ov->msg_bkp, EET_FILE_MODE_READ);
+               if (efile) {
+                       msg_list = eet_data_read(efile, ov->edd_msg_list,
+                                               ALL_MESSAGES);
+                       eet_close(efile);
+               }
+       }
+
+       if (!msg_list)
+               msg_list = calloc(1, sizeof(Messages_List));
+
+       ov->messages = msg_list;
+       EINA_SAFETY_ON_NULL_RETURN(ov->messages);
+
+       EINA_LIST_FOREACH(ov->messages->list, l, m_info) {
+               it = elm_genlist_item_append(ov->genlist,
+                                               ov->itc, m_info, NULL,
+                                               ELM_GENLIST_ITEM_NONE,
+                                               _on_item_clicked, m_info);
+               m_info->ov = ov;
+               m_info->it = it;
+       }
+}
+
+static Eina_Bool _overview_time_updater(void *data)
+{
+       Overview *ctx = data;
+       double now = ecore_loop_time_get();
+       const double interval_threshold = 30.0;
+       Elm_Object_Item *it;
+       const long long update_threshold = time(NULL) - WEEK - DAY;
+
+       if (!ctx->messages->list) {
+               ctx->updater = NULL;
+               return EINA_FALSE;
+       }
+
+       if (now - ctx->last_update < interval_threshold)
+               return EINA_TRUE;
+       ctx->last_update = now;
+
+       it = elm_genlist_first_item_get(ctx->genlist);
+       for (; it != NULL; it = elm_genlist_item_next_get(it)) {
+               const Message_Info *m_info = elm_object_item_data_get(it);
+               long long t = m_info->time;
+               if (EINA_UNLIKELY(t == 0)) {
+                       t = m_info->time;
+               }
+               if (EINA_UNLIKELY(t < update_threshold))
+                       break;
+               elm_genlist_item_update(it);
+       }
+
+       return EINA_TRUE;
+}
+
+static void _overview_timer_updater_start(Overview *ov)
+{
+       Evas *e = evas_object_evas_get(ov->layout);
+       Eina_Bool win_focused = evas_focus_state_get(e);
+       Eina_Bool obj_visible = evas_object_visible_get(ov->layout);
+
+       DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
+               ov->updater, win_focused, obj_visible);
+       if (ov->updater)
+               return;
+       if (!ov->messages->list)
+               return;
+       if ((!win_focused) || (!obj_visible))
+               return;
+
+       DBG("start poller messages");
+       /* ECORE_POLLER_CORE is 1/8th of second. */
+       ov->updater = ecore_poller_add(ECORE_POLLER_CORE, 8 * 60,
+                                               _overview_time_updater,
+                                               ov);
+       _overview_time_updater(ov);
+}
+
+static void _overview_time_updater_stop(Overview *ov)
+{
+       Evas *e = evas_object_evas_get(ov->layout);
+       Eina_Bool win_focused = evas_focus_state_get(e);
+       Eina_Bool obj_visible = evas_object_visible_get(ov->layout);
+
+       DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
+               ov->updater, win_focused, obj_visible);
+       if (!ov->updater)
+               return;
+       if (win_focused && obj_visible)
+               return;
+
+       DBG("delete poller %p", ov->updater);
+       ecore_poller_del(ov->updater);
+       ov->updater = NULL;
+}
+
+static Message *_message_list_search(Eina_List *list, Message *msg)
+{
+       Eina_List *l;
+       Message *m;
+
+       EINA_LIST_FOREACH(list, l, m) {
+               if ((m->content == msg->content &&
+                       m->time == msg->time) ||
+                       (msg->content == m->content && m->state != msg->state))
+                       return m;
+       }
+
+       return NULL;
+}
+
+static void _conversation_eet_update_save(Overview *ov, Message *msg)
+{
+
+       Eet_File *efile;
+       char buf[PATH_MAX], bkp[PATH_MAX];
+       Messages_List *messages = NULL;
+       Message *msg_aux;
+
+       snprintf(buf, sizeof(buf), "%s/%s.eet", ov->base_dir, msg->phone);
+       snprintf(bkp, sizeof(bkp), "%s/%s.eet.bkp", ov->base_dir, msg->phone);
+
+       efile = eet_open(buf, EET_FILE_MODE_READ);
+
+       if (efile) {
+               messages = eet_data_read(efile, ov->edd_c_msg, ALL_MESSAGES);
+               eet_close(efile);
+       }
+
+       if (!messages) {
+               efile = eet_open(bkp, EET_FILE_MODE_READ);
+               if (efile) {
+                       messages = eet_data_read(efile, ov->edd_c_msg,
+                                                       ALL_MESSAGES);
+                       eet_close(efile);
+               }
+       }
+
+       /* New file */
+       if (!messages) {
+               messages = calloc(1, sizeof(Messages_List));
+               EINA_SAFETY_ON_NULL_RETURN(messages);
+       }
+
+       msg_aux = _message_list_search(messages->list, msg);
+
+       if (!msg_aux) {
+               messages->list = eina_list_append(messages->list, msg);
+               msg->refcount++;
+       } else
+               msg_aux->state = msg->state;
+
+       ecore_file_unlink(bkp);
+       ecore_file_mv(buf, bkp);
+
+       efile = eet_open(buf, EET_FILE_MODE_WRITE);
+       EINA_SAFETY_ON_NULL_RETURN(efile);
+
+       eet_data_write(efile, ov->edd_c_msg, ALL_MESSAGES, messages,
+                       EET_COMPRESSION_DEFAULT);
+
+       eet_close(efile);
+       EINA_LIST_FREE(messages->list, msg_aux) {
+               if (msg_aux == msg)
+                       message_del(msg);
+               else /* messages read from eet have no refcount */
+                       _message_free(msg_aux);
+       }
+       free(messages);
+}
+
+static Eina_Bool _conversation_eet_update_do(void *data)
+{
+       Overview *ov = data;
+       Message *msg;
+
+       ov->p_conversations->dirty = EINA_FALSE;
+       ov->p_conversations->save_poller = NULL;
+
+       EINA_LIST_FREE(ov->p_conversations->list, msg) {
+               _conversation_eet_update_save(ov, msg);
+               message_del(msg);
+       }
+       ov->p_conversations->list = NULL;
+       return ECORE_CALLBACK_DONE;
+}
+
+static void _conversation_eet_update(Overview *ov)
+{
+       if (ov->p_conversations->save_poller)
+               return;
+
+       ov->p_conversations->save_poller = ecore_poller_add(ECORE_POLLER_CORE,
+                                                               32,
+                                                               _conversation_eet_update_do,
+                                                               ov);
+}
+
+static void _message_info_genlist_update(Overview *ov, time_t timestamp,
+                                               const char *sender,
+                                               const char *message)
+{
+       Message_Info *m_info;
+       Elm_Object_Item *it;
+
+       m_info = _message_info_search(ov, sender);
+
+       if (!m_info) {
+               m_info = calloc(1, sizeof(Message_Info));
+               EINA_SAFETY_ON_NULL_RETURN(m_info);
+               m_info->sender = eina_stringshare_add(sender);
+               ov->messages->list = eina_list_prepend(ov->messages->list,
+                                                       m_info);
+               m_info->ov = ov;
+       } else {
+               ov->messages->list = eina_list_remove(ov->messages->list,
+                                                       m_info);
+               ov->messages->list = eina_list_prepend(ov->messages->list,
+                                                       m_info);
+               if (m_info->it)
+                       elm_object_item_del(m_info->it);
+       }
+
+       m_info->count++;
+       m_info->time = timestamp;
+       eina_stringshare_replace(&m_info->last_msg, message);
+       ov->messages->dirty = EINA_TRUE;
+
+       it = elm_genlist_item_prepend(ov->genlist,
+                                       ov->itc, m_info, NULL,
+                                       ELM_GENLIST_ITEM_NONE,
+                                       _on_item_clicked, m_info);
+       m_info->it = it;
+
+       elm_genlist_item_show(m_info->it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
+       _overview_timer_updater_start(ov);
+       _overview_messages_save(ov);
+}
+
+Message *message_new(time_t timestamp, const char *content,
+                       Eina_Bool outgoing, OFono_Sent_SMS_State state)
+{
+       Message *msg;
+
+       msg = calloc(1, sizeof(Message));
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+       msg->time = timestamp;
+       msg->outgoing = outgoing;
+       msg->content = eina_stringshare_add(content);
+       msg->state = state;
+       msg->refcount++;
+       return msg;
+}
+
+static void _incoming_sms_cb(void *data, unsigned int sms_class,
+                               time_t timestamp, const char *sender,
+                               const char *message)
+{
+       Overview *ov = data;
+       Message *msg;
+
+       /* Users can only send class 1. This is OFono/GSM detail */
+       if (sms_class != 1)
+               return;
+
+       msg = message_new(timestamp, message, EINA_FALSE,
+                               OFONO_SENT_SMS_STATE_SENT);
+       EINA_SAFETY_ON_NULL_RETURN(msg);
+       msg->phone = eina_stringshare_add(sender);
+
+       _message_info_genlist_update(ov, timestamp, sender, message);
+
+       ov->p_conversations->list = eina_list_append(ov->p_conversations->list,
+                                                       msg);
+       ov->p_conversations->dirty = EINA_TRUE;
+       _conversation_eet_update(ov);
+}
+
+static void _on_show(void *data, Evas *e __UNUSED__,
+                       Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+       Overview *ov = data;
+       DBG("Overview became visible");
+       _overview_timer_updater_start(ov);
+}
+
+static void _on_win_focus_in(void *data, Evas *e __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       Overview *ov = data;
+       DBG("window is focused");
+       _overview_timer_updater_start(ov);
+}
+
+static void _on_win_focus_out(void *data, Evas *e __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       Overview *ov = data;
+       DBG("window is unfocused");
+       _overview_time_updater_stop(ov);
+}
+
+static void _on_hide(void *data, Evas *e __UNUSED__,
+                       Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+       Overview *ov = data;
+       DBG("Overview became hidden");
+       _overview_time_updater_stop(ov);
+}
+
+static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__,
+                               const char *part)
+{
+       Message_Info *m_info = data;
+
+       if (strncmp(part, "elm.text.", strlen("elm.text.")))
+               return NULL;
+       part += strlen("elm.text.");
+
+       if (strcmp(part, "name") == 0) {
+               Contact_Info *c_info = gui_contact_search(m_info->sender, NULL);
+
+               if (!c_info)
+                       return strdup(m_info->sender);
+               else
+                       return strdup(contact_info_full_name_get(c_info));
+       }
+
+       if (strcmp(part, "content") == 0)
+               return elm_entry_utf8_to_markup(m_info->last_msg);
+
+       if (strcmp(part, "time") == 0) {
+               time_t time_msg = m_info->time;
+               return date_short_format(time_msg);
+       }
+
+       ERR("Unexpected text part: %s", part);
+       return NULL;
+}
+
+static void _on_more_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
+                               const char *emission __UNUSED__,
+                               const char *source __UNUSED__)
+{
+       DBG("TODO - ON MORE CLICKED");
+}
+
+static void _on_del_clicked(void *data, Evas_Object *obj __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       Message_Info *m_info = data;
+       _message_info_del(m_info);
+}
+
+static Evas_Object *_item_content_get(void *data, Evas_Object *obj,
+                               const char *part)
+{
+       Evas_Object *btn = NULL;
+       Message_Info *msg = data;
+
+       if (strncmp(part, "elm.swallow.", strlen("elm.swallow.")))
+               return NULL;
+       part += strlen("elm.swallow.");
+
+       if (strcmp(part, "more") == 0) {
+               /* We can use the same button here */
+               btn = layout_add(obj, "history/img");
+               EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
+               elm_object_signal_callback_add(btn, "clicked,more", "gui",
+                                               _on_more_clicked, msg);
+       } else if (strcmp(part, "delete") == 0) {
+               btn = elm_button_add(obj);
+               EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
+               elm_object_style_set(btn, "history-delete");
+               elm_object_text_set(btn, "delete");
+               evas_object_smart_callback_add(btn, "clicked", _on_del_clicked,
+                                               msg);
+               evas_object_propagate_events_set(btn, EINA_FALSE);
+       }
+       else
+               ERR("unknown content part '%s'", part);
+
+       return btn;
+}
+
+static void _on_list_slide_enter(void *data __UNUSED__,
+                                       Evas_Object *obj,
+                                       void *event_info)
+{
+       Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
+       DBG("cancel decorated item=%p", it);
+       if (it)
+               elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
+
+       it = event_info;
+       EINA_SAFETY_ON_NULL_RETURN(it);
+       DBG("it=%p", it);
+       elm_genlist_item_decorate_mode_set(it, "slide", EINA_TRUE);
+}
+
+static void _on_list_slide_cancel(void *data __UNUSED__,
+                                       Evas_Object *obj,
+                                       void *event_info __UNUSED__)
+{
+       Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
+       DBG("it=%p", it);
+       if (it)
+               elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
+}
+
+void _overview_messages_clear(Overview *ov)
+{
+       Message_Info *m_info;
+       Eina_List *l, *l_next;
+
+       EINA_LIST_FOREACH_SAFE(ov->messages->list, l, l_next, m_info)
+               _message_info_del(m_info);
+}
+
+static void _on_layout_clicked(void *data, Evas_Object *o,
+                       const char *emission, const char *source __UNUSED__)
+{
+       Overview *ov = data;
+       DBG("signal: %s", emission);
+
+       EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
+       emission += strlen("clicked,");
+
+       if (strcmp(emission, "edit") == 0) {
+               elm_object_signal_emit(o, "toggle,on,edit", "gui");
+               elm_genlist_decorate_mode_set(ov->genlist, EINA_TRUE);
+       } else if (strcmp(emission, "compose") == 0) {
+               elm_object_signal_emit(o, "toggle,on,compose", "gui");
+               elm_object_signal_emit(o, "toggle,off,view", "gui");
+               gui_compose_enter();
+               elm_object_signal_emit(o, "toggle,off,compose", "gui");
+               elm_object_signal_emit(o, "toggle,on,view", "gui");
+       } else if (strcmp(emission, "view") == 0) {
+               elm_object_signal_emit(o, "toggle,off,compose", "gui");
+               elm_object_signal_emit(o, "toggle,on,view", "gui");
+       } else if (strcmp(emission, "edit,done") == 0) {
+               elm_object_signal_emit(o, "toggle,off,edit", "gui");
+               elm_genlist_decorate_mode_set(ov->genlist, EINA_FALSE);
+       } else if (strcmp(emission, "clear") == 0) {
+               _overview_messages_clear(ov);
+               elm_object_signal_emit(o, "toggle,off,edit", "gui");
+       } else
+               ERR("Unkown emission: %s", emission);
+}
+
+static void _sent_sms_cb(void *data, OFono_Error error, OFono_Sent_SMS *sms)
+{
+       Overview *ov = data;
+       Message *msg;
+       OFono_Sent_SMS_State state;
+       time_t timestamp;
+       const char *dest, *message;
+
+       if (error != OFONO_ERROR_NONE) {
+               ERR("OFono error - Sending a SMS");
+               return;
+       }
+
+       state = ofono_sent_sms_state_get(sms);
+       dest = ofono_sent_sms_destination_get(sms);
+       message = ofono_sent_sms_message_get(sms);
+       msg = eina_hash_find(ov->pending_sms, sms);
+       timestamp = ofono_sent_sms_timestamp_get(sms);
+
+       DBG("SMS Sent to: %s, message: %s, time: %ld", dest, message,
+               timestamp);
+       /* New SMS */
+       if (!msg) {
+               msg = message_new(timestamp, message, EINA_TRUE, state);
+               EINA_SAFETY_ON_NULL_RETURN(msg);
+               msg->phone = eina_stringshare_add(dest);
+
+               _message_info_genlist_update(ov, timestamp, dest, message);
+       } else
+               msg->state = state;
+
+       if (state == OFONO_SENT_SMS_STATE_FAILED ||
+               state == OFONO_SENT_SMS_STATE_SENT)
+               eina_hash_del_by_key(ov->pending_sms, sms);
+       else if (state == OFONO_SENT_SMS_STATE_PENDING) {
+               msg->refcount++;
+               eina_hash_add(ov->pending_sms, sms, msg);
+               ov->p_conversations->list = eina_list_append(ov->p_conversations->list,
+                                                               msg);
+               DBG("Added to pending conversations - msg:%p - to: %s - msg: %s",
+                       msg, dest, message);
+               ov->p_conversations->dirty = EINA_TRUE;
+       }
+
+       _conversation_eet_update(ov);
+}
+
+Evas_Object *overview_add(Evas_Object *parent)
+{
+       Evas_Object *obj, *genlist;
+       Overview *ov;
+       const char *config_path;
+       int r;
+       Evas *e;
+       Elm_Genlist_Item_Class *itc;
+
+       eet_init();
+       ecore_file_init();
+
+       ov = calloc(1, sizeof(Overview));
+       EINA_SAFETY_ON_NULL_RETURN_VAL(ov, NULL);
+
+       ov->p_conversations = calloc(1, sizeof(Messages_List));
+       EINA_SAFETY_ON_NULL_GOTO(ov->p_conversations, err_conversations);
+
+       ov->layout = obj = layout_add(parent, "messages-overview");
+       EINA_SAFETY_ON_NULL_GOTO(obj, err_obj);
+
+       elm_object_signal_callback_add(obj, "clicked,*", "gui",
+                                       _on_layout_clicked, ov);
+
+       genlist = elm_genlist_add(obj);
+       EINA_SAFETY_ON_NULL_GOTO(genlist, err_genlist);
+       elm_object_style_set(genlist, "messages-overview");
+       elm_genlist_homogeneous_set(genlist, EINA_TRUE);
+
+
+#ifdef HAVE_TIZEN
+       elm_genlist_scroller_policy_set(genlist, ELM_SCROLLER_POLICY_OFF,
+                                       ELM_SCROLLER_POLICY_AUTO);
+#else
+       elm_scroller_policy_set(genlist, ELM_SCROLLER_POLICY_OFF,
+                               ELM_SCROLLER_POLICY_AUTO);
+#endif
+
+       itc = elm_genlist_item_class_new();
+       EINA_SAFETY_ON_NULL_GOTO(itc, err_itc);
+       itc->item_style = "messages-overview";
+       itc->func.text_get = _item_label_get;
+       itc->func.content_get = _item_content_get;
+       itc->func.state_get = NULL;
+       itc->func.del = NULL;
+       itc->decorate_all_item_style = "messages-overview-delete";
+       itc->decorate_item_style = "messages-overview-delete";
+       ov->genlist = genlist;
+       ov->itc = itc;
+
+       evas_object_smart_callback_add(genlist, "drag,start,right",
+                                       _on_list_slide_enter, ov);
+       evas_object_smart_callback_add(genlist, "drag,start,left",
+                                       _on_list_slide_cancel, ov);
+       evas_object_smart_callback_add(genlist, "drag,start,down",
+                                       _on_list_slide_cancel, ov);
+       evas_object_smart_callback_add(genlist, "drag,start,up",
+                                       _on_list_slide_cancel, ov);
+
+       elm_object_part_content_set(obj, "elm.swallow.genlist", genlist);
+
+       evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
+                                       ov);
+       evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide,
+                                       ov);
+       evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show,
+                                       ov);
+
+       e = evas_object_evas_get(obj);
+       evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_OUT,
+                               _on_win_focus_out, ov);
+       evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_IN,
+                               _on_win_focus_in, ov);
+
+       evas_object_data_set(obj, "overview.ctx", ov);
+
+       config_path = efreet_config_home_get();
+
+       r = asprintf(&ov->base_dir, "%s/%s/messages", config_path,
+                       PACKAGE_NAME);
+
+       if (r < 0)
+               goto err_base_dir;
+
+       ecore_file_mkpath(ov->base_dir);
+
+       r = asprintf(&ov->msg_path,  "%s/%s/messages/messages.eet", config_path,
+                       PACKAGE_NAME);
+
+       if (r < 0)
+               goto err_path;
+
+       r = asprintf(&ov->msg_bkp,  "%s/%s/messages/messages.eet.bkp",
+                       config_path, PACKAGE_NAME);
+
+       if (r < 0)
+               goto err_bkp;
+
+       _eet_descriptors_init(&ov->edd_msg_list, &ov->edd_msg_info,
+                               &ov->edd_msg, &ov->edd_c_msg);
+       _overview_messages_read(ov);
+
+       ov->pending_sms = eina_hash_pointer_new(EINA_FREE_CB(message_del));
+       EINA_SAFETY_ON_NULL_GOTO(ov->pending_sms, err_hash);
+
+       incoming_sms = ofono_incoming_sms_cb_add(_incoming_sms_cb, ov);
+       sent_sms = ofono_sent_sms_changed_cb_add(_sent_sms_cb, ov);
+       elm_object_signal_emit(ov->layout, "toggle,on,view", "gui");
+
+       return obj;
+
+err_hash:
+       free(ov->msg_bkp);
+err_bkp:
+       free(ov->msg_path);
+err_path:
+       free(ov->base_dir);
+err_base_dir:
+       elm_genlist_item_class_free(itc);
+err_itc:
+       evas_object_del(genlist);
+err_genlist:
+       evas_object_del(obj);
+err_obj:
+       free(ov->p_conversations);
+err_conversations:
+       free(ov);
+       ecore_file_shutdown();
+       eet_shutdown();
+       return NULL;
+}
+
+void overview_all_contact_messages_clear(Evas_Object *obj, const char *contact)
+{
+       Overview *ov;
+       Message_Info *m_info;
+
+       EINA_SAFETY_ON_NULL_RETURN(obj);
+       ov = evas_object_data_get(obj, "overview.ctx");
+       EINA_SAFETY_ON_NULL_RETURN(ov);
+
+       m_info = _message_info_search(ov, contact);
+       EINA_SAFETY_ON_NULL_RETURN(m_info);
+       _message_info_del(m_info);
+}
diff --git a/messages/overview.h b/messages/overview.h
new file mode 100644 (file)
index 0000000..cbb60bc
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _EFL_OFONO_OVERVIEW_H__
+#define _EFL_OFONO_OVERVIEW_H__ 1
+
+#include "ofono.h"
+
+typedef struct _Message Message;
+
+Evas_Object *overview_add(Evas_Object *parent);
+long long message_time_get(const Message *msg);
+const char * message_content_get(const Message *msg);
+const char * message_phone_get(const Message *msg);
+unsigned char message_outgoing_get(const Message *msg);
+unsigned char message_state_get(const Message *msg);
+void message_state_set(Message *msg, unsigned char state);
+void message_ref(Message *msg);
+
+void overview_message_from_file_delete(Evas_Object *obj, Message *msg, const char *contact);
+
+void message_del(Message *msg);
+
+void message_data_set(Message *msg, void *data);
+void *message_data_get(const Message *msg);
+
+Elm_Object_Item *message_object_item_get(const Message *msg);
+void message_object_item_set(Message *msg, Elm_Object_Item *it);
+
+void overview_genlist_update(Evas_Object *obj, Message *msg,const char *contact);
+void overview_all_contact_messages_clear(Evas_Object *obj, const char *contact);
+
+Message *message_new(time_t timestamp, const char *content,
+                       Eina_Bool outgoing, OFono_Sent_SMS_State state);
+#endif
diff --git a/tizen/message_daemon.c b/tizen/message_daemon.c
new file mode 100644 (file)
index 0000000..9c0c74c
--- /dev/null
@@ -0,0 +1,148 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Elementary.h>
+#include <appcore-efl.h>
+#include <Eina.h>
+#include <E_DBus.h>
+#include <notification.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+#include <power.h>
+#include "ofono.h"
+
+#define APP_NAME "org.tizen.message_daemon"
+
+static OFono_Callback_List_Incoming_SMS_Node *inc_sms = NULL;
+
+static char _img_path[PATH_MAX];
+
+int _log_domain = -1;
+
+#define ERR(...)      EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
+#define INF(...)      EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
+#define DBG(...)      EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
+
+static void _notification_create(const char *sender, const char *message)
+{
+       int id;
+       notification_h noti;
+       notification_error_e err;
+
+       noti = notification_new(NOTIFICATION_TYPE_NOTI,
+                               NOTIFICATION_GROUP_ID_NONE,
+                               NOTIFICATION_PRIV_ID_NONE);
+       EINA_SAFETY_ON_NULL_RETURN(noti);
+
+       err = notification_set_text(noti, NOTIFICATION_TEXT_TYPE_TITLE,
+                                       sender, NULL,
+                                       NOTIFICATION_VARIABLE_TYPE_NONE);
+
+       if (err != NOTIFICATION_ERROR_NONE)
+               ERR("Could not set the title");
+
+       err = notification_set_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT,
+                                       message, NULL,
+                                       NOTIFICATION_VARIABLE_TYPE_NONE);
+
+       if (err != NOTIFICATION_ERROR_NONE)
+               ERR("Could not set the body");
+
+       err = notification_set_image(noti, NOTIFICATION_IMAGE_TYPE_ICON, _img_path);
+
+       if (err != NOTIFICATION_ERROR_NONE)
+               ERR("Could not set the image");
+
+       err = notification_insert(noti, &id);
+
+       if (err != NOTIFICATION_ERROR_NONE)
+               ERR("Could not show the notification");
+
+       notification_free(noti);
+}
+
+static Eina_Bool _phone_locked(void)
+{
+       int lock;
+       if (vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock) == -1)
+               return EINA_FALSE;
+
+       if (lock == VCONFKEY_IDLE_LOCK)
+               return EINA_TRUE;
+
+       return EINA_FALSE;
+}
+
+static void _inc_sms_cb(void *data __UNUSED__, unsigned int sms_class,
+                       time_t timestamp __UNUSED__, const char *sender,
+                       const char *message)
+{
+       if (sms_class != 1)
+               return;
+
+       if (_phone_locked())
+               power_wakeup();
+
+       _notification_create(sender, message);
+}
+
+static int _create(void *data __UNUSED__)
+{
+       if (!ofono_init())
+               return -1;
+
+       inc_sms = ofono_incoming_sms_cb_add(_inc_sms_cb, NULL);
+
+       elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
+       /* TODO SET IMAGE */
+       snprintf(_img_path, sizeof(_img_path), "%s/img",
+                       elm_app_data_dir_get());
+       return 0;
+}
+
+static int _reset(bundle *b __UNUSED__, void *data __UNUSED__)
+{
+       return 0;
+}
+
+static int _resume(void *data __UNUSED__)
+{
+       return 0;
+}
+
+static int _pause(void *data __UNUSED__)
+{
+       return 0;
+}
+
+static int _terminate(void *data __UNUSED__)
+{
+       ofono_incoming_sms_cb_del(inc_sms);
+       ofono_shutdown();
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int r = EXIT_FAILURE;
+       struct appcore_ops ops = {
+               .create = _create,
+               .resume = _resume,
+               .reset = _reset,
+               .pause = _pause,
+               .terminate = _terminate,
+       };
+       ops.data = NULL;
+
+       eina_init();
+       e_dbus_init();
+
+       _log_domain = eina_log_domain_register("answer_daemon", NULL);
+
+       r = appcore_efl_main(APP_NAME, &argc, &argv, &ops);
+
+       eina_shutdown();
+       e_dbus_shutdown();
+
+       return r;
+}
index 53fdf24..1b71a64 100644 (file)
@@ -13,6 +13,8 @@ const char *contact_info_full_name_get(const Contact_Info *c);
 const char *contact_info_first_name_get(const Contact_Info *c);
 const char *contact_info_last_name_get(const Contact_Info *c);
 
+Eina_List *contact_info_all_numbers_get(const Contact_Info *c);
+
 const char *contact_info_detail_get(const Contact_Info *c, const char *type);
 
 const char *contact_info_number_check(const Contact_Info *c, const char *number);
@@ -32,4 +34,11 @@ void contact_info_on_del_callback_add(Contact_Info *c, void (*cb)(void *data, co
 void contact_info_on_del_callback_del(Contact_Info *c, void (*cb)(void *data, const Contact_Info *c), const void *data);
 void contact_info_del(Contact_Info *c);
 
+typedef struct _Contact_Partial_Match Contact_Partial_Match;
+Eina_List *contact_partial_match_search(Evas_Object *obj, const char *query);
+void contact_partial_match_search_free(Eina_List *results);
+const char *contact_partial_match_type_get(const Contact_Partial_Match *pm);
+const Contact_Info *contact_partial_match_info_get(const Contact_Partial_Match *pm);
+Eina_Bool contact_partial_match_name_match_get(const Contact_Partial_Match *pm);
+
 #endif
index 81a3bf5..c8f88e9 100644 (file)
@@ -33,6 +33,11 @@ typedef struct  _Contact_Number {
        char number[];
 } Contact_Number;
 
+typedef struct _Contact_Name_Search {
+       const char *name;
+       Contact_Info *c_info;
+} Contact_Name_Search;
+
 typedef struct _Contact_Number_Entry {
        Eina_List *contacts;
        char number[];
@@ -68,6 +73,22 @@ typedef struct _Contact_Info_On_Changed_Ctx {
        Eina_Bool deleted;
 } Contact_Info_On_Changed_Ctx;
 
+struct _Contact_Partial_Match
+{
+       const Contact_Info *info;
+       const char *type;
+       Eina_Bool name_match : 1;
+};
+
+typedef struct _Partial_Match_Search
+{
+       Eina_List *matches;
+       const Contacts *contacts;
+} Partial_Match_Search;
+
+
+static void _contact_number_entry_add(const char *number, Contact_Info *c_info);
+
 static const char *phone_type_get(contact_number_h number);
 static void _contact_info_free(Contact_Info *c_info);
 
@@ -75,6 +96,230 @@ static void _contact_number_add(char *number,
                                Contact_Info *c_info,
                                contact_number_h number_h);
 
+const char *contact_info_number_check(const Contact_Info *c,
+                                       const char *number);
+
+static void _partial_match_add(Eina_List **p_list, const char *type,
+                               const Contact_Info *c_info,
+                               Eina_Bool name_match)
+{
+       Contact_Partial_Match *pm = malloc(sizeof(Contact_Partial_Match));
+       EINA_SAFETY_ON_NULL_RETURN(pm);
+       pm->info = c_info;
+       pm->type = type;
+       pm->name_match = name_match;
+       *p_list = eina_list_append(*p_list, pm);
+}
+
+static void _partial_number_match_add(Eina_List **p_list, const char *type,
+                                       const Contact_Info *c_info)
+{
+       _partial_match_add(p_list, type, c_info, EINA_FALSE);
+}
+
+static bool _number_partial_search(contact_query_number_s *query, void *data)
+{
+       Partial_Match_Search *pm_search = data;
+       const Contacts *contacts = pm_search->contacts;
+       char *n;
+       contact_h tizen_c;
+       const char *type;
+       contact_number_iterator_h it;
+       contact_number_h number_h;
+       Contact_Info *c_info;
+       Contact_Number *cn;
+
+       c_info = eina_hash_find(contacts->hash_ids, &query->contact_db_id);
+
+       if (c_info)
+               goto exit;
+
+       c_info = calloc(1, sizeof(Contact_Info));
+       EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, true);
+       c_info->first_name = eina_stringshare_add(query->first_name);
+       c_info->last_name = eina_stringshare_add(query->last_name);
+       c_info->picture = eina_stringshare_add(query->contact_image_path);
+       c_info->id = query->contact_db_id;
+       if (contact_get_from_db(c_info->id, &tizen_c) != CONTACTS_ERROR_NONE)
+               return true;
+
+       if (contact_get_number_iterator(tizen_c, &it) !=
+               CONTACTS_ERROR_NONE)
+               return true;
+
+       while (contact_number_iterator_has_next(it)) {
+               if (contact_number_iterator_next(&it, &number_h) !=
+                       CONTACTS_ERROR_NONE)
+                       continue;
+               if (contact_number_get_number(number_h, &n) !=
+                       CONTACTS_ERROR_NONE)
+                       continue;
+               _contact_number_add(n, c_info, number_h);
+               free(n);
+       }
+       contact_destroy(tizen_c);
+
+       /* New contact */
+       c_info->contacts = (Contacts *)contacts;
+       eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
+       EINA_INLIST_FOREACH(c_info->numbers, cn)
+               _contact_number_entry_add(cn->number, c_info);
+
+exit:
+       type = contact_info_number_check(c_info, query->phone_number);
+       _partial_number_match_add(&pm_search->matches, type,
+                                       c_info);
+       return true;
+
+}
+
+static bool _name_partial_search(contact_query_name_s *query, void *data)
+{
+       Partial_Match_Search *pm_search = data;
+       const Contacts *contacts = pm_search->contacts;
+       char *n;
+       contact_h tizen_c;
+       contact_number_iterator_h it;
+       contact_number_h number_h;
+       Contact_Info *c_info;
+       Contact_Number *cn;
+       Eina_Bool c_info_new = EINA_FALSE;
+
+
+       c_info = eina_hash_find(contacts->hash_ids, &query->contact_db_id);
+
+       if (c_info)
+               goto exit;
+
+       c_info = calloc(1, sizeof(Contact_Info));
+       EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, true);
+       c_info->first_name = eina_stringshare_add(query->first_name);
+       c_info->last_name = eina_stringshare_add(query->last_name);
+       c_info->picture = eina_stringshare_add(query->contact_image_path);
+       c_info->id = query->contact_db_id;
+       if (contact_get_from_db(c_info->id, &tizen_c) != CONTACTS_ERROR_NONE)
+               return true;
+
+       if (contact_get_number_iterator(tizen_c, &it) !=
+               CONTACTS_ERROR_NONE)
+               return true;
+
+       while (contact_number_iterator_has_next(it)) {
+               if (contact_number_iterator_next(&it, &number_h) !=
+                       CONTACTS_ERROR_NONE)
+                       continue;
+               if (contact_number_get_number(number_h, &n) !=
+                       CONTACTS_ERROR_NONE)
+                       continue;
+               _contact_number_add(n, c_info, number_h);
+               free(n);
+       }
+       contact_destroy(tizen_c);
+
+       /* New contact */
+       c_info->contacts = (Contacts *)contacts;
+       eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
+       c_info_new = EINA_TRUE;
+exit:
+       EINA_INLIST_FOREACH(c_info->numbers, cn) {
+               if (c_info_new)
+                       _contact_number_entry_add(cn->number, c_info);
+               _partial_match_add(&pm_search->matches, cn->type, c_info,
+                                       EINA_TRUE);
+       }
+       return true;
+}
+
+Eina_List *contact_partial_match_search(Evas_Object *obj, const char *query)
+{
+
+       const Contacts *contacts;
+       int i, j;
+       Eina_Bool name_search = EINA_FALSE;
+       char *query_number;
+       Partial_Match_Search pm_search;
+
+       EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(query, NULL);
+       contacts = evas_object_data_get(obj, "contacts.ctx");
+       EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
+
+       if (!contacts->contacts_on)
+               return NULL;
+
+       /* Check if it is numeric */
+       query_number = alloca(strlen(query) + 1);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(query_number, NULL);
+       for (i = 0, j = 0; query[i] != '\0'; i++) {
+               if (isalpha(query[i])) {
+                       name_search = EINA_TRUE;
+                       break;
+               } else if (isdigit(query[i]))
+                       query_number[j++] = query[i];
+       }
+
+       pm_search.contacts = contacts;
+       pm_search.matches = NULL;
+
+       if (name_search) {
+               if (contact_query_contact_by_name(_name_partial_search, query,
+                                                       &pm_search) < 0) {
+                       ERR("Could not search in contacts DB the name: %s",
+                               query);
+                       return NULL;
+               }
+       } else {
+               query_number[j] = '\0';
+               if (contact_query_contact_by_number(_number_partial_search,
+                                                       query,
+                                                       &pm_search) < 0) {
+                       ERR("Could not search in contacts DB the number: %s",
+                               query);
+                       return NULL;
+               }
+       }
+
+       return pm_search.matches;
+}
+
+void contact_partial_match_search_free(Eina_List *results)
+{
+       Contact_Partial_Match *pm;
+       EINA_LIST_FREE(results, pm)
+               free(pm);
+}
+
+const char *contact_partial_match_type_get(const Contact_Partial_Match *pm)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
+       return pm->type;
+}
+
+const Contact_Info *contact_partial_match_info_get(const Contact_Partial_Match *pm)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
+       return pm->info;
+}
+
+Eina_Bool contact_partial_match_name_match_get(const Contact_Partial_Match *pm)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(pm, EINA_FALSE);
+       return pm->name_match;
+}
+
+Eina_List *contact_info_all_numbers_get(const Contact_Info *c)
+{
+       Eina_List *l = NULL;
+       Contact_Number *cn;
+
+       EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+
+       EINA_INLIST_FOREACH(c->numbers, cn)
+               l = eina_list_append(l, cn->number);
+
+       return l;
+}
+
 static void _contact_number_entry_add(const char *number,
                                        Contact_Info *c_info)
 {
index 3dd14b9..386f1d0 100644 (file)
@@ -4,6 +4,7 @@
 #include <Elementary.h>
 #include <Eet.h>
 #include <Eina.h>
+#include <string.h>
 
 #include "log.h"
 #include "ofono.h"
@@ -65,6 +66,144 @@ typedef struct _Contact_Info_On_Changed_Ctx {
        Eina_Bool deleted;
 } Contact_Info_On_Changed_Ctx;
 
+Eina_List *contact_info_all_numbers_get(const Contact_Info *c)
+{
+       Eina_List *l = NULL;
+
+       EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+
+       if (c->mobile)
+               l = eina_list_append(l, c->mobile);
+       if (c->work)
+               l = eina_list_append(l, c->work);
+       if (c->home)
+               l = eina_list_append(l, c->home);
+
+       return l;
+}
+
+static Eina_Bool _number_match(const char *n1, const char *n2)
+{
+       if (eina_str_has_suffix(n1, n2))
+               return EINA_TRUE;
+
+       return EINA_FALSE;
+}
+
+struct _Contact_Partial_Match
+{
+       const Contact_Info *info;
+       const char *type;
+       Eina_Bool name_match : 1;
+};
+
+static void _partial_match_add(Eina_List **p_list, const char *type,
+                               const Contact_Info *c_info,
+                               Eina_Bool name_match)
+{
+       Contact_Partial_Match *pm = malloc(sizeof(Contact_Partial_Match));
+       EINA_SAFETY_ON_NULL_RETURN(pm);
+       pm->info = c_info;
+       pm->type = type;
+       pm->name_match = name_match;
+       *p_list = eina_list_append(*p_list, pm);
+}
+
+static void _partial_name_match_add(Eina_List **p_list,
+                                       const Contact_Info *c_info)
+{
+       if (c_info->mobile)
+               _partial_match_add(p_list, "Mobile", c_info, EINA_TRUE);
+       if (c_info->work)
+               _partial_match_add(p_list, "Work", c_info, EINA_TRUE);
+       if (c_info->home)
+               _partial_match_add(p_list, "Home", c_info, EINA_TRUE);
+}
+
+static void _partial_number_match_add(Eina_List **p_list, const char *type,
+                                       const Contact_Info *c_info)
+{
+       _partial_match_add(p_list, type, c_info, EINA_FALSE);
+}
+
+Eina_List *contact_partial_match_search(Evas_Object *obj, const char *query)
+{
+       const Contact_Info *c_info;
+       const Contacts *contacts;
+       Eina_List *ret = NULL, *l;
+       int i, j;
+       Eina_Bool name_search = EINA_FALSE;
+       char *query_number;
+
+       EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(query, NULL);
+       contacts = evas_object_data_get(obj, "contacts.ctx");
+       EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
+
+       /* Check if it is numeric */
+       query_number = alloca(strlen(query) + 1);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(query_number, NULL);
+       for (i = 0, j = 0; query[i] != '\0'; i++) {
+               if (isalpha(query[i])) {
+                       name_search = EINA_TRUE;
+                       break;
+               } else if (isdigit(query[i]))
+                       query_number[j++] = query[i];
+       }
+
+       if (name_search) {
+               EINA_LIST_FOREACH(contacts->c_list->list, l, c_info) {
+                       const char *full_name;
+
+                       full_name = contact_info_full_name_get(c_info);
+                       if (strcasestr(full_name, query))
+                               _partial_name_match_add(&ret, c_info);
+               }
+       } else {
+               query_number[j] = '\0';
+               EINA_LIST_FOREACH(contacts->c_list->list, l, c_info) {
+                       if (_number_match(c_info->mobile, query_number))
+                               _partial_number_match_add(&ret, "Mobile",
+                                                               c_info);
+
+                       if (_number_match(c_info->work, query_number))
+                               _partial_number_match_add(&ret, "Work",
+                                                               c_info);
+
+                       if (_number_match(c_info->home, query_number))
+                               _partial_number_match_add(&ret, "Home",
+                                                               c_info);
+               }
+       }
+
+       return ret;
+}
+
+void contact_partial_match_search_free(Eina_List *results)
+{
+       Contact_Partial_Match *pm;
+       EINA_LIST_FREE(results, pm)
+               free(pm);
+}
+
+const char *contact_partial_match_type_get(const Contact_Partial_Match *pm)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
+       return pm->type;
+}
+
+const Contact_Info *contact_partial_match_info_get(const Contact_Partial_Match *pm)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
+       return pm->info;
+}
+
+Eina_Bool contact_partial_match_name_match_get(const Contact_Partial_Match *pm)
+{
+       EINA_SAFETY_ON_NULL_RETURN_VAL(pm, EINA_FALSE);
+       return pm->name_match;
+}
+
 Contact_Info *contact_search(Evas_Object *obj, const char *number, const char **type)
 {
        Contact_Info *c_info;
@@ -144,8 +283,8 @@ const char *contact_info_detail_get(const Contact_Info *c, const char *type)
 
 const char *contact_info_number_check(const Contact_Info *c, const char *number)
 {
-       EINA_SAFETY_ON_NULL_RETURN_VAL(c, EINA_FALSE);
-       EINA_SAFETY_ON_NULL_RETURN_VAL(number, EINA_FALSE);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(number, NULL);
 
        if (strcmp(number, c->mobile) == 0)
                return "Mobile";
index 46f4761..7b72681 100644 (file)
@@ -80,8 +80,7 @@ char *date_format(time_t date)
        else if (dt < (HOUR * 4))
                r = asprintf(&buf, "%dh ago", (int)dt/3600);
        else if (dt <= DAY) {
-               struct tm *f_time = gmtime(&date);
-               EINA_SAFETY_ON_NULL_GOTO(f_time, err_gmtime);
+               struct tm *f_time = localtime(&date);
                r = asprintf(&buf,  "%02d:%02d", f_time->tm_hour,
                                f_time->tm_min);
        } else if (dt < WEEK) {
@@ -100,9 +99,35 @@ char *date_format(time_t date)
                buf = strdup("");
 
        return buf;
+}
+
+char *date_short_format(time_t date)
+{
+       time_t now = time(NULL);
+       double dt = difftime(now, date);
+       char *buf;
+       int r;
 
-err_gmtime:
-       return strdup("");
+       if (dt <= DAY) {
+               struct tm *f_time = localtime(&date);
+               r = asprintf(&buf,  "%02d:%02d", f_time->tm_hour,
+                               f_time->tm_min);
+       } else if (dt < WEEK) {
+               char tmp[256];
+               struct tm *tm = localtime(&date);
+               strftime(tmp, sizeof(tmp), "%A", tm);
+               r = asprintf(&buf, "%s", tmp);
+       } else {
+               char tmp[256];
+               struct tm *tm = localtime(&date);
+               strftime(tmp, sizeof(tmp), "%x", tm);
+               r = asprintf(&buf, "%s", tmp);
+       }
+
+       if (r < 0)
+               buf = strdup("");
+
+       return buf;
 }
 
 Evas_Object *picture_icon_get(Evas_Object *parent, const char *picture)
index e5d60fe..246dbe6 100644 (file)
@@ -11,6 +11,7 @@
 char *phone_format(const char *number);
 
 char *date_format(time_t date);
+char *date_short_format(time_t date);
 
 Evas_Object *picture_icon_get(Evas_Object *parent, const char *picture);