full messages implementation, squashed in a single commit.
messages/main.c \
messages/rc.c \
messages/rc.h \
+ messages/overview.c \
+ messages/overview.h \
messages/gui.c \
messages/gui.h \
messages/compose.c \
if HAVE_TIZEN
bin_PROGRAMS += \
+ tizen/message_daemon \
tizen/dialer_open \
tizen/dialer_daemon
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' $< > $@
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 \
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 \
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 \
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.
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])
utilX
aul
appsvc
+ notification
],
[have_tizen="yes"],
[have_tizen="no"])
#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"
#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"
#include "includes/messages.edc"
#include "includes/compose.edc"
-
+#include "includes/messages-overview.edc"
+#include "includes/messages-overview-list.edc"
}
*
* 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;
}
}
}
}
}
- }
-}
+
+ 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";
+ }
+ }
+}
+
+
--- /dev/null
+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";
+ }
+ }
+ }
+}
--- /dev/null
+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";
+ }
+ }
+}
*
*/
+ images {
+ image: "ico_edit.png" COMP;
+ }
+
parts {
part {
name: "bg";
}
}
}
+
+ part {
+ name: "elm.swallow.overview";
+ type: SWALLOW;
+ description {
+ state: "default" 0.0;
+ rel1 {
+ to_y: "notification.bar";
+ relative: 0.0 1.0;
+ }
+ }
+ }
}
}
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;
}
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;
#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);
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;
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");
+}
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
#include "compose.h"
#include "util.h"
#include "simple-popup.h"
+#include "contacts-ofono-efl.h"
#ifdef HAVE_TIZEN
#include <appcore-efl.h>
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);
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 */
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");
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);
#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);
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
--- /dev/null
+#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);
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+}
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);
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
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[];
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);
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)
{
#include <Elementary.h>
#include <Eet.h>
#include <Eina.h>
+#include <string.h>
#include "log.h"
#include "ofono.h"
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;
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";
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) {
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)
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);