TizenRefApp-7059 Update Select All item behavior in the Select View during Search 33/86833/4
authorEugene Kurzberg <i.kurtsberg@samsung.com>
Mon, 5 Sep 2016 12:56:40 +0000 (15:56 +0300)
committerAleksandr Sapozhnik <a.sapozhnik@samsung.com>
Wed, 7 Sep 2016 10:47:11 +0000 (03:47 -0700)
[Implementation] Implemented GenItem visibility tracking.
Simplified count update in SelectView. Implemented visible items counting.

Change-Id: Iae02386130af9305190a2891bf45931c18d5a23d
Signed-off-by: Eugene Kurzberg <i.kurtsberg@samsung.com>
lib-apps-common/inc/Ui/GenItem.h
lib-apps-common/inc/Ux/SelectItem.h
lib-apps-common/inc/Ux/SelectView.h
lib-apps-common/src/Ui/GenItem.cpp
lib-apps-common/src/Ux/SelectItem.cpp
lib-apps-common/src/Ux/SelectView.cpp
lib-contacts/inc/Contacts/List/PersonGroupItem.h
lib-contacts/inc/Contacts/List/PersonSearchItem.h
lib-contacts/src/Contacts/List/Model/PersonProvider.cpp
lib-contacts/src/Contacts/List/PersonGroupItem.cpp
lib-contacts/src/Contacts/List/PersonSearchItem.cpp

index 7998023..5b21db6 100644 (file)
@@ -61,6 +61,11 @@ namespace Ui
                bool isInserted() const;
 
                /**
+                * @return Whether the item is visible.
+                */
+               bool isVisible() const;
+
+               /**
                 * @return Whether the item is a group item.
                 */
                virtual bool isGroupItem() const { return false; }
@@ -115,7 +120,7 @@ namespace Ui
                 * @brief Set item destruction callback.
                 * @param[in]   callback    Callback to be called before item is destroyed
                 */
-               void setDestroyCallback(SelectCallback callback);
+               void setDestroyCallback(DestroyCallback callback);
 
                /**
                 * @brief Scroll to the item.
@@ -176,8 +181,8 @@ namespace Ui
 
                /**
                 * @brief Called whenever any item's state part needs to be updated
-                * @details Genlist will emit signal "elm,state,x,active" or
-                *          "elm,state,x,passive" with part's name instead of 'x'.
+                * @details Genlist will emit signal "elm,state,x,active" or "elm,state,x,passive"
+                *          with part's name instead of 'x'.
                 * @param[in]   parent  Parent genlist
                 * @param[in]   part    Name of the part
                 * @return EINA_TRUE for active, EINA_FALSE for passive
@@ -186,11 +191,10 @@ namespace Ui
 
                /**
                 * @brief Called when genlist filter is set using elm_genlist_filter_set().
-                * @param[in]   parent  Parent genlist
                 * @param[in]   filter  Filter to compare with
                 * @return Whether the item satisfies the filter.
                 */
-               virtual Eina_Bool compare(Evas_Object *parent, void *filter) { return EINA_TRUE; }
+               virtual bool compare(void *filter) { return true; }
 
                /**
                 * @brief Called after item was inserted into genlist.
@@ -203,6 +207,12 @@ namespace Ui
                virtual void onPop() { }
 
                /**
+                * @brief Called when item visibility changes via pop() or compare() or
+                *        insertion into container.
+                */
+               virtual void onVisibilityChanged(bool isVisible) { }
+
+               /**
                 * @brief Called when item is selected.
                 */
                virtual void onSelected() { }
@@ -214,13 +224,13 @@ namespace Ui
                virtual bool onLongpressed() { return false; }
 
                /**
-                * @brief Called when item is realized (became visible).
+                * @brief Called when item is realized (its content is created).
                 */
                virtual void onRealized() { }
 
                /**
-                * @brief Called when item is unrealized (became invisible)
-                *        and its text and content is deleted until it is realized again.
+                * @brief Called when item is unrealized and its text and content are
+                *        deleted until it is realized again.
                 */
                virtual void onUnrealized() { }
 
@@ -230,8 +240,11 @@ namespace Ui
                virtual void onFocused() { }
 
        private:
+               void updateVisibility();
+
                friend class GenContainer;
                void onInserted(Elm_Object_Item *item);
+               Eina_Bool onFiltered(Evas_Object *parent, void *filter);
                void onDestroy(Evas_Object *genlist);
 
                void onSelected(Elm_Object_Item *item);
@@ -241,7 +254,9 @@ namespace Ui
 
                Elm_Object_Item *m_Item;
                bool m_Preserve;
+               bool m_IsMatching;
                bool m_IsRealized;
+               bool m_IsVisible;
                bool m_IsFocusPending;
                bool m_IsLongpressed;
 
index a675f7a..447124a 100644 (file)
@@ -86,6 +86,11 @@ namespace Ux
                virtual Evas_Object *getContent(Evas_Object *parent, const char *part) override;
 
                /**
+                * @GenItem::onVisibilityChanged()
+                */
+               virtual void onVisibilityChanged(bool isVisible) override;
+
+               /**
                 * @see GenItem::onSelected()
                 */
                virtual void onSelected() override;
index 6b4ed83..681daa5 100644 (file)
@@ -60,12 +60,12 @@ namespace Ux
 
                /**
                 * @brief Called when item's "checked" state changed in #SelectMulti mode.
-                * @param[in]   item        Changed item
-                * @param[in]   isChecked   Whether item is checked
-                * @param[in]   isSelectAll Whether item is being checked via "Select All"
+                * @param[in]   item            Changed item
+                * @param[in]   isChecked       Whether item is checked
+                * @param[in]   isMultiChecked  Whether item is being checked via "Select All"
                 * @return Whether item's state should be changed.
                 */
-               typedef std::function<bool(SelectItem *item, bool isChecked, bool isSelectAll)> CheckCallback;
+               typedef std::function<bool(SelectItem *item, bool isChecked, bool isMultiChecked)> CheckCallback;
 
                /**
                 * @brief Called when selection limit is reached.
@@ -209,6 +209,7 @@ namespace Ux
                };
 
                size_t getSelectMax() const;
+               bool isLimitReached() const;
                bool isMaxSelected() const;
 
                void updatePageTitle();
@@ -218,13 +219,17 @@ namespace Ux
                void updateDoneButtonState();
                void updateSelectAllState();
 
-               void updateSelectCount(CountChange change, SelectItem *item);
-               void updateItemCount(CountChange change, SelectItem *item);
+               void updateTotalCount(CountChange change, SelectItem *item);
+               void updateTotalSelectCount(CountChange change, SelectItem *item);
+
+               void updateVisibleCount(CountChange change, SelectItem *item);
+               void updateVisibleSelectCount(CountChange change, SelectItem *item);
 
                void createPageButtons(Ui::NavigatorPage *page);
                void destroyPageButtons();
 
                void onItemExcluded(SelectItem *item, bool isExcluded);
+               void onItemVisibilityChanged(SelectItem *item, bool isVisible);
                void onItemSelected(SelectItem *item);
                bool onItemChecked(SelectItem *item, bool isChecked);
                bool onSelectAllChecked(bool isChecked);
@@ -239,9 +244,11 @@ namespace Ux
                Evas_Object *m_DoneButton;
                Evas_Object *m_CancelButton;
 
-               bool m_IsChecking;
+               bool m_IsMultiChecking;
                size_t m_TotalCount;
-               size_t m_SelectCount;
+               size_t m_TotalSelectCount;
+               size_t m_VisibleCount;
+               size_t m_VisibleSelectCount;
                size_t m_SelectLimit;
                bool m_IsEmptyResultAllowed;
 
index 91c2c58..888a2a2 100644 (file)
@@ -59,7 +59,8 @@ namespace
 
 GenItem::GenItem(GenContainer::Type type)
        : m_Item(nullptr), m_Preserve(false),
-         m_IsRealized(false), m_IsFocusPending(false), m_IsLongpressed(false),
+         m_IsMatching(true), m_IsRealized(false), m_IsVisible(false),
+         m_IsFocusPending(false), m_IsLongpressed(false),
          m_Api(&api[type])
 {
 }
@@ -85,6 +86,11 @@ bool GenItem::isInserted() const
        return m_Item != nullptr;
 }
 
+bool GenItem::isVisible() const
+{
+       return m_IsVisible;
+}
+
 Elm_Object_Item *GenItem::getObjectItem() const
 {
        return m_Item;
@@ -174,7 +180,7 @@ Elm_Gen_Item_Class GenItem::createItemClass(const char *style,
        itc.func.text_get = makeCallback(&GenItem::getText);
        itc.func.content_get = makeCallback(&GenItem::getContent);
        itc.func.state_get = makeCallback(&GenItem::getState);
-       itc.func.filter_get = makeCallback(&GenItem::compare);
+       itc.func.filter_get = makeCallback(&GenItem::onFiltered);
        itc.func.del = makeCallback(&GenItem::onDestroy);
 
        return itc;
@@ -186,10 +192,27 @@ Elm_Gen_Item_Class *GenItem::getItemClass() const
        return &itc;
 }
 
+void GenItem::updateVisibility()
+{
+       bool isVisible = isInserted() && m_IsMatching;
+       if (m_IsVisible != isVisible) {
+               m_IsVisible = isVisible;
+               onVisibilityChanged(m_IsVisible);
+       }
+}
+
 void GenItem::onInserted(Elm_Object_Item *item)
 {
        m_Item = item;
        onInserted();
+       updateVisibility();
+}
+
+Eina_Bool GenItem::onFiltered(Evas_Object *parent, void *filter)
+{
+       m_IsMatching = compare(filter);
+       updateVisibility();
+       return m_IsMatching;
 }
 
 void GenItem::onDestroy(Evas_Object *genlist)
@@ -197,6 +220,9 @@ void GenItem::onDestroy(Evas_Object *genlist)
        m_Item = nullptr;
        if (!m_Preserve) {
                delete this;
+       } else {
+               m_IsMatching = true;
+               updateVisibility();
        }
 }
 
@@ -228,8 +254,8 @@ void GenItem::onRealized(Elm_Object_Item *item)
 
        m_IsRealized = true;
        if (m_IsFocusPending) {
-               onFocused();
                m_IsFocusPending = false;
+               onFocused();
        }
 
        onRealized();
index b2e0e2f..ef1109d 100644 (file)
@@ -90,6 +90,13 @@ Evas_Object *SelectItem::getContent(Evas_Object *parent, const char *part)
        return nullptr;
 }
 
+void SelectItem::onVisibilityChanged(bool isVisible)
+{
+       if (m_SelectView && !m_IsExcluded) {
+               return m_SelectView->onItemVisibilityChanged(this, isVisible);
+       }
+}
+
 void SelectItem::onSelected()
 {
        if (m_SelectMode == SelectSingle) {
index 3e606ed..535c1da 100644 (file)
@@ -32,9 +32,11 @@ using namespace Ux;
 using namespace std::placeholders;
 
 SelectView::SelectView()
-       : m_DoneButton(nullptr), m_CancelButton(nullptr), m_IsChecking(false),
-         m_TotalCount(0), m_SelectCount(0), m_SelectLimit(0), m_IsEmptyResultAllowed(false),
-         m_SelectMode(SelectNone), m_Strings{ nullptr }
+       : m_DoneButton(nullptr), m_CancelButton(nullptr), m_IsMultiChecking(false),
+         m_TotalCount(0), m_TotalSelectCount(0),
+         m_VisibleCount(0), m_VisibleSelectCount(0),
+         m_SelectLimit(0), m_IsEmptyResultAllowed(false), m_SelectMode(SelectNone),
+         m_Strings{ nullptr }
 {
 }
 
@@ -57,7 +59,7 @@ size_t SelectView::getSelectLimit() const
 
 size_t SelectView::getSelectCount() const
 {
-       return m_SelectCount;
+       return m_TotalSelectCount;
 }
 
 const SelectView::SelectItems &SelectView::getSelectItems() const
@@ -93,14 +95,14 @@ void SelectView::setSelectLimit(size_t selectLimit)
                m_SelectLimit = selectLimit;
 
                if (m_SelectLimit) {
-                       m_IsChecking = true;
-                       for (size_t i = m_Items.size() - 1; m_SelectCount > m_SelectLimit; --i) {
+                       m_IsMultiChecking = true;
+                       for (size_t i = m_Items.size() - 1; m_TotalSelectCount > m_SelectLimit; --i) {
                                if (!m_Items[i]->isExcluded()) {
                                        m_Items[i]->setChecked(false);
                                }
                        }
 
-                       m_IsChecking = false;
+                       m_IsMultiChecking = false;
                }
 
                updateSelectAllState();
@@ -146,7 +148,7 @@ void SelectView::addSelectItem(SelectItem *item)
        m_Items.push_back(item);
 
        if (!item->isExcluded()) {
-               updateItemCount(CountIncrement, item);
+               updateTotalCount(CountIncrement, item);
        }
 }
 
@@ -159,7 +161,7 @@ void SelectView::removeSelectItem(SelectItem *item)
 
        m_Items.erase(it);
        if (!item->isExcluded()) {
-               updateItemCount(CountDecrement, item);
+               updateTotalCount(CountDecrement, item);
        }
        item->m_SelectView = nullptr;
 }
@@ -183,16 +185,21 @@ bool SelectView::onBackPressed()
 
 size_t SelectView::getSelectMax() const
 {
-       if (m_SelectLimit && m_SelectLimit < m_TotalCount) {
+       if (m_SelectLimit && m_SelectLimit < m_VisibleCount) {
                return m_SelectLimit;
        }
 
-       return m_TotalCount;
+       return m_VisibleCount;
+}
+
+bool SelectView::isLimitReached() const
+{
+       return m_SelectLimit && m_TotalSelectCount == m_SelectLimit;
 }
 
 bool SelectView::isMaxSelected() const
 {
-       return m_SelectCount == getSelectMax();
+       return m_VisibleSelectCount == getSelectMax();
 }
 
 void SelectView::updatePageTitle()
@@ -214,10 +221,10 @@ void SelectView::updatePageTitle()
                        break;
                case SelectMulti:
                        if (m_SelectLimit) {
-                               snprintf(buffer, sizeof(buffer), _(m_Strings.titleWithLimit), m_SelectCount, m_SelectLimit);
+                               snprintf(buffer, sizeof(buffer), _(m_Strings.titleWithLimit), m_TotalSelectCount, m_SelectLimit);
                                title = buffer;
-                       } else if (m_SelectCount) {
-                               snprintf(buffer, sizeof(buffer), _(m_Strings.titleWithCount), m_SelectCount);
+                       } else if (m_TotalSelectCount) {
+                               snprintf(buffer, sizeof(buffer), _(m_Strings.titleWithCount), m_TotalSelectCount);
                                title = buffer;
                        } else {
                                title = m_Strings.titleMulti;
@@ -254,7 +261,7 @@ void SelectView::updatePageButtons()
 
 void SelectView::updateSelectAllItem()
 {
-       if (m_SelectMode == SelectMulti && m_TotalCount) {
+       if (m_SelectMode == SelectMulti && m_VisibleCount) {
                if (m_SelectAllItem.expired()) {
                        SelectAllItem *item = new SelectAllItem(m_Strings.selectAll);
                        item->setCheckCallback(std::bind(&SelectView::onSelectAllChecked, this, _1));
@@ -274,7 +281,7 @@ void SelectView::updateSelectAllItem()
 void SelectView::updateDoneButtonState()
 {
        elm_object_disabled_set(m_DoneButton,
-                       m_IsEmptyResultAllowed ? m_TotalCount == 0 : m_SelectCount == 0);
+                       m_IsEmptyResultAllowed ? m_TotalCount == 0 : m_TotalSelectCount == 0);
 }
 
 void SelectView::updateSelectAllState()
@@ -285,52 +292,50 @@ void SelectView::updateSelectAllState()
        }
 }
 
-void SelectView::updateSelectCount(CountChange change, SelectItem *item)
+void SelectView::updateTotalCount(CountChange change, SelectItem *item)
 {
-       /* CURRENT count if incremented, PREVIOUS count otherwise */
-       size_t checkCount = (change == CountIncrement) ? ++m_SelectCount : m_SelectCount--;
-       onSelectCountChanged(m_SelectCount);
+       (change == CountIncrement) ? ++m_TotalCount : --m_TotalCount;
 
-       if (m_SelectLimit && m_SelectCount > m_SelectLimit) {
-               item->setChecked(false);
-               return;
+       if (item->isChecked()) {
+               updateTotalSelectCount(change, item);
        }
+       if (item->isVisible()) {
+               updateVisibleCount(change, item);
+       }
+}
 
-       /* Prevent updating if multiple checking is in progress */
-       if (m_IsChecking) {
+void SelectView::updateTotalSelectCount(CountChange change, SelectItem *item)
+{
+       (change == CountIncrement) ? ++m_TotalSelectCount : --m_TotalSelectCount;
+       onSelectCountChanged(m_TotalSelectCount);
+
+       if (m_SelectLimit && m_TotalSelectCount > m_SelectLimit) {
+               item->setChecked(false);
                return;
        }
 
-       /* m_SelectCount: (all - 1) -> all or all -> (all - 1) */
-       if (checkCount == getSelectMax()) {
-               updateSelectAllState();
-       }
-       /* m_SelectCount: 0 -> 1 or 1 -> 0 */
-       if (checkCount == 1) {
-               updateDoneButtonState();
+       updateDoneButtonState();
+       /* Prevent updating if multiple checking is in progress (performance optimization) */
+       if (!m_IsMultiChecking) {
+               updatePageTitle();
        }
-
-       updatePageTitle();
 }
 
-void SelectView::updateItemCount(CountChange change, SelectItem *item)
+void SelectView::updateVisibleCount(CountChange change, SelectItem *item)
 {
-       /* PREVIOUS count if incremented, CURRENT count otherwise */
-       size_t checkCount = (change == CountIncrement) ? m_TotalCount++ : --m_TotalCount;
+       (change == CountIncrement) ? ++m_VisibleCount : --m_VisibleCount;
 
        if (item->isChecked()) {
-               updateSelectCount(change, item);
+               updateVisibleSelectCount(change, item);
        }
 
-       /* (all checked -> unchecked inserted) or (one unchecked -> unchecked removed) */
-       if (checkCount == m_SelectCount) {
-               updateSelectAllState();
-       }
-       /* m_TotalCount: 0 -> 1 or 1 -> 0 */
-       if (checkCount == 0) {
-               updateDoneButtonState();
-               updateSelectAllItem();
-       }
+       updateSelectAllItem();
+}
+
+void SelectView::updateVisibleSelectCount(CountChange change, SelectItem *item)
+{
+       (change == CountIncrement) ? ++m_VisibleSelectCount : --m_VisibleSelectCount;
+       updateSelectAllState();
 }
 
 void SelectView::createPageButtons(Ui::NavigatorPage *page)
@@ -353,7 +358,12 @@ void SelectView::destroyPageButtons()
 
 void SelectView::onItemExcluded(SelectItem *item, bool isExcluded)
 {
-       updateItemCount(isExcluded ? CountDecrement : CountIncrement, item);
+       updateTotalCount(isExcluded ? CountDecrement : CountIncrement, item);
+}
+
+void SelectView::onItemVisibilityChanged(SelectItem *item, bool isVisible)
+{
+       updateVisibleCount(isVisible ? CountIncrement : CountDecrement, item);
 }
 
 void SelectView::onItemSelected(SelectItem *item)
@@ -368,16 +378,20 @@ void SelectView::onItemSelected(SelectItem *item)
 
 bool SelectView::onItemChecked(SelectItem *item, bool isChecked)
 {
-       if (isChecked && isMaxSelected()) {
+       if (isChecked && isLimitReached()) {
                onLimitReached();
                return false;
        }
 
-       if (m_OnChecked && !m_OnChecked(item, isChecked, m_IsChecking)) {
+       if (m_OnChecked && !m_OnChecked(item, isChecked, m_IsMultiChecking)) {
                return false;
        }
 
-       updateSelectCount(isChecked ? CountIncrement : CountDecrement, item);
+       CountChange change = isChecked ? CountIncrement : CountDecrement;
+       updateTotalSelectCount(change, item);
+       if (item->isVisible()) {
+               updateVisibleSelectCount(change, item);
+       }
        return true;
 }
 
@@ -387,18 +401,17 @@ bool SelectView::onSelectAllChecked(bool isChecked)
                return true;
        }
 
-       m_IsChecking = true;
+       m_IsMultiChecking = true;
        for (auto &&item : m_Items) {
-               if (!item->isExcluded()) {
+               if (!item->isExcluded() && item->isVisible()) {
                        if (!item->setChecked(isChecked)) {
                                break;
                        }
                }
        }
 
-       m_IsChecking = false;
+       m_IsMultiChecking = false;
        updatePageTitle();
-       updateDoneButtonState();
        return isChecked == isMaxSelected();
 }
 
index ff37aac..fd28d5f 100644 (file)
@@ -57,7 +57,7 @@ namespace Contacts
 
                private:
                        virtual char *getText(Evas_Object *parent, const char *part) override;
-                       virtual Eina_Bool compare(Evas_Object *parent, void *filter) override;
+                       virtual bool compare(void *filter) override;
 
                        Utils::UniString m_Title;
                        Elm_Object_Item *m_IndexItem;
index 526d154..e824509 100644 (file)
@@ -40,7 +40,7 @@ namespace Contacts
 
                private:
                        virtual char *getText(Evas_Object *parent, const char *part) override;
-                       virtual Eina_Bool compare(Evas_Object *parent, void *filter) override;
+                       virtual bool compare(void *filter) override;
 
                        std::string getHighlightedStr() const;
                        void onSearchDataChanged();
index 322fa57..34c9ead 100644 (file)
@@ -289,7 +289,6 @@ void PersonProvider::updatePersonList()
                                int personId = getPersonId(contactId);
                                contacts_record_h personRecord = getPersonRecord(personId, PersonId);
                                auto personIt = findPerson(personId, PersonId);
-
                                if (personIt != m_PersonList.end()) {
                                        updatePerson(personIt, personRecord, contactId);
                                } else {
index 72ff9d6..61f3e8e 100644 (file)
@@ -56,7 +56,7 @@ char *PersonGroupItem::getText(Evas_Object *parent, const char *part)
        return nullptr;
 }
 
-Eina_Bool PersonGroupItem::compare(Evas_Object *parent, void *filter)
+bool PersonGroupItem::compare(void *filter)
 {
        return !(filter && *(const char *) filter);
 }
index cfe5d98..0a512ec 100644 (file)
@@ -68,7 +68,7 @@ char *PersonSearchItem::getText(Evas_Object *parent, const char *part)
        return PersonItem::getText(parent, part);
 }
 
-Eina_Bool PersonSearchItem::compare(Evas_Object *parent, void *filter)
+bool PersonSearchItem::compare(void *filter)
 {
        const char *str = (const char *) filter;
        if (str && *str) {