From: Eugene Kurzberg Date: Mon, 5 Sep 2016 12:56:40 +0000 (+0300) Subject: TizenRefApp-7059 Update Select All item behavior in the Select View during Search X-Git-Tag: submit/tizen/20160909.115235~1^2~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F33%2F86833%2F4;p=profile%2Fmobile%2Fapps%2Fnative%2Fphone-contacts.git TizenRefApp-7059 Update Select All item behavior in the Select View during Search [Implementation] Implemented GenItem visibility tracking. Simplified count update in SelectView. Implemented visible items counting. Change-Id: Iae02386130af9305190a2891bf45931c18d5a23d Signed-off-by: Eugene Kurzberg --- diff --git a/lib-apps-common/inc/Ui/GenItem.h b/lib-apps-common/inc/Ui/GenItem.h index 7998023..5b21db6 100644 --- a/lib-apps-common/inc/Ui/GenItem.h +++ b/lib-apps-common/inc/Ui/GenItem.h @@ -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; diff --git a/lib-apps-common/inc/Ux/SelectItem.h b/lib-apps-common/inc/Ux/SelectItem.h index a675f7a..447124a 100644 --- a/lib-apps-common/inc/Ux/SelectItem.h +++ b/lib-apps-common/inc/Ux/SelectItem.h @@ -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; diff --git a/lib-apps-common/inc/Ux/SelectView.h b/lib-apps-common/inc/Ux/SelectView.h index 6b4ed83..681daa5 100644 --- a/lib-apps-common/inc/Ux/SelectView.h +++ b/lib-apps-common/inc/Ux/SelectView.h @@ -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 CheckCallback; + typedef std::function 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; diff --git a/lib-apps-common/src/Ui/GenItem.cpp b/lib-apps-common/src/Ui/GenItem.cpp index 91c2c58..888a2a2 100644 --- a/lib-apps-common/src/Ui/GenItem.cpp +++ b/lib-apps-common/src/Ui/GenItem.cpp @@ -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(); diff --git a/lib-apps-common/src/Ux/SelectItem.cpp b/lib-apps-common/src/Ux/SelectItem.cpp index b2e0e2f..ef1109d 100644 --- a/lib-apps-common/src/Ux/SelectItem.cpp +++ b/lib-apps-common/src/Ux/SelectItem.cpp @@ -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) { diff --git a/lib-apps-common/src/Ux/SelectView.cpp b/lib-apps-common/src/Ux/SelectView.cpp index 3e606ed..535c1da 100644 --- a/lib-apps-common/src/Ux/SelectView.cpp +++ b/lib-apps-common/src/Ux/SelectView.cpp @@ -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(); } diff --git a/lib-contacts/inc/Contacts/List/PersonGroupItem.h b/lib-contacts/inc/Contacts/List/PersonGroupItem.h index ff37aac..fd28d5f 100644 --- a/lib-contacts/inc/Contacts/List/PersonGroupItem.h +++ b/lib-contacts/inc/Contacts/List/PersonGroupItem.h @@ -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; diff --git a/lib-contacts/inc/Contacts/List/PersonSearchItem.h b/lib-contacts/inc/Contacts/List/PersonSearchItem.h index 526d154..e824509 100644 --- a/lib-contacts/inc/Contacts/List/PersonSearchItem.h +++ b/lib-contacts/inc/Contacts/List/PersonSearchItem.h @@ -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(); diff --git a/lib-contacts/src/Contacts/List/Model/PersonProvider.cpp b/lib-contacts/src/Contacts/List/Model/PersonProvider.cpp index 322fa57..34c9ead 100644 --- a/lib-contacts/src/Contacts/List/Model/PersonProvider.cpp +++ b/lib-contacts/src/Contacts/List/Model/PersonProvider.cpp @@ -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 { diff --git a/lib-contacts/src/Contacts/List/PersonGroupItem.cpp b/lib-contacts/src/Contacts/List/PersonGroupItem.cpp index 72ff9d6..61f3e8e 100644 --- a/lib-contacts/src/Contacts/List/PersonGroupItem.cpp +++ b/lib-contacts/src/Contacts/List/PersonGroupItem.cpp @@ -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); } diff --git a/lib-contacts/src/Contacts/List/PersonSearchItem.cpp b/lib-contacts/src/Contacts/List/PersonSearchItem.cpp index cfe5d98..0a512ec 100644 --- a/lib-contacts/src/Contacts/List/PersonSearchItem.cpp +++ b/lib-contacts/src/Contacts/List/PersonSearchItem.cpp @@ -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) {