TizenRefApp-8058 Implement Thread list controller 92/116692/2
authorDenis Dolzhenko <d.dolzhenko@samsung.com>
Mon, 27 Feb 2017 16:39:50 +0000 (18:39 +0200)
committerDenis Dolzhenko <d.dolzhenko@samsung.com>
Tue, 28 Feb 2017 09:04:02 +0000 (11:04 +0200)
Change-Id: Ie0bd1fac5445f532cde8f765abd081d60b26a404
Signed-off-by: Denis Dolzhenko <d.dolzhenko@samsung.com>
18 files changed:
src/Common/Controller/src/App.cpp
src/Common/View/inc/ListView.h
src/Common/View/inc/StandardWindow.h
src/Common/View/inc/Window.h
src/Common/View/src/GroupListViewItem.cpp
src/Common/View/src/ListView.cpp
src/Common/View/src/NaviFrameView.cpp
src/Common/View/src/StandardWindow.cpp
src/MsgThread/Controller/inc/MsgThreadFrame.h
src/MsgThread/Controller/inc/ThreadList.h [new file with mode: 0644]
src/MsgThread/Controller/inc/ThreadListItem.h [new file with mode: 0644]
src/MsgThread/Controller/src/MsgThreadFrame.cpp
src/MsgThread/Controller/src/ThreadList.cpp [new file with mode: 0644]
src/MsgThread/Controller/src/ThreadListItem.cpp [new file with mode: 0644]
src/MsgThread/View/inc/ThreadComposeListViewItem.h
src/MsgThread/View/inc/ThreadListViewItem.h
src/MsgThread/View/src/ThreadComposeListViewItem.cpp
src/MsgThread/View/src/ThreadListViewItem.cpp

index c8aef83e4079f236563485a8dee73fac02647d4e..c3fdf12f3fca2d516cc30a1a042692a35f77cd53 100644 (file)
@@ -80,10 +80,14 @@ App &App::getInst()
 
 void App::exit()
 {
+    // TODO: Temporary solution
+    terminate();
+/*
     if (m_NeedToCloseApp)
         terminate(); // Close app completely
     else if (m_pWindow)
         m_pWindow->lower(); // Minimize window
+*/
 }
 
 void App::updateCharacterOrientation()
@@ -140,8 +144,7 @@ const ContactManager &App::getContactManager() const
 
 Window &App::getWindow()
 {
-    if (!m_pWindow)
-    {
+    if (!m_pWindow) {
         m_pWindow = new StandardWindow;
         m_pWindow->show();
     }
index a71a6227d5c4e68ff0286c275a2ce736ad33227f..a49ce4570ea2f7c8e19b157d66d0254430e8301c 100644 (file)
@@ -41,8 +41,9 @@ namespace Msg
             /**
              * @brief A constructor of ListView object based on outside parent object.
              * @param[in] parent an object responsible for automatic removing of ListView instance.
+             * @param[in] parent circle surface
              */
-            ListView(Evas_Object *parent);
+            ListView(Evas_Object *parent, Eext_Circle_Surface *parentCircleSurface = nullptr);
             virtual ~ListView();
 
             /**
@@ -247,7 +248,7 @@ namespace Msg
             static void notifyListener(void *data, Evas_Object *obj, void *event_info, ListenerMethod method);
 
         private:
-            void createListView(Evas_Object *parent);
+            void createListView(Evas_Object *parent, Eext_Circle_Surface *parentCircleSurface);
 
             static void on_item_selected_cb(void *data, Evas_Object *obj, void *event_info);
             static void on_realized_cb(void *data, Evas_Object *obj, void *event_info);
@@ -258,6 +259,7 @@ namespace Msg
             IListViewListener *m_pListener;
             bool m_CheckMode;
             CmpFunc m_CmpFunc;
+            Evas_Object *m_pCircleGenlist;
     };
 
     /**
index dc8d5b4c30e2460c6d85c710fdae8c5f134b8ab7..9487834eba87eec5546fdb9b67b51a03fe6649ad 100644 (file)
@@ -31,6 +31,7 @@ namespace Msg
             Evas_Object *getWinEvasObject() const override;
             Evas_Object *getConformEvasObject() const override;
             Evas_Object *getHostEvasObject() const override;
+            Eext_Circle_Surface *getCircleSurface() const override;
             void setContent(Evas_Object *content) override;
             void getScreenSize(int *x, int *y, int *w, int *h) const override;
             int getRotation() const override;
@@ -40,6 +41,7 @@ namespace Msg
         private:
             Evas_Object *m_pConform;
             Evas_Object *m_pBg;
+            Eext_Circle_Surface *m_pCircleSurface;
     };
 }
 
index 68a1f12a2f863b2e58fd3890887c9c14c7d0e338..caa6675a1e8ecec169cf35236b93edcf74319465 100644 (file)
@@ -34,6 +34,7 @@ namespace Msg
             virtual Evas_Object *getWinEvasObject() const = 0;
             virtual Evas_Object *getConformEvasObject() const = 0;
             virtual Evas_Object *getHostEvasObject() const = 0;
+            virtual Eext_Circle_Surface *getCircleSurface() const = 0;
             virtual void setContent(Evas_Object *content) = 0;
             virtual void getScreenSize(int *x, int *y, int *w, int *h) const = 0;
             virtual int getRotation() const = 0;
index 838da4228acd8909c097a806a9b6c4a6681d8c4c..5130e3cf32d2ea07732991d2034c162f3c614595 100644 (file)
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <GroupListViewItem.h>
+#include "GroupListViewItem.h"
 
 using namespace Msg;
 
@@ -36,7 +36,7 @@ void GroupListViewItem::onAttached(ViewItem &item)
 std::string GroupListViewItem::getText(ListItem &item, const char *part)
 {
     if (!strcmp(part, "elm.text"))
-        return m_TitleText;
+        return msg(m_TitleText);
 
     return "";
 }
index 007d1585c71f36d9136b4ea40276d22e4773b6e4..7fdffdfc2629a55634c353b1a47a864150661721 100644 (file)
@@ -21,6 +21,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include <efl_extension.h>
+
 using namespace Msg;
 
 namespace
@@ -32,13 +34,14 @@ namespace
 }
 
 // ListView:
-ListView::ListView(Evas_Object *parent)
+ListView::ListView(Evas_Object *parent, Eext_Circle_Surface *parentCircleSurface)
     : View()
     , m_pListener(nullptr)
     , m_CheckMode(false)
     , m_CmpFunc()
+    , m_pCircleGenlist(nullptr)
 {
-    createListView(parent);
+    createListView(parent, parentCircleSurface);
 }
 
 ListView::~ListView()
@@ -50,12 +53,21 @@ void ListView::setListener(IListViewListener *listener)
     m_pListener = listener;
 }
 
-void ListView::createListView(Evas_Object *parent)
+void ListView::createListView(Evas_Object *parent, Eext_Circle_Surface *parentCircleSurface)
 {
     setEo(elm_genlist_add(parent));
     evas_object_smart_callback_add(getEo(), "realized", ListView::on_realized_cb, this);
     evas_object_smart_callback_add(getEo(), "unrealized", ListView::on_unrealized_cb, this);
     evas_object_smart_callback_add(getEo(), "longpressed", ListView::on_longpressed_cb, this);
+
+    if (parentCircleSurface) {
+        // Default settings:
+        m_pCircleGenlist = eext_circle_object_genlist_add(getEo(), parentCircleSurface);
+        if (m_pCircleGenlist) {
+            eext_circle_object_genlist_scroller_policy_set(m_pCircleGenlist, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
+            eext_rotary_object_event_activated_set(m_pCircleGenlist, true);
+        }
+    }
 }
 
 bool ListView::appendItem(ListItem &listItem, ListItem *parent)
@@ -270,7 +282,8 @@ void ListView::checkAllItems(bool check,  bool updateFullItem)
 {
     for (ListItem *item: getItems())
     {
-        item->setCheckedState(check, false);
+        if (item->isCheckable())
+            item->setCheckedState(check, false);
     }
 
     if (updateFullItem)
@@ -278,7 +291,8 @@ void ListView::checkAllItems(bool check,  bool updateFullItem)
     else
         for (ListItem *item: getRealizedItems())
         {
-            item->updateFields(item->getCheckPart(*item), ELM_GENLIST_ITEM_FIELD_ALL);
+            if (item->isCheckable())
+                item->updateFields(item->getCheckPart(*item), ELM_GENLIST_ITEM_FIELD_ALL);
         }
 }
 
index 0479ba00bc974d5a67583ea0e005dc095af7e69b..08dd7aac2b5d9ba52956278812b7b2f779ecb7a3 100644 (file)
@@ -32,10 +32,8 @@ NaviFrameView::NaviFrameView(Evas_Object *parent)
 }
 
 NaviFrameView::NaviFrameView(View &parent)
-    : View()
-    , m_TransitionStatus(false)
+    : NaviFrameView(parent.getEo())
 {
-    create(parent.getEo());
 }
 
 NaviFrameView::~NaviFrameView()
@@ -209,3 +207,4 @@ bool NaviFrameView::getTransitionStatus() const
     // TODO: Move functionality for gets TransitionStatus to EFL (elm_naviframe) side.
     return m_TransitionStatus;
 }
+
index 79497f9d85472bdec73b80bb5860ecfccb19e1ce..8fd510e823f6b48bf9113f74e10880622f874d78 100644 (file)
@@ -25,6 +25,7 @@ StandardWindow::StandardWindow()
     : Window()
     , m_pConform(nullptr)
     , m_pBg(nullptr)
+    , m_pCircleSurface(nullptr)
 {
     // Window:
     setEo(elm_win_add(nullptr, PACKAGE_NAME, ELM_WIN_BASIC));
@@ -39,6 +40,8 @@ StandardWindow::StandardWindow()
     elm_win_resize_object_add(getEo(), m_pConform);
     evas_object_show(m_pConform);
 
+    m_pCircleSurface = eext_circle_surface_conformant_add(m_pConform);
+
     // Bg:
     m_pBg = elm_bg_add(m_pConform);
     evas_object_size_hint_weight_set(m_pBg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
@@ -77,6 +80,11 @@ Evas_Object *StandardWindow::getHostEvasObject() const
     return m_pConform;
 }
 
+Eext_Circle_Surface *StandardWindow::getCircleSurface() const
+{
+    return m_pCircleSurface;
+}
+
 void StandardWindow::setContent(Evas_Object *content)
 {
     elm_object_content_set(m_pConform, content);
index db37802b4e3c5ae46f56cfc671f7f75cd1d4a1a6..6c432780e03c5589d9b963000ae8cd0f266d0311 100644 (file)
 #include "SelectButton.h"
 #include "MoreOption.h"
 #include "CtxPopup.h"
+#include "ThreadList.h"
 
 namespace Msg {
     class MsgThreadFrame
-        : public FrameController {
+        : public FrameController
+        , private IThreadListListener {
 
         public:
             MsgThreadFrame(NaviFrameController &parent);
@@ -68,11 +70,19 @@ namespace Msg {
             void onNewMessageClicked(MoreOption &obj);
             void onDeleteClicked(MoreOption &obj);
 
+            // IThreadListListener:
+            void onListItemSelected(ThreadId id) override;
+            void onThreadListChanged() override;
+            void onThreadListItemChecked() override;
+            void onComposeButtonClicked() override;
+            void onContactsButtonClicked() override;
+
         private:
             DefaultLayout *m_pLayout;
             MoreOption *m_pMoreOption;
             BottomButton *m_pDeleteButton;
             SelectButton *m_pSelectButton;
+            ThreadList *m_pThreadList;
             Mode m_Mode;
     };
 }
diff --git a/src/MsgThread/Controller/inc/ThreadList.h b/src/MsgThread/Controller/inc/ThreadList.h
new file mode 100644 (file)
index 0000000..0821e86
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ThreadList_h_
+#define ThreadList_h_
+
+#include "ListView.h"
+#include "MsgStorage.h"
+#include "ContactManager.h"
+#include "SystemSettingsManager.h"
+#include "ThreadComposeListViewItem.h"
+#include "MsgTypes.h"
+#include <set>
+
+namespace Msg {
+    class IThreadListListener;
+    class ThreadListItem;
+    class App;
+
+    class ThreadList
+        : public ListView
+        , private IMsgStorageListener
+        , private IListViewListener
+        , private IContactManagerListener
+        , private ISystemSettingsManager
+        , private IThreadComposeListViewItemListener {
+
+        public:
+            ThreadList(Evas_Object *parent);
+            virtual ~ThreadList();
+
+            void setListener(IThreadListListener *l);
+            void setDeleteMode(bool value);
+            bool isDeleteModeEnabled() const;
+            void deleteSelectedItems();
+            int getThreadsCheckedCount() const;
+
+        private:
+            // IMsgStorageListener:
+            void onMsgStorageThreadUpdate(const ThreadId &threadId) override;
+            void onMsgStorageThreadInsert(const ThreadId &threadId) override;
+            void onMsgStorageThreadDelete(const ThreadId &threadId) override;
+
+            // IContactManagerListener:
+            void onContactChanged() override;
+
+            // IListViewListener:
+            void onListItemSelected(ListItem &listItem) override;
+            void onListItemChecked(ListItem &listItem) override;
+
+            // ISystemSettingsManager:
+            void onTimeFormatChanged() override;
+            void onLanguageChanged() override;
+
+            // IThreadComposeListViewItemListener:
+            void onComposeButtonClicked() override;
+            void onContactsButtonClicked() override;
+
+        private:
+            void checkHandler(ThreadListItem &item);
+            void fillList();
+            void deleteItems();
+            void updateItems(const MsgIdList &idList);
+            void updateItems();
+            void updateItem(ThreadListItem &item);
+            void insertItem(ThreadId id);
+            void navigateTo(ThreadListItem &item);
+            ThreadListItem *getItem(ThreadId id) const;
+            bool isAllThreadListItemChecked() const;
+            void updateSelectAllItem();
+            std::set<ThreadId> getThreadIdSet(const MsgIdList &idList);
+            static int cmpFunc(const ListItem &item1, const ListItem &item2);
+
+        private:
+            IThreadListListener *m_pListener;
+            App &m_App;
+            bool m_DeleteMode;
+            ThreadComposeListViewItem *m_ComposeItem;
+    };
+
+    class IThreadListListener {
+        public:
+            virtual ~IThreadListListener() {}
+            virtual void onListItemSelected(ThreadId id) {};
+            virtual void onThreadListChanged() {}
+            virtual void onThreadListItemChecked() {}
+            virtual void onComposeButtonClicked() {};
+            virtual void onContactsButtonClicked() {};
+    };
+}
+
+#endif // ThreadList_h_
diff --git a/src/MsgThread/Controller/inc/ThreadListItem.h b/src/MsgThread/Controller/inc/ThreadListItem.h
new file mode 100644 (file)
index 0000000..ee66005
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ThreadListItem_h_
+#define ThreadListItem_h_
+
+#include "MsgThreadItem.h"
+#include "ContactPersonNumber.h"
+#include "ThreadListViewItem.h"
+
+namespace Msg {
+    class ThreadListItem
+        : public ThreadListViewItem {
+        public:
+            ThreadListItem(const MsgThreadItem &threadItem);
+            virtual ~ThreadListItem();
+
+            ThreadId getThreadId() const;
+            void update(const MsgThreadItem &threadItem, bool updateUi);
+            void updateName(const MsgAddressList &addressList);
+            void updateName(const MsgThreadItem &threadItem);
+            void updateName(const MsgAddress &address, int addressesCount);
+            void updateName(const ContactAddress &address, int addressesCount);
+            void updateName(const std::string &address, int addressesCount);
+            void updateTime(time_t time);
+            void updateTime();
+            void updateMessage(const MsgThreadItem &threadItem);
+            void updateMessage(const std::string &msg);
+            time_t getRawTime() const;
+
+        private:
+            // ThreadListViewItem:
+            std::string getName() override;
+            std::string getMessage() override;
+            std::string getTime() override;
+            std::string getUnreadCount() override;
+
+        private:
+            ThreadId m_ThreadId;
+            std::string m_UnreadCount;
+            std::string m_Name;
+            std::string m_Message;
+            std::string m_Time;
+            time_t m_RawTime;
+    };
+}
+
+#endif // ThreadListItem_h_
index 0ae1a256db4638f6473eb3fe3d5177746afb340e..bbf8c1a2aa838e97ec1d4604eef4c93003ad525b 100644 (file)
@@ -33,12 +33,14 @@ MsgThreadFrame::MsgThreadFrame(NaviFrameController &parent)
     , m_pMoreOption(nullptr)
     , m_pDeleteButton(nullptr)
     , m_pSelectButton(nullptr)
+    , m_pThreadList(nullptr)
     , m_Mode(InitMode)
 {
     MSG_LOG("");
     prepareMainLayout();
     prepareMoreOption();
     prepareDeleteViews();
+    prepareThreadList();
     setMode(NormalMode);
 }
 
@@ -73,6 +75,7 @@ void MsgThreadFrame::setNormalMode(bool value)
     m_pLayout->showMoreOption(true);
     m_pLayout->showBottomButton(false);
     m_pSelectButton->showButton(false);
+    m_pThreadList->setDeleteMode(false);
 }
 
 void MsgThreadFrame::setDeleteMode(bool value)
@@ -80,13 +83,19 @@ void MsgThreadFrame::setDeleteMode(bool value)
     MSG_LOG("");
     m_Mode = DeleteMode;
     m_pLayout->showBottomButton(true);
-    m_pSelectButton->showButton(true);
     m_pLayout->showMoreOption(false);
+    m_pSelectButton->showButton(true);
+    m_pThreadList->setDeleteMode(true);
 }
 
 void MsgThreadFrame::prepareThreadList()
 {
-
+    if (!m_pThreadList) {
+        m_pThreadList = new ThreadList(*m_pLayout);
+        m_pThreadList->setListener(this);
+        m_pLayout->setContent(*m_pThreadList);
+        m_pLayout->showContent(true);
+    }
 }
 
 void MsgThreadFrame::prepareMainLayout()
@@ -184,3 +193,27 @@ void MsgThreadFrame::onDeleteClicked(MoreOption &obj)
     setMode(DeleteMode);
 }
 
+void MsgThreadFrame::onListItemSelected(ThreadId id)
+{
+    MSG_LOG("");
+}
+
+void MsgThreadFrame::onThreadListChanged()
+{
+    MSG_LOG("");
+}
+
+void MsgThreadFrame::onThreadListItemChecked()
+{
+    MSG_LOG("");
+}
+
+void MsgThreadFrame::onComposeButtonClicked()
+{
+    MSG_LOG("");
+}
+
+void MsgThreadFrame::onContactsButtonClicked()
+{
+    MSG_LOG("");
+}
diff --git a/src/MsgThread/Controller/src/ThreadList.cpp b/src/MsgThread/Controller/src/ThreadList.cpp
new file mode 100644 (file)
index 0000000..1c72a31
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "ThreadList.h"
+#include "ThreadListItem.h"
+#include "PaddingListViewItem.h"
+#include "ThreadComposeListViewItem.h"
+#include "NoContentListViewItem.h"
+#include "GroupListViewItem.h"
+#include "MsgEngine.h"
+#include "App.h"
+
+using namespace Msg;
+
+namespace {
+    bool isThreadItem(const ListItem &item)
+    {
+        return dynamic_cast<const ThreadListItem*>(&item) != nullptr;
+    }
+}
+
+ThreadList::ThreadList(Evas_Object *parent)
+    : ListView(parent, App::getInst().getWindow().getCircleSurface())
+    , m_pListener(nullptr)
+    , m_App(App::getInst())
+    , m_DeleteMode(false)
+    , m_ComposeItem(nullptr)
+{
+    ListView::setListener(this);
+    ListView::setHomogeneous(false);
+    ListView::setMultiSelection(false);
+    ListView::setMode(ELM_LIST_COMPRESS);
+    ListView::setCmpFunc(cmpFunc);
+
+    m_App.getMsgEngine().getStorage().addListener(*this);
+    m_App.getContactManager().addListener(*this);
+    m_App.getSysSettingsManager().addListener(*this);
+    fillList();
+}
+
+ThreadList::~ThreadList()
+{
+    m_App.getMsgEngine().getStorage().removeListener(*this);
+    m_App.getContactManager().removeListener(*this);
+    m_App.getSysSettingsManager().removeListener(*this);
+}
+
+void ThreadList::setListener(IThreadListListener *l)
+{
+    m_pListener = l;
+}
+
+void ThreadList::setDeleteMode(bool value)
+{
+    if (m_DeleteMode != value) {
+        m_DeleteMode = value;
+        setCheckMode(value);
+        ThreadListViewItem::resetCheckMode(*this);
+        checkAllItems(false, true);
+        if (m_ComposeItem)
+            m_ComposeItem->disabled(value);
+    }
+}
+
+bool ThreadList::isDeleteModeEnabled() const
+{
+    return m_DeleteMode;
+}
+
+void ThreadList::deleteSelectedItems()
+{
+    auto items = getItems<ThreadListItem>();
+    for (ThreadListItem *it : items) {
+        if (it->getCheckedState())
+            m_App.getMsgEngine().getStorage().deleteThread(it->getThreadId());
+    }
+}
+
+int ThreadList::getThreadsCheckedCount() const
+{
+    auto items = getItems<ThreadListItem>();
+    int count = 0;
+    for (ThreadListItem *item : items) {
+        if (item->isCheckable() && item->getCheckedState())
+            ++count;
+    }
+    return count;
+}
+
+bool ThreadList::isAllThreadListItemChecked() const
+{
+    // Simple impl. but not fast:
+    auto items = getItems<ThreadListItem>();
+    for (ThreadListItem *item : items) {
+        if (item->isCheckable() && !item->getCheckedState())
+            return false;
+    }
+    return true;
+}
+
+void ThreadList::updateSelectAllItem()
+{
+    if (!m_DeleteMode)
+        return;
+
+  //  bool allChecked = isAllThreadListItemChecked();
+}
+
+void ThreadList::checkHandler(ThreadListItem &item)
+{
+    ThreadId threadId = item.getThreadId();
+    MSG_LOG("Checked (id : state) = ", threadId, ":", item.getCheckedState());
+    updateSelectAllItem();
+    if (m_pListener)
+        m_pListener->onThreadListItemChecked();
+}
+
+int ThreadList::cmpFunc(const ListItem &item1, const ListItem &item2)
+{
+    bool isTh1 = isThreadItem(item1);
+    bool isTh2 = isThreadItem(item2);
+
+    if (!isTh1 && !isTh2)
+        return 0;
+
+    if (!isTh1 || !isTh2)
+        return !isTh1;
+
+    auto &threadItem1 = static_cast<const ThreadListItem&>(item1);
+    auto &threadItem2 = static_cast<const ThreadListItem&>(item2);
+    return threadItem2.getRawTime() - threadItem1.getRawTime();
+}
+
+void ThreadList::insertItem(ThreadId id)
+{
+    MsgThreadItemRef threadItem = m_App.getMsgEngine().getStorage().getThread(id);
+    if (threadItem) {
+        auto newItem = new ThreadListItem(*threadItem);
+        ListView::sortedInsertItem(*newItem);
+        navigateTo(*newItem);
+    }
+}
+
+ThreadListItem *ThreadList::getItem(ThreadId id) const
+{
+    auto items = ListView::getItems<ThreadListItem>();
+    for (ThreadListItem *item : items) {
+        if (item->getThreadId() == id)
+            return item;
+    }
+    return nullptr;
+}
+
+void ThreadList::fillList()
+{
+    // Top padding:
+    ListView::appendItem(*new PaddingListViewItem);
+
+    // Compose Item:
+    m_ComposeItem = new ThreadComposeListViewItem;
+    m_ComposeItem->setListener(this);
+    ListView::appendItem(*m_ComposeItem);
+
+    // Group item:
+    ListView::appendItem(*new GroupListViewItem("IDS_MSG_HEADER_MESSAGES"));
+
+    // Thread list:
+    MsgThreadListRef msgThreadList = m_App.getMsgEngine().getStorage().getThreadList();
+    if (msgThreadList) {
+        int length = msgThreadList->getLength();
+
+        for (int i = 0; i < length; ++i) {
+            const MsgThreadItem &msgThreadItem = msgThreadList->at(i);
+            ListView::appendItem(*new ThreadListItem(msgThreadItem));
+        }
+    }
+
+    // Bottom padding:
+    ListView::appendItem(*new PaddingListViewItem);
+}
+
+void ThreadList::deleteItems()
+{
+    MsgThreadListRef msgThreadList = m_App.getMsgEngine().getStorage().getThreadList();
+    if (!msgThreadList)
+        return;
+
+    std::set<ThreadId> threadIdSet;
+    int length = msgThreadList->getLength();
+    for (int i = 0; i < length; ++i) {
+        const MsgThreadItem &msgThreadItem = msgThreadList->at(i);
+        threadIdSet.insert(msgThreadItem.getId());
+    }
+
+    auto items = ListView::getItems<ThreadListItem>();
+
+    for (ThreadListItem *item : items) {
+        if (threadIdSet.count(item->getThreadId()) == 0)
+            ListView::deleteItem(*item);
+    }
+
+    updateSelectAllItem();
+}
+
+void ThreadList::navigateTo(ThreadListItem &item)
+{
+    ListView::showItem(item, ELM_GENLIST_ITEM_SCROLLTO_TOP);
+}
+
+void ThreadList::updateItems(const MsgIdList &idList)
+{
+    auto threadIdSet = getThreadIdSet(idList);
+    auto threadItems = getItems<ThreadListItem>();
+
+    for (ThreadListItem *item: threadItems) {
+        if (threadIdSet.count(item->getThreadId()))
+            updateItem(*item);
+    }
+}
+
+void ThreadList::updateItems()
+{
+    auto items = getItems<ThreadListItem>();
+    for (ThreadListItem *item: items) {
+        updateItem(*item);
+    }
+}
+
+void ThreadList::updateItem(ThreadListItem &item)
+{
+    MsgThreadItemRef msgThread = m_App.getMsgEngine().getStorage().getThread(item.getThreadId());
+    if (!msgThread) {
+        MSG_LOG_ERROR("msgThread is null");
+        return;
+    }
+
+    auto *next = getNextItem<ThreadListItem>(item);
+    auto *prev = getPrevItem<ThreadListItem>(item);
+    time_t threadTime = msgThread->getTime();
+
+    if ((next && threadTime < next->getRawTime()) ||
+       (prev && threadTime > prev->getRawTime())) {
+        auto newItem = new ThreadListItem(*msgThread);
+        newItem->setCheckedState(item.getCheckedState(), false);
+        item.destroy();
+        ListView::sortedInsertItem(*newItem);
+        navigateTo(*newItem);
+    } else {
+        item.update(*msgThread, true);
+        navigateTo(item);
+    }
+}
+
+std::set<ThreadId> ThreadList::getThreadIdSet(const MsgIdList &idList)
+{
+    std::set<ThreadId> res;
+    for (MsgId msgId : idList) {
+        ThreadId threadId = m_App.getMsgEngine().getStorage().getThreadId(msgId);
+        if (threadId.isValid())
+            res.insert(threadId);
+    }
+    return res;
+}
+
+void ThreadList::onListItemSelected(ListItem &listItem)
+{
+    MSG_LOG("");
+    auto *it = dynamic_cast<ThreadListItem*>(&listItem);
+    if (it && m_pListener)
+        m_pListener->onListItemSelected(it->getThreadId());
+}
+
+void ThreadList::onListItemChecked(ListItem &listItem)
+{
+    MSG_LOG("");
+    if (auto *it = dynamic_cast<ThreadListItem*>(&listItem))
+        checkHandler(*it);
+}
+
+void ThreadList::onMsgStorageThreadUpdate(const ThreadId &threadId)
+{
+    MSG_LOG("");
+    auto* item = getItem(threadId);
+    if (item)
+        updateItem(*item);
+}
+
+void ThreadList::onMsgStorageThreadInsert(const ThreadId &threadId)
+{
+    MSG_LOG("");
+    insertItem(threadId);
+    updateSelectAllItem();
+    if (m_pListener)
+        m_pListener->onThreadListChanged();
+}
+
+void ThreadList::onMsgStorageThreadDelete(const ThreadId &threadId)
+{
+    MSG_LOG("");
+    auto* thread = getItem(threadId);
+    if (thread) {
+        ListView::deleteItem(*thread);
+        updateSelectAllItem();
+    }
+
+    if (m_pListener)
+        m_pListener->onThreadListChanged();
+}
+
+void ThreadList::onContactChanged()
+{
+    MSG_LOG("");
+    updateItems();
+}
+
+void ThreadList::onTimeFormatChanged()
+{
+    MSG_LOG("");
+    auto items = ListView::getItems<ThreadListItem>();
+    for (ThreadListItem *item : items) {
+        item->updateTime();
+    }
+
+    ListView::updateRealizedItems();
+}
+
+void ThreadList::onLanguageChanged()
+{
+    MSG_LOG("");
+    updateItems();
+}
+
+void ThreadList::onComposeButtonClicked()
+{
+    MSG_LOG("");
+    if (m_pListener)
+        m_pListener->onComposeButtonClicked();
+}
+
+void ThreadList::onContactsButtonClicked()
+{
+    MSG_LOG("");
+    if (m_pListener)
+        m_pListener->onContactsButtonClicked();
+}
diff --git a/src/MsgThread/Controller/src/ThreadListItem.cpp b/src/MsgThread/Controller/src/ThreadListItem.cpp
new file mode 100644 (file)
index 0000000..c3fe711
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2016  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ThreadListItem.h"
+#include "ListView.h"
+#include "Logger.h"
+#include "PathUtils.h"
+#include "MsgEngine.h"
+#include "App.h"
+#include "MsgThreadItem.h"
+#include "LangUtils.h"
+#include "TimeUtils.h"
+#include "ContactManager.h"
+
+using namespace Msg;
+
+ThreadListItem::ThreadListItem(const MsgThreadItem &threadItem)
+    : ThreadListViewItem()
+    , m_ThreadId()
+    , m_RawTime()
+{
+    update(threadItem, false);
+}
+
+ThreadListItem::~ThreadListItem()
+{
+}
+
+void ThreadListItem::update(const MsgThreadItem &threadItem, bool updateUi)
+{
+    m_ThreadId = threadItem.getId();
+    State state = NormalState;
+
+    MsgConversationListRef convList = App::getInst().getMsgEngine().getStorage().getConversationList(m_ThreadId);
+    if (convList && convList->getLength() > 0) {
+        MsgConversationItem &item = convList->at(convList->getLength() - 1);
+
+        Message::NetworkStatus status = item.getNetworkStatus();
+        if (status == Message::NS_Sending) {
+            state = StatusState;
+        } else if (status == Message::NS_Send_Fail) {
+            state = StatusState;
+        } else if (item.isDraft()) {
+            state = StatusState;
+        } else if (!item.isRead()) {
+            int count = threadItem.getUnreadCount();
+            if (count > 0) {
+                state = IconState;
+                m_UnreadCount = std::to_string(count);
+            }
+        }
+    }
+
+    setState(state, false);
+    updateMessage(threadItem);
+    updateName(threadItem);
+    updateTime(threadItem.getTime());
+
+    if (updateUi)
+        ListItem::update();
+}
+
+void ThreadListItem::updateMessage(const MsgThreadItem &threadItem)
+{
+    updateMessage(threadItem.getLastMessage());
+}
+
+void ThreadListItem::updateMessage(const std::string &msg)
+{
+    m_Message = msg;
+}
+
+void ThreadListItem::updateName(const MsgThreadItem &threadItem)
+{
+    const MsgAddressListRef addressList = App::getInst().getMsgEngine().getStorage().getAddressList(threadItem.getId());
+    if (addressList)
+        updateName(*addressList);
+}
+
+void ThreadListItem::updateName(const MsgAddressList &addressList)
+{
+    int countContact = addressList.getLength();
+    if (countContact <= 0) {
+        MSG_LOG_WARN("Msg address list is empty");
+        return;
+    }
+
+    const MsgAddress &addr = addressList[0];
+
+    if (countContact > 1) {
+        updateName(addr, countContact);
+    } else if (countContact == 1) {
+        updateName(addr, countContact);
+    }
+}
+
+void ThreadListItem::updateName(const MsgAddress &address, int addressesCount)
+{
+    ContactAddressRef contactAddress = App::getInst().getContactManager().getContactAddress(address.getAddress());
+    if (contactAddress)
+        updateName(*contactAddress, addressesCount);
+    else
+        updateName(address.getAddress(), addressesCount);
+}
+
+void ThreadListItem::updateName(const ContactAddress &address, int addressesCount)
+{
+    std::string dispName = address.getDispName();
+    if (dispName.empty())
+        dispName = address.getAddress();
+    updateName(dispName, addressesCount);
+}
+
+void ThreadListItem::updateName(const std::string &address, int addressesCount)
+{
+    m_Name = address;
+    --addressesCount;
+    if (addressesCount > 0)
+        m_Name += " +" + std::to_string(addressesCount);
+}
+
+void ThreadListItem::updateTime(time_t time)
+{
+    m_RawTime = time;
+    m_Time = TimeUtils::makeThreadTimeString(time);
+}
+
+void ThreadListItem::updateTime()
+{
+    m_Time = TimeUtils::makeThreadTimeString(m_RawTime);
+}
+
+std::string ThreadListItem::getName()
+{
+    return m_Name;
+}
+
+std::string ThreadListItem::getMessage()
+{
+    return m_Message;
+}
+
+std::string ThreadListItem::getTime()
+{
+    return m_Time;
+}
+
+time_t ThreadListItem::getRawTime() const
+{
+    return m_RawTime;
+}
+
+ThreadId ThreadListItem::getThreadId() const
+{
+    return m_ThreadId;
+}
+
+std::string ThreadListItem::getUnreadCount()
+{
+    return m_UnreadCount;
+}
+
index 1e16aa3f9647c6a316d56bf7618f35985cd5a505..d6f1644597575acad0eaf48d91d7fc87edce3c5d 100644 (file)
@@ -21,6 +21,9 @@
 #include <string>
 
 namespace Msg {
+
+    class IThreadComposeListViewItemListener;
+
     class ThreadComposeListViewItem
         : public ListItem {
 
@@ -28,9 +31,9 @@ namespace Msg {
             ThreadComposeListViewItem();
             virtual ~ThreadComposeListViewItem();
 
+            void setListener(IThreadComposeListViewItemListener *l);
+
         protected:
-            virtual void onComposeButtonClicked(Evas_Object *obj, void *event) {};
-            virtual void onContactsButtonClicked(Evas_Object *obj, void *event) {};
             void onAttached(ViewItem &item) override;
 
         private:
@@ -39,6 +42,16 @@ namespace Msg {
 
             Evas_Object *makeButton(const std::string& iconName);
             Evas_Object *getContent(ListItem &item, const char *part) override;
+
+        private:
+            IThreadComposeListViewItemListener *m_pListener;
+    };
+
+    class IThreadComposeListViewItemListener {
+        public:
+            virtual ~IThreadComposeListViewItemListener() {};
+            virtual void onComposeButtonClicked() {};
+            virtual void onContactsButtonClicked() {};
     };
 }
 
index c26297c8a008b009748a6b55d745386f6fb72ff0..e1ebbfa1eb7ab0d0a858296a85a0546003ad249b 100644 (file)
@@ -26,11 +26,12 @@ namespace Msg {
         public:
             enum State {
                 NormalState,
-                IconState
+                IconState,
+                StatusState
             };
 
         public:
-            ThreadListViewItem(Elm_Genlist_Item_Type type = ELM_GENLIST_ITEM_NONE);
+            ThreadListViewItem();
             virtual ~ThreadListViewItem();
 
             void setState(State state, bool updateUi);
@@ -38,10 +39,10 @@ namespace Msg {
             static void resetCheckMode(ListView &listView);
 
         protected:
-            virtual std::string getName();
-            virtual std::string getMessage();
-            virtual std::string getTime();
-            virtual std::string getUnreadCount();
+            virtual std::string getName() = 0;
+            virtual std::string getMessage() = 0;
+            virtual std::string getTime() = 0;
+            virtual std::string getUnreadCount() = 0;
 
             using ListItem::getState;
             Evas_Object *makeUnreadIcon(const std::string &text) const;
index 5092011689d4498c9b220f6e6ec71e142e899b65..5c4992bf0426344413e0ced38568bac3ebe322df 100644 (file)
@@ -30,6 +30,7 @@ namespace {
 
 ThreadComposeListViewItem::ThreadComposeListViewItem()
     : ListItem(ListItemStyle::create("compose_threadlist_item"))
+    , m_pListener(nullptr)
 {
 }
 
@@ -57,14 +58,30 @@ void ThreadComposeListViewItem::onAttached(ViewItem &item)
 Evas_Object *ThreadComposeListViewItem::getComposeButton()
 {
     Evas_Object *btn = makeButton("compose_icon");
-    evas_object_smart_callback_add(btn, "clicked", makeCbFirst(&ThreadComposeListViewItem::onComposeButtonClicked), this);
+    evas_object_smart_callback_add(
+        btn, "clicked",
+        [](void *data, Evas_Object *obj, void *event)
+        {
+            auto *self = static_cast<ThreadComposeListViewItem*>(data);
+            if (self && self->m_pListener)
+                self->m_pListener->onComposeButtonClicked();
+        },
+        this);
     return btn;
 }
 
 Evas_Object *ThreadComposeListViewItem::getContactsButton()
 {
     Evas_Object *btn = makeButton("contacts_icon");
-    evas_object_smart_callback_add(btn, "clicked", makeCbFirst(&ThreadComposeListViewItem::onContactsButtonClicked), this);
+    evas_object_smart_callback_add(
+        btn, "clicked",
+        [](void *data, Evas_Object *obj, void *event)
+        {
+            auto *self = static_cast<ThreadComposeListViewItem*>(data);
+            if (self && self->m_pListener)
+                self->m_pListener->onContactsButtonClicked();
+        },
+        this);
     return btn;
 }
 
@@ -78,3 +95,9 @@ Evas_Object *ThreadComposeListViewItem::makeButton(const std::string& iconName)
 
     return button;
 }
+
+void ThreadComposeListViewItem::setListener(IThreadComposeListViewItemListener *l)
+{
+    m_pListener = l;
+}
+
index 080db197622608818ff62904d8917364b51e3c06..1cbb00ad954ebec2c34ddae9d3d146960f618d60 100644 (file)
@@ -28,8 +28,6 @@
 using namespace Msg;
 
 namespace {
-    ListItemStyleRef threadItemStyle = ListItemStyle::create("msg_thread");
-
     const char *namePart = "elm.text";
     const char *messagePart = "elm.text.1";
     const char *timePart = "elm.text.2";
@@ -37,8 +35,8 @@ namespace {
     const char *iconPart = "elm.icon";
 }
 
-ThreadListViewItem::ThreadListViewItem(Elm_Genlist_Item_Type type)
-    : ListItem(threadItemStyle, type)
+ThreadListViewItem::ThreadListViewItem()
+    : ListItem(ListItemStyle::create("msg_thread"), ELM_GENLIST_ITEM_NONE)
     , m_State(NormalState)
 {
 }
@@ -99,26 +97,7 @@ Evas_Object *ThreadListViewItem::makeUnreadIcon(const std::string &text) const
     return icon;
 }
 
-std::string ThreadListViewItem::getName()
-{
-    return "NAME"; // only for test
-}
-
-std::string ThreadListViewItem::getMessage()
-{
-    return "Message"; // only for test
-}
-
-std::string ThreadListViewItem::getTime()
-{
-    return "17.45"; // only for test
-}
-
-std::string ThreadListViewItem::getUnreadCount()
-{
-    return ""; // only for test
-}
-
 void ThreadListViewItem::resetCheckMode(ListView &listView)
 {
+    // TODO: impl if needed.
 }