TizenRefApp-8196 Implement controller for input of recipients 20/120320/2
authorDenis Dolzhenko <d.dolzhenko@samsung.com>
Wed, 22 Mar 2017 09:05:31 +0000 (11:05 +0200)
committerDenis Dolzhenko <d.dolzhenko@samsung.com>
Wed, 22 Mar 2017 09:17:06 +0000 (11:17 +0200)
+ Update Contact model

Change-Id: I567a916b6967f673c637f97151ff17fbaebe2da7
Signed-off-by: Denis Dolzhenko <d.dolzhenko@samsung.com>
22 files changed:
inc/Resource.h
res/edje/images.edc
src/Common/ContactManager/inc/ContactAddress.h
src/Common/ContactManager/inc/ContactMyProfileEmail.h
src/Common/ContactManager/inc/ContactMyProfileNumber.h
src/Common/ContactManager/inc/ContactPersonEmail.h
src/Common/ContactManager/inc/ContactPersonNumber.h
src/Common/ContactManager/inc/ContactPersonPhoneLog.h
src/Common/ContactManager/inc/ContactRecord.h
src/Common/ContactManager/src/ContactRecord.cpp
src/Common/Controller/inc/InputFrame.h
src/Common/Controller/src/InputFrame.cpp
src/Common/MsgEngine/inc/MsgUtils.h
src/Common/MsgEngine/src/MsgUtils.cpp
src/Common/View/inc/Entry.h
src/Common/View/inc/PopupManager.h
src/Common/View/inc/SearchBar.h
src/Common/View/src/Entry.cpp
src/Common/View/src/PopupManager.cpp
src/Composer/Controller/inc/RecipInputFrame.h
src/Composer/Controller/src/RecipFrame.cpp
src/Composer/Controller/src/RecipInputFrame.cpp

index 0ef78721705cc1d25b71e70e311a6e88d9fcb690..a411e55138369fd270bee27f870a32b1ddcf4a51 100644 (file)
@@ -25,6 +25,8 @@
 #define NEW_MSG_MORE_ICON                MORE_OPTION_ICON"/b_more_option_ic_compose.png"
 #define DELETEG_MORE_ICON                MORE_OPTION_ICON"/b_more_option_ic_delete.png"
 
+#define FAIL_ICON                        "sent_fail_icon.png"
+
 // Images(res):
 #define THUMB_CONTACT_IMG_PATH           IMAGE_PATH"/messages_list_thumb_image_single.png"
 #define THUMB_GROUP_IMG_PATH             IMAGE_PATH"/messages_list_thumb_image_multi.png"
index 61869a7b08a68332b90f8a5321fdea1ebee3bd1b..392fc31b6fc2b0640fb8547b95bee6de3344e666 100755 (executable)
@@ -1,6 +1,6 @@
 #include "macros.inl"
 
-#define RESOURCE_IMAGE( FILE_NAME ) \
+#define RES_IMAGE( FILE_NAME ) \
    group { \
       name: FILE_NAME; \
       images.image: FILE_NAME RAW; \
@@ -18,6 +18,7 @@
 
 collections {
     BASE_SCALE;
-    RESOURCE_IMAGE("More_option_icon/b_more_option_ic_compose.png");
-    RESOURCE_IMAGE("More_option_icon/b_more_option_ic_delete.png");
+    RES_IMAGE("More_option_icon/b_more_option_ic_compose.png");
+    RES_IMAGE("More_option_icon/b_more_option_ic_delete.png");
+    RES_IMAGE("sent_fail_icon.png");
 }
index f0ff88e772eaeff0b8795ddd83fcb5c9d5b4c2e0..b53a612573ac110c2af901ed9548119170815944 100644 (file)
 #define __ContactAddress_h__
 
 #include "MsgUtils.h"
+#include "ContactRecord.h"
 
 namespace Msg {
     class ContactAddress;
     typedef std::shared_ptr<ContactAddress> ContactAddressRef;
 
-    class ContactAddress {
+    class ContactAddress
+        : public ContactRecord {
+
         public:
             enum AddressType {
                 EmailType,
@@ -36,6 +39,8 @@ namespace Msg {
             };
 
         public:
+            ContactAddress();
+            ContactAddress(bool release, contacts_record_h record = nullptr);
             virtual ~ContactAddress() {};
             virtual AddressType getAddressType() const = 0;
             virtual OwnerType getOwnerType() const = 0;
@@ -45,6 +50,15 @@ namespace Msg {
             virtual std::string getThumbnailPath() const = 0;
     };
 
+    inline ContactAddress::ContactAddress()
+        : ContactRecord()
+    {
+    }
+
+    inline ContactAddress::ContactAddress(bool release, contacts_record_h record)
+        : ContactRecord(release, record)
+    {
+    }
 }
 
 #endif /* __ContactAddress_h__ */
index 04f6c1f25a0db4d8d54e9ed1d3c5ca9aa08fa91b..9b2366efdc8a9f9107d5407dba600d42a1fbcba2 100644 (file)
@@ -26,8 +26,7 @@ namespace Msg {
     typedef std::shared_ptr<ContactMyProfileEmail> ContactMyProfileEmailRef;
 
     class ContactMyProfileEmail
-        : public ContactAddress
-        , public ContactRecord {
+        : public ContactAddress {
         public:
             ContactMyProfileEmail(bool release, const ContactMyProfile &myProfile, contacts_record_h record = nullptr);
             static const char *getUri();
@@ -40,6 +39,7 @@ namespace Msg {
             std::string getDispName() const override;
             std::string getAddress() const override;
             std::string getThumbnailPath() const override;
+            ContactRecordRef clone() const override;
 
         private:
             int m_MyProfileId;
@@ -48,7 +48,7 @@ namespace Msg {
     };
 
     inline ContactMyProfileEmail::ContactMyProfileEmail(bool release, const ContactMyProfile &myProfile, contacts_record_h record)
-        : ContactRecord(release, record)
+        : ContactAddress(release, record)
         , m_MyProfileId(myProfile.getId())
         , m_ThumbnailPath(myProfile.getThumbnailPath())
         , m_DispName(myProfile.getDispName())
@@ -94,6 +94,11 @@ namespace Msg {
     {
         return EmailType;
     }
+
+    inline ContactRecordRef ContactMyProfileEmail::clone() const
+    {
+        return cloneInternal<ContactMyProfileEmail>();
+    }
 }
 
 
index 2ca002c8e685ed078d739f401430c8232f59c329..b9ac7849634400b673281ede9ea42e49eb65ead9 100644 (file)
@@ -26,8 +26,8 @@ namespace Msg {
     typedef std::shared_ptr<ContactMyProfileNumber> ContactMyProfileNumberRef;
 
     class ContactMyProfileNumber
-        : public ContactAddress
-        , public ContactRecord {
+        : public ContactAddress {
+
         public:
             ContactMyProfileNumber(bool release, const ContactMyProfile &myProfile, contacts_record_h record = nullptr);
             static const char *getUri();
@@ -40,6 +40,7 @@ namespace Msg {
             std::string getDispName() const override;
             std::string getAddress() const override;
             std::string getThumbnailPath() const override;
+            ContactRecordRef clone() const override;
 
         private:
             int m_MyProfileId;
@@ -48,7 +49,7 @@ namespace Msg {
     };
 
     inline ContactMyProfileNumber::ContactMyProfileNumber(bool release, const ContactMyProfile &myProfile, contacts_record_h record)
-        : ContactRecord(release, record)
+        : ContactAddress(release, record)
         , m_MyProfileId(myProfile.getId())
         , m_ThumbnailPath(myProfile.getThumbnailPath())
         , m_DispName(myProfile.getDispName())
@@ -94,6 +95,11 @@ namespace Msg {
     {
         return NumberType;
     }
+
+    inline ContactRecordRef ContactMyProfileNumber::clone() const
+    {
+        return cloneInternal<ContactMyProfileNumber>();
+    }
 }
 
 
index 21ab05989465cb7f5cec6b0c6009714340cdc68a..0a7bda46295cc1deed364d05a5cf79e926470931 100644 (file)
@@ -25,8 +25,8 @@ namespace Msg {
     typedef std::shared_ptr<ContactPersonEmail> ContactPersonEmailRef;
 
     class ContactPersonEmail
-        : public ContactAddress
-        , public ContactRecord {
+        : public ContactAddress {
+
         public:
             ContactPersonEmail(bool release, contacts_record_h record = nullptr);
             static const char *getUri();
@@ -39,10 +39,11 @@ namespace Msg {
             std::string getDispName() const override;
             std::string getAddress() const override;
             std::string getThumbnailPath() const override;
+            ContactRecordRef clone() const override;
     };
 
     inline ContactPersonEmail::ContactPersonEmail(bool release, contacts_record_h record)
-        : ContactRecord(release, record)
+        : ContactAddress(release, record)
     {
     }
 
@@ -85,6 +86,11 @@ namespace Msg {
     {
         return EmailType;
     }
+
+    inline ContactRecordRef ContactPersonEmail::clone() const
+    {
+        return cloneInternal<ContactPersonEmail>();
+    }
 }
 
 
index e9e5ba5905a10cde834cced24eabf2941bb94a38..950021d7911e28ba5844210f352665d36e839c11 100644 (file)
@@ -25,8 +25,8 @@ namespace Msg {
     typedef std::shared_ptr<ContactPersonNumber> ContactPersonNumberRef;
 
     class ContactPersonNumber
-        : public ContactAddress
-        , public ContactRecord {
+        : public ContactAddress {
+
         public:
             ContactPersonNumber(bool release, contacts_record_h record = nullptr);
             static const char *getUri();
@@ -39,10 +39,11 @@ namespace Msg {
             std::string getDispName() const override;
             std::string getAddress() const override;
             std::string getThumbnailPath() const override;
+            ContactRecordRef clone() const override;
     };
 
     inline ContactPersonNumber::ContactPersonNumber(bool release, contacts_record_h record)
-        : ContactRecord(release, record)
+        : ContactAddress(release, record)
     {
     }
 
@@ -85,6 +86,11 @@ namespace Msg {
     {
         return NumberType;
     }
+
+    inline ContactRecordRef ContactPersonNumber::clone() const
+    {
+        return cloneInternal<ContactPersonNumber>();
+    }
 }
 
 
index 524fcbc8ea86ee461b9eff8ebc18a0962e470744..a6932cb465460767f377ff7d06488877722f318b 100644 (file)
@@ -32,6 +32,7 @@ namespace Msg {
             int getPersonId() const;
             std::string getAddress() const;
             std::string getDispName() const;
+            ContactRecordRef clone() const override;
     };
 
     inline ContactPersonPhoneLog::ContactPersonPhoneLog(bool release, contacts_record_h record)
@@ -63,6 +64,11 @@ namespace Msg {
     {
         return _contacts_person_phone_log._uri;
     }
+
+    inline ContactRecordRef ContactPersonPhoneLog::clone() const
+    {
+        return cloneInternal<ContactPersonPhoneLog>();
+    }
 }
 
 
index c8bcaf0429537b81c9d68d8afa560e183386e056..31852b2d25f19dfc3f129eef006cce7f5d293bd2 100644 (file)
@@ -27,6 +27,7 @@ namespace Msg {
 
     class ContactRecord {
         public:
+            ContactRecord();
             ContactRecord(bool release, contacts_record_h record = nullptr);
             virtual ~ContactRecord();
             ContactRecord(ContactRecord&) = delete;
@@ -34,8 +35,14 @@ namespace Msg {
 
             void set(contacts_record_h record);
             contacts_record_h getRecord() const;
+            bool isValid() const;
+            virtual ContactRecordRef clone() const;
 
         protected:
+
+            template <typename T>
+            std::shared_ptr<T> cloneInternal() const;
+
             std::string getStr(unsigned propertyId) const;
             int getInt(unsigned propertyId) const;
             int getChildCount(unsigned propertyId) const;
@@ -108,6 +115,19 @@ namespace Msg {
     {
         return getInt(m_Record, propertyId);
     }
+
+    inline bool ContactRecord::isValid() const
+    {
+        return m_Record != nullptr;
+    }
+
+    template <typename T>
+    std::shared_ptr<T> ContactRecord::cloneInternal() const
+    {
+        contacts_record_h clonedRec = {};
+        contacts_record_clone(m_Record, &clonedRec);
+        return std::make_shared<T>(true, clonedRec);
+    }
 }
 
 #endif /* __ContactRecord_h__ */
index 8645af74c6951a77ae3a9799951cc9b0d614954e..5641c541982fa0ed90b522d93303e2d48c2bb1b8 100644 (file)
@@ -32,3 +32,8 @@ ContactRecord::~ContactRecord()
         m_Record = nullptr;
     }
 }
+
+ContactRecordRef ContactRecord::clone() const
+{
+    return cloneInternal<ContactRecord>();
+}
index 3905a7574318cba1ed29c3b90b18b663aa7ab68d..2d8bd3207840dc26068f3b025fe06a5a11739fe1 100644 (file)
@@ -29,6 +29,7 @@ namespace Msg {
             virtual ~InputFrame();
 
             Entry &getEntry();
+            const Entry &getEntry() const;
             void setPredictBar(Evas_Object *obj);
             void showPredictBar(bool value);
             InputLayout &getLayout();
@@ -38,7 +39,7 @@ namespace Msg {
             void onAttached(ViewItem &item) override;
 
         private:
-            void onHwBackButtonPreessed(Evas_Object *obj, void *event_info);
+            void onFocusChanged(Evas_Object *obj, void *event_info);
             void onInputPanelEvent(Ecore_IMF_Context *ctx, int value);
 
             void prepareLayout();
index a4d132251d55b7e3cfbb1eb9d8eca80eb2b86070..06609e941337c3bd2534f8e6cad706c19ddaba63 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "InputFrame.h"
+#include "PopupManager.h"
 
 using namespace Msg;
 
@@ -44,6 +45,11 @@ Entry &InputFrame::getEntry()
     return *m_pEntry;
 }
 
+const Entry &InputFrame::getEntry() const
+{
+    return *m_pEntry;
+}
+
 void InputFrame::setPredictBar(Evas_Object *obj)
 {
     m_pLayout->setPredictBar(obj);
@@ -70,28 +76,35 @@ void InputFrame::prepareEntry()
 {
     if (!m_pEntry) {
         m_pEntry = new Entry(*m_pLayout);
-        m_pEntry->addHwButtonEvent(EEXT_CALLBACK_BACK, makeCbFirst(&InputFrame::onHwBackButtonPreessed), this);
-        m_pEntry->addInputPanelEventCb(ECORE_IMF_INPUT_PANEL_STATE_EVENT, makeCbFirst(&InputFrame::onInputPanelEvent), this);
+        m_pEntry->enabledInputPanel(false);
+        m_pEntry->setFocusAllow(true);
         m_pEntry->setSingleLine(true);
         m_pEntry->setFocus(true);
         m_pEntry->setScrollable(true);
         m_pEntry->setScrollerPolicy(ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_ON);
+
+        m_pEntry->addFocusedCb(makeCbFirst(&InputFrame::onFocusChanged), this);
+        m_pEntry->addUnfocusedCb(makeCbFirst(&InputFrame::onFocusChanged), this);
+        m_pEntry->addInputPanelEventCb(ECORE_IMF_INPUT_PANEL_STATE_EVENT, makeCbFirst(&InputFrame::onInputPanelEvent), this);
+
         m_pLayout->setEntry(*m_pEntry);
     }
 }
 
-void InputFrame::onHwBackButtonPreessed(Evas_Object *obj, void *event_info)
+void InputFrame::onFocusChanged(Evas_Object *obj, void *event_info)
 {
-    MSG_LOG("");
-    // Empty callback for back button
+    m_pEntry->showInputPanel(m_pEntry->getFocus());
 }
 
 void InputFrame::onInputPanelEvent(Ecore_IMF_Context *ctx, int value)
 {
     switch (value) {
-    case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
-        if (!isPause())
-            pop();
-        break;
+    case ECORE_IMF_INPUT_PANEL_STATE_HIDE: {
+            BasePopup *popup = App::getInst().getPopupManager().getTop();
+            if (!isPause() && !(popup && popup->isVisible()))
+                pop();
+            break;
+        }
     }
 }
+
index fc119ec5499d407b9fb7f6d208e113e5e0a1fd21..7d6b9a6e5acc4fade03abaa48fff47f1b9ec2b8c 100644 (file)
 #include <vector>
 
 namespace Msg {
-    struct TokenizedRecipients {
-        std::list<std::pair<std::string, MsgAddress::AddressType>> validResults;
-        std::string invalidResult;
-    };
+    namespace MsgUtils {
+
+            struct TokenizedRecipients {
+                std::list<std::pair<std::string, MsgAddress::AddressType>> validResults;
+                std::string invalidResult;
+            };
 
-    class MsgUtils {
-        public:
-            static TokenizedRecipients tokenizeRecipients(const std::string &inputText);
-            static bool isValidNumber(const std::string &address);
-            static bool isValidEmail(const std::string &address);
-            static bool isValidAddress(const std::string &address);
-            static MsgAddress::AddressType getAddressType(const std::string &address);
-            static std::string makeNormalizedNumber(const std::string &number);
-            static std::string makeCleanedNumber(const std::string &number);
-            static bool isMms(Message::Type type);
-            static bool isSms(Message::Type type);
-            static std::string makeKbStr(long long bytes);
+            TokenizedRecipients tokenizeRecipients(const std::string &inputText);
+            bool isValidNumber(const std::string &address);
+            bool isValidEmail(const std::string &address);
+            bool isValidAddress(const std::string &address);
+            MsgAddress::AddressType getAddressType(const std::string &address);
+            std::string makeNormalizedNumber(const std::string &number);
+            std::string makeCleanedNumber(const std::string &number);
+            bool isMms(Message::Type type);
+            bool isSms(Message::Type type);
+            std::string makeKbStr(long long bytes);
     };
 }
 
index 71fcb38d7681c2355d4139af133511d960c41f8d..719ae002a241bb592d4ec04fc65c9679a5eae8fa 100644 (file)
 #include <unistd.h>
 #include <regex>
 
-using namespace Msg;
+namespace Msg {
+namespace MsgUtils {
 
-namespace
-{
-    unsigned emailAddrLenMax = 256;
-    const char *delimiters = ",;";
-    const char *numberRegex = "\\+?([[:digit:]][ *\\(\\)-]*){2,14}[[:digit:]]$";
-    const char *emailRegex = "(([[:alnum:]_!#$%&'*+/=?`{|}~^-]+)|(^\"([[:alnum:]_!#$%&'*+/=?`{|}~^-\\(\\)<>\\[\\]:;@,. (\\\\)(\\\")])+\"))+(?:\\.(([[:alnum:]_!#$%&'*+/=?`{|}~^-]+)|(\"([[:alnum:]_!#$%&'*+/=?`{|}~^-\\(\\)<>\\[\\]:;@,. (\\\\)(\\\")])+\")))*@[[:alnum:]-]+(?:\\.[[:alnum:]-]+)*";
-}
+unsigned emailAddrLenMax = 256;
+const char *delimiters = ",;";
+const char *numberRegex = "\\+?([[:digit:]][ *\\(\\)-]*){2,14}[[:digit:]]$";
+const char *emailRegex = "(([[:alnum:]_!#$%&'*+/=?`{|}~^-]+)|(^\"([[:alnum:]_!#$%&'*+/=?`{|}~^-\\(\\)<>\\[\\]:;@,. (\\\\)(\\\")])+\"))+(?:\\.(([[:alnum:]_!#$%&'*+/=?`{|}~^-]+)|(\"([[:alnum:]_!#$%&'*+/=?`{|}~^-\\(\\)<>\\[\\]:;@,. (\\\\)(\\\")])+\")))*@[[:alnum:]-]+(?:\\.[[:alnum:]-]+)*";
 
-TokenizedRecipients MsgUtils::tokenizeRecipients(const std::string &inputText)
+TokenizedRecipients tokenizeRecipients(const std::string &inputText)
 {
     TokenizedRecipients result;
     std::string::size_type begin = inputText.find_first_not_of(delimiters);
@@ -62,7 +60,7 @@ TokenizedRecipients MsgUtils::tokenizeRecipients(const std::string &inputText)
     return result;
 }
 
-bool MsgUtils::isValidNumber(const std::string &address)
+bool isValidNumber(const std::string &address)
 {
     if (address.empty())
         return false;
@@ -71,7 +69,7 @@ bool MsgUtils::isValidNumber(const std::string &address)
     return std::regex_match(address, numTemplate);
 }
 
-bool MsgUtils::isValidEmail(const std::string &address)
+bool isValidEmail(const std::string &address)
 {
     if (address.empty() || address.length() > emailAddrLenMax)
         return false;
@@ -80,12 +78,12 @@ bool MsgUtils::isValidEmail(const std::string &address)
     return std::regex_match(address, emailTemplate);
 }
 
-bool MsgUtils::isValidAddress(const std::string &address)
+bool isValidAddress(const std::string &address)
 {
     return isValidNumber(address) || isValidEmail(address);
 }
 
-MsgAddress::AddressType MsgUtils::getAddressType(const std::string &address)
+MsgAddress::AddressType getAddressType(const std::string &address)
 {
     if (isValidNumber(address))
     {
@@ -100,7 +98,7 @@ MsgAddress::AddressType MsgUtils::getAddressType(const std::string &address)
     return MsgAddress::UnknownAddressType;
 }
 
-std::string MsgUtils::makeNormalizedNumber(const std::string &number)
+std::string makeNormalizedNumber(const std::string &number)
 {
     std::string normalizedNumber;
     for (auto symbol : number)
@@ -113,7 +111,7 @@ std::string MsgUtils::makeNormalizedNumber(const std::string &number)
     return normalizedNumber;
 }
 
-std::string MsgUtils::makeCleanedNumber(const std::string &number)
+std::string makeCleanedNumber(const std::string &number)
 {
     std::string cleanedNumber;
     for (auto symbol : number)
@@ -124,7 +122,7 @@ std::string MsgUtils::makeCleanedNumber(const std::string &number)
     return cleanedNumber;
 }
 
-bool MsgUtils::isMms(Message::Type type)
+bool isMms(Message::Type type)
 {
     switch (type)
     {
@@ -141,7 +139,7 @@ bool MsgUtils::isSms(Message::Type type)
     return type == Message::MT_SMS;
 }
 
-std::string MsgUtils::makeKbStr(long long bytes)
+std::string makeKbStr(long long bytes)
 {
     const long long kb = 1024; // Bytes in kb
     long long sizeKb = 0;
@@ -157,3 +155,5 @@ std::string MsgUtils::makeKbStr(long long bytes)
 
     return std::to_string(sizeKb) + " " + (std::string)msg("IDS_MSGF_BODY_MSGSIZE_KB");
 }
+} // MsgUtils
+} // Msg
index 5c1dde221aeee08b2df868c89b78889bf751f3fa..5054afe4ba416922fc1440a4470a96cce9d6f0d8 100644 (file)
@@ -36,16 +36,27 @@ namespace Msg {
             const char *getEntry() const;
             void setEditable(bool value);
             void enabledInputPanel(bool value);
+            void showInputPanel(bool value);
             void setScrollerPolicy(Elm_Scroller_Policy policyH, Elm_Scroller_Policy policyV);
             void setAutocapitalType(Elm_Autocapital_Type type);
             void setScrollable(bool value);
             void setSingleLine(bool value);
             void setCursorPos(int pos);
+            void setCursorPosToEnd();
             int getCursorPos() const;
             void setEditInfo(Entry &entry);
             bool isEmpty() const;
             void clear();
+            void setLimit(int charCount, int byteCount = 0);
 
+            void addMarkupFilterCb(Elm_Entry_Filter_Cb, void *data);
+            void addPreeditCb(Evas_Smart_Cb cb, void *data);
+            void addActivatedCb(Evas_Smart_Cb cb, void *data);
+            void addMaxlengthReachedCb(Evas_Smart_Cb cb, void *data);
+            void addFocusedCb(Evas_Smart_Cb cb, void *data);
+            void addUnfocusedCb(Evas_Smart_Cb cb, void *data);
+            void addChangedCb(Evas_Smart_Cb cb, void *data);
+            void addKeyDownCb(Evas_Object_Event_Cb cb, void *data);
             void addInputPanelEventCb(Ecore_IMF_Input_Panel_Event type, InputPanelEventCb cb, const void *data);
             void delInputPanelEventCb(Ecore_IMF_Input_Panel_Event type, InputPanelEventCb cb);
     };
index 37b2b2dcd963b97ec613f6bae1e341492d944078..562b22ba29304c96cc51242412c199c779e2657e 100644 (file)
@@ -49,6 +49,7 @@ namespace Msg {
             void pop(void *id = nullptr);
             void pop(BasePopup *popup);
             void push(BasePopup &popup, void *id = nullptr);
+            BasePopup *getTop() const;
 
             /**
              * @brief Process pause event
index fed9ec5365434887333d16c29b7a9cc00fbcfed4..aaec44514d2248108708cd817fa9d2177fa822a0 100644 (file)
@@ -43,8 +43,8 @@ namespace Msg {
     class ISearchBarListener {
         public:
             virtual ~ISearchBarListener() {};
-            void onButtonClicked(SearchBar &obj) {};
-            void onTextClicked(SearchBar &obj) {};
+            virtual void onButtonClicked(SearchBar &obj) {};
+            virtual void onTextClicked(SearchBar &obj) {};
     };
 }
 
index 1f2bc0856920f5a83bb954482352c8f8638b1000..9b874239970e78cf6e4d5ffb95b5067ebd1baadf 100644 (file)
@@ -44,6 +44,14 @@ void Entry::enabledInputPanel(bool value)
     elm_entry_input_panel_enabled_set(getEo(), value);
 }
 
+void Entry::showInputPanel(bool value)
+{
+    if (value)
+        elm_entry_input_panel_show(getEo());
+    else
+        elm_entry_input_panel_hide(getEo());
+}
+
 void Entry::setInputPanelReturnType(Elm_Input_Panel_Return_Key_Type retType)
 {
     elm_entry_input_panel_return_key_type_set(getEo(), retType);
@@ -89,6 +97,11 @@ void Entry::setCursorPos(int pos)
     elm_entry_cursor_pos_set(getEo(), pos);
 }
 
+void Entry::setCursorPosToEnd()
+{
+    elm_entry_cursor_end_set(getEo());
+}
+
 int Entry::getCursorPos() const
 {
     return elm_entry_cursor_pos_get(getEo());
@@ -111,16 +124,57 @@ void Entry::clear()
     View::setText(getEo(), "");
 }
 
+void Entry::setLimit(int charCount, int byteCount)
+{
+    Elm_Entry_Filter_Limit_Size limitFilter = {charCount, byteCount};
+    elm_entry_markup_filter_append(getEo(), elm_entry_filter_limit_size, &limitFilter);
+}
+
+void Entry::addKeyDownCb(Evas_Object_Event_Cb cb, void *data)
+{
+    addEventCb(EVAS_CALLBACK_KEY_DOWN, cb, data);
+}
+
+void Entry::addChangedCb(Evas_Smart_Cb cb, void *data)
+{
+    addSmartCb("changed", cb, data);
+}
+
+void Entry::addFocusedCb(Evas_Smart_Cb cb, void *data)
+{
+    addSmartCb("focused", cb, data);
+}
+
+void Entry::addUnfocusedCb(Evas_Smart_Cb cb, void *data)
+{
+    addSmartCb("unfocused", cb, data);
+}
+
+void Entry::addMaxlengthReachedCb(Evas_Smart_Cb cb, void *data)
+{
+    addSmartCb("maxlength,reached", cb, data);
+}
+
+void Entry::addActivatedCb(Evas_Smart_Cb cb, void *data)
+{
+    addSmartCb("activated", cb, data);
+}
+
+void Entry::addMarkupFilterCb(Elm_Entry_Filter_Cb cb, void *data)
+{
+    elm_entry_markup_filter_append(getEo(), cb, data);
+}
+
 void Entry::addInputPanelEventCb(Ecore_IMF_Input_Panel_Event type, InputPanelEventCb cb, const void *data)
 {
-    Ecore_IMF_Context *imf = (Ecore_IMF_Context*)elm_entry_imf_context_get(getEo());
+    auto *imf = (Ecore_IMF_Context*)elm_entry_imf_context_get(getEo());
     if (imf)
         ecore_imf_context_input_panel_event_callback_add(imf, type, cb, data);
 }
 
 void Entry::delInputPanelEventCb(Ecore_IMF_Input_Panel_Event type, InputPanelEventCb cb)
 {
-    Ecore_IMF_Context *imf = (Ecore_IMF_Context*)elm_entry_imf_context_get(getEo());
+    auto *imf = (Ecore_IMF_Context*)elm_entry_imf_context_get(getEo());
     if (imf)
         ecore_imf_context_input_panel_event_callback_del(imf, type, cb);
 }
index 7c378e26c683df37a4c2041a1dae6fd0915c15c9..0d69e3f0d81d92e7d7d9763150c6e71a43920c67 100644 (file)
@@ -69,6 +69,11 @@ void PopupManager::push(BasePopup &popup, void *id)
     }
 }
 
+BasePopup *PopupManager::getTop() const
+{
+    return m_pPopup;
+}
+
 void PopupManager::onHwBackButtonClicked(Evas_Object *obj, void *eventInfo)
 {
     pop();
index a44d946cdaca6617d309bb59e27711b5db452624..5d3fc484202d3bbfc2a5014b28583e93d18fef2c 100644 (file)
 
 #include "InputFrame.h"
 #include "SearchBar.h"
+#include "ContactAddress.h"
 
 namespace Msg {
 
     class RecipInputFrame
-        : public InputFrame {
+        : public InputFrame
+        , private ISearchBarListener {
 
         public:
-            RecipInputFrame(NaviFrameController &parent);
+            RecipInputFrame(NaviFrameController &parent, std::string recip);
             virtual ~RecipInputFrame();
 
+            std::string getAddress() const;
+
         private:
             // NaviFrameItem:
             void onAttached(ViewItem &item) override;
-            bool onRequestPop() override;
+
+            // Entry:
+            void onEntryChanged(Evas_Object *obj, void *event_info);
+            void onEntryActivated(Evas_Object *obj, void *event_info);
+            void onEntryFilter(Evas_Object *obj, char **text);
+
+            // ISearchBarListener:
+            void onButtonClicked(SearchBar &obj) override;
+            void onTextClicked(SearchBar &obj) override;
+
+            // Timer:
+            Eina_Bool onSearchTimerTick();
+
+        private:
+            template<typename ContactRec>
+            std::shared_ptr<ContactRec> search(const std::string &searchWord);
+
+            void showSearchBar(bool show);
+            void prepareEntry(std::string initText);
+            void close();
+            void reqestSearch();
+            void cancelSearch();
+            void searchButtonHandler();
 
         private:
             SearchBar *m_pSearchBar;
+            Ecore_Timer *m_pTimer;
+            std::string m_ContactAddress;
+            std::string m_DsipName;
     };
 }
 
index a270daef70e8780b3414d7b17d19b73c51226a48..8fe6bafb85ad35b4c2d528cd74b64a6485b12dfb 100644 (file)
@@ -75,7 +75,7 @@ void RecipFrame::prepareEntry()
 void RecipFrame::showInputFrame()
 {
     if (!m_pInputFrame) {
-        m_pInputFrame = new RecipInputFrame(getParent());
+        m_pInputFrame = new RecipInputFrame(getParent(), m_pRecipField->getEntry().getText());
         m_pInputFrame->setOnPopCb(makeCbLast(&RecipFrame::onInputFramePop), this);
         getParent().push(*m_pInputFrame);
     }
@@ -120,5 +120,6 @@ void RecipFrame::onContactButtonClicked(RecipFieldView &obj)
 void RecipFrame::onInputFramePop(NaviFrameItem &item)
 {
     MSG_LOG("");
+    m_pRecipField->getEntry().setText((m_pInputFrame->getAddress()));
     m_pInputFrame = nullptr;
 }
index de23df474e1fb2bac9745c0bd6b2a9fcc7bccfbb..5cb14759e09a5923859104cc4ec217d80616889e 100644 (file)
  */
 
 #include "RecipInputFrame.h"
+#include "ContactManager.h"
 #include "Logger.h"
+#include "ContactPersonPhoneLog.h"
+#include "ContactPersonNumber.h"
+#include "App.h"
+#include "TextDecorator.h"
+#include "MsgUtils.h"
+#include "ToastPopup.h"
+
+#include <Eina.h>
 
 using namespace Msg;
 
-RecipInputFrame::RecipInputFrame(NaviFrameController &parent)
+namespace {
+    const int minDigits = 3;
+    const int minCharacters = 2;
+
+    bool isDigit(const std::string &str) {
+        auto itEnd = str.end();
+        for (auto it = str.begin() ;it != itEnd; ++it) {
+            if (!isdigit(*it))
+                return false;
+        }
+        return true;
+    }
+
+    bool isSeparatorChar(char c)
+    {
+        return c == ';' || c == ',';
+    }
+
+    bool isSeparatorChar(const std::string &str)
+    {
+        return str.size() == 1 && isSeparatorChar(str[0]);
+    }
+
+    bool isPreedit(const char *str)
+    {
+        return strstr(str, "<preedit>") == str &&
+               strstr(str, "</preedit>") != nullptr;
+    }
+}
+
+RecipInputFrame::RecipInputFrame(NaviFrameController &parent, std::string recip)
     : InputFrame(parent)
     , m_pSearchBar(nullptr)
+    , m_pTimer(nullptr)
 {
-    m_pSearchBar = new SearchBar(getLayout());
-    setPredictBar(*m_pSearchBar);
-    showPredictBar(true);
+    prepareEntry(std::move(recip));
 }
 
 RecipInputFrame::~RecipInputFrame()
 {
+    cancelSearch();
+}
+
+std::string RecipInputFrame::getAddress() const
+{
+    return getEntry().getText();
+}
+
+void RecipInputFrame::showSearchBar(bool show)
+{
+    if (show && !m_pSearchBar) {
+        m_pSearchBar = new SearchBar(getLayout());
+        setPredictBar(*m_pSearchBar);
+    }
+    showPredictBar(show);
+}
+
+void RecipInputFrame::prepareEntry(std::string initText)
+{
+    getEntry().setText(std::move(initText));
+    getEntry().setCursorPosToEnd();
+    getEntry().setInputPanelReturnType(ELM_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH);
+    getEntry().addChangedCb(makeCbFirst(&RecipInputFrame::onEntryChanged), this);
+    getEntry().addActivatedCb(makeCbFirst(&RecipInputFrame::onEntryActivated), this);
+    getEntry().addMarkupFilterCb(makeCbFirst(&RecipInputFrame::onEntryFilter), this);
+}
+
+void RecipInputFrame::close()
+{
+    cancelSearch();
+    pop();
+}
+
+template<typename ContactRec>
+std::shared_ptr<ContactRec> RecipInputFrame::search(const std::string &searchWord)
+{
+    if (!searchWord.empty()) {
+        auto list = App::getInst().getContactManager().search<ContactRec>(searchWord);
+        if (list) {
+            do {
+                auto &rec = list->get();
+                if (rec.isValid() && MsgUtils::isValidAddress(rec.getAddress())) {
+                    return std::static_pointer_cast<ContactRec>(rec.clone());
+                } else {
+                    MSG_LOG("Skip invalid contact: ", rec.getAddress());
+                }
+            } while (list->next());
+         }
+    }
+    return {};
+}
+
+Eina_Bool RecipInputFrame::onSearchTimerTick()
+{
+    std::string searchWord = getEntry().getText();
+    std::string highlightWord;
+
+    int len = eina_unicode_utf8_get_len(searchWord.c_str());
+    bool isDig = isDigit(searchWord);
+
+    if ((isDig && len >= minDigits)  || (!isDig && len >= minCharacters)) {
+
+        ContactPersonNumberRef numberRef;
+        ContactPersonPhoneLogRef phoneLogRef;
+        std::string address;
+        std::string dispName;
+
+        numberRef = search<ContactPersonNumber>(searchWord);
+
+        if (numberRef) {
+            address = numberRef->getAddress();
+            dispName = numberRef->getDispName();
+        } else if (!numberRef) {
+            phoneLogRef = search<ContactPersonPhoneLog>(searchWord);
+            if (phoneLogRef)
+                address = phoneLogRef->getAddress();
+        }
+
+        if (!dispName.empty()) {
+            highlightWord = TextDecorator::highlightKeyword(std::move(dispName), searchWord);
+
+        }
+        else if (!address.empty()) {
+            highlightWord = TextDecorator::highlightKeyword(std::move(address), searchWord);
+        }
+    }
+
+    if (!highlightWord.empty()) {
+        showSearchBar(true);
+        m_pSearchBar->setText(highlightWord);
+    } else {
+        showSearchBar(false);
+    }
+
+    m_pTimer = nullptr;
+    return false; // Delete timer
+}
+
+void RecipInputFrame::reqestSearch()
+{
+    static const double interval = 0.3;
+
+    if (!isPopping()) {
+        if (!m_pTimer)
+            m_pTimer = ecore_timer_add(interval, makeCbFirst(&RecipInputFrame::onSearchTimerTick), this);
+        else
+            ecore_timer_reset(m_pTimer);
+    }
+}
+
+void RecipInputFrame::cancelSearch()
+{
+    if (m_pTimer) {
+        ecore_timer_del(m_pTimer);
+        m_pTimer = nullptr;
+    }
+}
+
+void RecipInputFrame::searchButtonHandler()
+{
+    cancelSearch();
+
+    std::string input = getEntry().getText();
+    int len = eina_unicode_utf8_get_len(input.c_str());
+
+    if (len > 0) {
+        bool isDig = isDigit(input);
+
+        if (len < minCharacters && !isDig) {
+            ToastPopup::toast(msgt("WDS_MSG_TPOP_ENTER_2_OR_MORE_LETTERS_ABB"));
+            return;
+        }
+
+        if (len < minDigits && isDig) {
+            ToastPopup::toast(msgt("WDS_MSG_TPOP_ENTER_3_OR_MORE_DIGITS_ABB"));
+            return;
+        }
+
+        auto numberRef = search<ContactPersonNumber>(input);
+        auto phoneLogRef = search<ContactPersonPhoneLog>(input);
+
+        if (numberRef || phoneLogRef) {
+            // TODO: impl.
+        } else {
+            if (MsgUtils::isValidNumber(input)) {
+                close();
+            } else {
+                ToastPopup::toast(msgt("WDS_PB_TPOP_NO_RESULTS_FOUND"), FAIL_ICON);
+            }
+        }
+    }
 }
 
 void RecipInputFrame::onAttached(ViewItem &item)
@@ -38,8 +227,42 @@ void RecipInputFrame::onAttached(ViewItem &item)
     InputFrame::onAttached(item);
 }
 
-bool RecipInputFrame::onRequestPop()
+void RecipInputFrame::onEntryFilter(Evas_Object *obj, char **text)
+{
+    if (*text) {
+        MSG_LOG(*text);
+        if (isPreedit(*text))
+            return;
+
+        if (isSeparatorChar(*text)) {
+            free(*text);
+            *text = nullptr;
+            close();
+        }
+    }
+}
+
+void RecipInputFrame::onEntryChanged(Evas_Object *obj, void *event_info)
+{
+    MSG_LOG("");
+    reqestSearch();
+}
+
+void RecipInputFrame::onButtonClicked(SearchBar &obj)
+{
+    MSG_LOG("");
+    searchButtonHandler();
+}
+
+void RecipInputFrame::onTextClicked(SearchBar &obj)
+{
+    MSG_LOG("");
+    close();
+}
+
+void RecipInputFrame::onEntryActivated(Evas_Object *obj, void *event_info)
 {
     MSG_LOG("");
-    return true;
+    searchButtonHandler();
 }
+