From: Sergei Kobec Date: Wed, 27 Jan 2016 12:31:22 +0000 (+0200) Subject: TizenRefApp-5537 Implement multi-pick mode X-Git-Tag: submit/tizen/20160524.113145~199 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=909f2802b7183a361fda70dc1872c44cac8134c3;p=profile%2Fmobile%2Fapps%2Fnative%2Fphone-contacts.git TizenRefApp-5537 Implement multi-pick mode Change-Id: I27849a8d56700118b9d9bc39dfd510e4f889f2f1 Signed-off-by: Sergei Kobec --- diff --git a/lib-contact/inc/Contacts/List/ListView.h b/lib-contact/inc/Contacts/List/ListView.h index 90d2da07..f5ad95ae 100644 --- a/lib-contact/inc/Contacts/List/ListView.h +++ b/lib-contact/inc/Contacts/List/ListView.h @@ -19,6 +19,7 @@ #define CONTACTS_LIST_LIST_VIEW_H #include "Contacts/List/Model/PersonProvider.h" +#include "Contacts/List/PersonItem.h" #include "Ui/View.h" #include "Utils/UniString.h" #include @@ -44,31 +45,83 @@ namespace Contacts class EXPORT_API ListView : public Ui::View { public: - ListView(); + /** + * @brief Represents view mode + */ + enum Mode + { + ModeDefault, + ModeMultipick, + ModeMax + }; + + /** + * @brief Create new person list view + * @param]in] personFilter Defines how to filter person list + */ + ListView(Model::PersonProvider::FilterType personFilter = + Model::PersonProvider::FilterNone); virtual ~ListView() override; + /** + * @brief Set view mode + * @details View can be in Default, SinglePick or Multipick mode + * @param[in] mode View mode + */ + void setMode(Mode mode); + private: - virtual Evas_Object *onCreate(Evas_Object *parent) override; - Evas_Object *createIndex(Evas_Object *parent); + enum SectionId + { + SectionFirst, + SectionSearch = SectionFirst, + SectionSelectAll, + SectionMyProfile, + SectionFavorites, + SectionMfc, + SectionPerson, + SectionMax + }; + virtual Evas_Object *onCreate(Evas_Object *parent) override; virtual void onPageAttached() override; virtual void onCreated() override; + virtual void onMenuPressed() override; void fillList(); + void fillSearchItem(); + void fillSelectAllItem(); void fillMyProfile(); + void fillFavorites(); + void fillMfc(); + void fillPersonList(); - void insertMyProfileGroupItem(); - Ui::GenlistGroupItem *getNextMyProfileGroupItem(); + void setFavouriteItemsMode(PersonItem::Mode mode); + void setPersonItemsMode(PersonItem::Mode mode); + + void addSection(SectionId sectionId); + void removeSection(SectionId sectionId); + Ui::GenlistGroupItem *getNextSectionItem(SectionId currentSection); + bool getSectionVisibility(Mode mode, SectionId sectionId); + + PersonItem::Mode getItemMode(Mode viewMode); + + void updateTitle(); + void createNewContactButton(); + void deleteNewContactButton(); + + void insertMyProfileGroupItem(); void updateMyProfileItem(const char *view_uri); + Evas_Object *createIndex(Evas_Object *parent); Elm_Index_Item *insertIndexItem(const char *indexLetter, Elm_Index_Item *nextItem = nullptr); - PersonGroupItem *insertGroupItem(Utils::UniString indexLetter, + PersonGroupItem *insertPersonGroupItem(Utils::UniString indexLetter, PersonGroupItem *nextGroup = nullptr); - void deleteGroupItem(PersonGroupItem *group); - PersonGroupItem *getNextGroupItem(const Utils::UniString &indexLetter); + void deletePersonGroupItem(PersonGroupItem *group); + PersonGroupItem *getNextPersonGroupItem(const Utils::UniString &indexLetter); PersonItem *createPersonItem(Model::PersonPtr person); void insertPersonItem(PersonItem *item); @@ -76,22 +129,30 @@ namespace Contacts void deletePersonItem(PersonItem *item); PersonItem *getNextPersonItem(PersonGroupItem *group, const Model::Person &person); + void launchPersonDetail(PersonItem *item); + void onIndexChanged(Evas_Object *index, Elm_Object_Item *indexItem); void onIndexSelected(Evas_Object *index, Elm_Object_Item *indexItem); void onCreatePressed(); - virtual void onMenuPressed() override; void onPersonInserted(Model::PersonPtr person); void onPersonChanged(Model::PersonPtr person, contacts_changed_e changeType, PersonItem *item); + void onItemChecked(PersonItem *item); + Ui::Genlist *m_Genlist; Evas_Object *m_Index; - GroupItem *m_MyProfileGroup; - std::map m_Groups; + Ui::GenlistGroupItem *m_Sections[SectionMax]; + std::map m_PersonGroups; Model::PersonProvider m_Provider; + + Mode m_ViewMode; + + size_t m_PersonCount; + size_t m_CheckedCount; }; } } diff --git a/lib-contact/inc/Contacts/List/PersonItem.h b/lib-contact/inc/Contacts/List/PersonItem.h index d11132eb..2c82557a 100644 --- a/lib-contact/inc/Contacts/List/PersonItem.h +++ b/lib-contact/inc/Contacts/List/PersonItem.h @@ -44,9 +44,10 @@ namespace Contacts /** * @brief Represents item mode */ - enum ItemMode { - DefaultMode, /*< Usual mode */ - PickMode /*< Mode with ability to select item */ + enum Mode + { + ModeDefault, /*< Usual mode */ + ModePick /*< Mode with ability to select item */ }; /** @@ -54,13 +55,13 @@ namespace Contacts * @param[in] person Person object * @param[in] mode Item mode */ - explicit PersonItem(Model::PersonPtr person, ItemMode mode = DefaultMode); + explicit PersonItem(Model::PersonPtr person, Mode mode = ModeDefault); /** * @brief Set item mode * @param[in] mode Item mode */ - void setMode(ItemMode mode); + void setMode(Mode mode); /** * @remark Used in item pick mode @@ -96,7 +97,7 @@ namespace Contacts Model::PersonPtr m_Person; - ItemMode m_ItemMode; + Mode m_ItemMode; bool m_Checked; SelectedCallback m_OnSelected; diff --git a/lib-contact/src/Contacts/List/ListView.cpp b/lib-contact/src/Contacts/List/ListView.cpp index ee4f9896..17289f01 100644 --- a/lib-contact/src/Contacts/List/ListView.cpp +++ b/lib-contact/src/Contacts/List/ListView.cpp @@ -18,7 +18,6 @@ #include "Contacts/List/ListView.h" #include "Contacts/List/GroupItem.h" #include "Contacts/List/MyProfileItem.h" -#include "Contacts/List/PersonItem.h" #include "Contacts/List/PersonGroupItem.h" #include "Contacts/Input/InputView.h" #include "Contacts/Settings/MainView.h" @@ -28,16 +27,23 @@ #include "Ui/Menu.h" #include "Ui/Navigator.h" #include "Utils/Callback.h" -#include "Utils/Logger.h" + +#include +#include + +#define TITLE_SIZE 32 using namespace Contacts; using namespace Contacts::List; using namespace Contacts::List::Model; using namespace Utils; -ListView::ListView() +ListView::ListView(PersonProvider::FilterType personFilter) : m_Genlist(nullptr), m_Index(nullptr), - m_Provider(PersonProvider(PersonProvider::FilterNone)) + m_Sections{ nullptr }, + m_Provider(PersonProvider(personFilter)), + m_ViewMode(ModeDefault), + m_PersonCount(0), m_CheckedCount(0) { } @@ -48,6 +54,29 @@ ListView::~ListView() makeCallbackWithLastParam(&ListView::updateMyProfileItem), this); } +void ListView::setMode(Mode mode) +{ + if (m_ViewMode != mode) { + m_ViewMode = mode; + + updateTitle(); + + for (size_t i = SectionFirst; i < SectionMax; ++i) { + if (getSectionVisibility(mode, static_cast(i))) { + addSection(static_cast(i)); + } else { + removeSection(static_cast(i)); + } + } + + if (mode == ModeDefault) { + createNewContactButton(); + } else { + deleteNewContactButton(); + } + } +} + Evas_Object *ListView::onCreate(Evas_Object *parent) { Evas_Object *layout = elm_layout_add(parent); @@ -60,30 +89,10 @@ Evas_Object *ListView::onCreate(Evas_Object *parent) return layout; } -Evas_Object *ListView::createIndex(Evas_Object *parent) -{ - m_Index = elm_index_add(parent); - elm_index_autohide_disabled_set(m_Index, EINA_TRUE); - elm_index_omit_enabled_set(m_Index, EINA_TRUE); - - evas_object_smart_callback_add(m_Index, "changed", - (Evas_Smart_Cb) makeCallback(&ListView::onIndexChanged), this); - evas_object_smart_callback_add(m_Index, "selected", - (Evas_Smart_Cb) makeCallback(&ListView::onIndexSelected), this); - - return m_Index; -} - void ListView::onPageAttached() { - Evas_Object *button = elm_button_add(getEvasObject()); - elm_object_style_set(button, "bottom"); - elm_object_translatable_text_set(button, "IDS_PB_OPT_CREATE"); - evas_object_smart_callback_add(button, "clicked", - (Evas_Smart_Cb) makeCallback(&ListView::onCreatePressed), this); - - getPage()->setTitle("IDS_PB_TAB_CONTACTS"); - getPage()->setContent("toolbar", button); + updateTitle(); + createNewContactButton(); } void ListView::onCreated() @@ -95,51 +104,211 @@ void ListView::onCreated() makeCallbackWithLastParam(&ListView::updateMyProfileItem), this); } -void ListView::fillList() +void ListView::onMenuPressed() { - fillMyProfile(); - - PersonList list = m_Provider.getPersonList(); - PersonGroupItem *group = nullptr; + Ui::Menu *menu = new Ui::Menu(); + menu->create(getEvasObject()); - for (auto &&person : list) { - const UniString &nextLetter = person->getIndexLetter(); + menu->addItem("IDS_LOGS_OPT_DELETE", [this] { + ListView *deleteView = new ListView(); + getNavigator()->navigateTo(deleteView); + deleteView->setMode(ModeMultipick); + }); - if (!group || group->getTitle() != nextLetter) { - group = insertGroupItem(nextLetter); - } + menu->addItem("IDS_PB_OPT_SETTINGS", [this] { + getNavigator()->navigateTo(new Settings::MainView()); + }); + menu->show(); +} - m_Genlist->insert(createPersonItem(std::move(person)), group); +void ListView::fillList() +{ + for (size_t i = SectionMyProfile; i < SectionMax; ++i) { + addSection(static_cast(i)); } } +void ListView::fillSearchItem() +{ + //Todo +} + +void ListView::fillSelectAllItem() +{ + //Todo +} + void ListView::fillMyProfile() { - if (!m_MyProfileGroup) { + if (!m_Sections[SectionMyProfile]) { insertMyProfileGroupItem(); } updateMyProfileItem(nullptr); } -void ListView::insertMyProfileGroupItem() +void ListView::fillFavorites() +{ + if (!m_Sections[SectionFavorites]) { + //Todo Create here Favorite group + } else { + setFavouriteItemsMode(getItemMode(m_ViewMode)); + } +} + +void ListView::fillMfc() +{ + //Todo +} + +void ListView::fillPersonList() +{ + if (m_PersonGroups.empty()) { + PersonList list = m_Provider.getPersonList(); + PersonGroupItem *group = nullptr; + + for (auto &&person : list) { + const UniString &nextLetter = person->getIndexLetter(); + + if (!group || group->getTitle() != nextLetter) { + group = insertPersonGroupItem(nextLetter); + } + + m_Genlist->insert(createPersonItem(std::move(person)), group); + + ++m_PersonCount; + } + } else { + setPersonItemsMode(getItemMode(m_ViewMode)); + } +} + +void ListView::setFavouriteItemsMode(PersonItem::Mode mode) +{ + if (m_Sections[SectionFavorites]) { + for (auto &&favoriteItem : *m_Sections[SectionFavorites]) { + static_cast(favoriteItem)->setMode(mode); + } + } +} + +void ListView::setPersonItemsMode(PersonItem::Mode mode) { - m_MyProfileGroup = new GroupItem("IDS_PB_HEADER_ME"); - m_Genlist->insert(m_MyProfileGroup, nullptr, getNextMyProfileGroupItem()); - elm_genlist_item_select_mode_set(m_MyProfileGroup->getObjectItem(), ELM_OBJECT_SELECT_MODE_NONE); + for (auto &&group : m_PersonGroups) { + for (auto &&personItem : *group.second) { + static_cast(personItem)->setMode(mode); + } + } } -Ui::GenlistGroupItem *ListView::getNextMyProfileGroupItem() +void ListView::addSection(SectionId sectionId) { - //Todo: Here will be search of next group item for My profile group item + switch (sectionId) { + case SectionSearch: fillSearchItem(); break; + case SectionSelectAll: fillSelectAllItem(); break; + case SectionMyProfile: fillMyProfile(); break; + case SectionFavorites: fillFavorites(); break; + case SectionMfc: fillMfc(); break; + case SectionPerson: fillPersonList(); break; + default: break; + } +} + +void ListView::removeSection(SectionId sectionId) +{ + delete m_Sections[sectionId]; + m_Sections[sectionId] = nullptr; +} + +Ui::GenlistGroupItem *ListView::getNextSectionItem(SectionId currentSection) +{ + for (size_t nextSection = currentSection + 1; nextSection < SectionMax; ++nextSection) { + if (m_Sections[nextSection]) { + return m_Sections[nextSection]; + } + } + return nullptr; } +bool ListView::getSectionVisibility(Mode mode, SectionId sectionId) +{ + static bool sectionVisibility[ListView::ModeMax][ListView::SectionMax] = { + /* ModeDefault = */ { + /* SectionSearch = */ true, + /* SectionSelectAll = */ false, + /* SectionMyProfile = */ true, + /* SectionFavorites = */ true, + /* SectionMfc = */ true, + /* SectionPerson = */ true + }, + /* ModeMultipick = */ { + /* SectionSearch = */ true, + /* SectionSelectAll = */ true, + /* SectionMyProfile = */ false, + /* SectionFavorites = */ true, + /* SectionMfc = */ false, + /* SectionPerson = */ true + } + }; + + return sectionVisibility[mode][sectionId]; +} + +PersonItem::Mode ListView::getItemMode(Mode viewMode) +{ + if (viewMode == ModeMultipick) { + return PersonItem::ModePick; + } else { + return PersonItem::ModeDefault; + } +} + +void ListView::updateTitle() +{ + switch (m_ViewMode) { + case ModeDefault: getPage()->setTitle("IDS_PB_TAB_CONTACTS"); break; + case ModeMultipick: { + char title[TITLE_SIZE]; + snprintf(title, TITLE_SIZE, _("IDS_PB_HEADER_PD_SELECTED_ABB"), m_CheckedCount); + + getPage()->setTitle(title); + break; + } + default: break; + } +} + +void ListView::createNewContactButton() +{ + Evas_Object *button = elm_button_add(getEvasObject()); + elm_object_style_set(button, "bottom"); + elm_object_translatable_text_set(button, "IDS_PB_OPT_CREATE"); + evas_object_smart_callback_add(button, "clicked", + (Evas_Smart_Cb) makeCallback(&ListView::onCreatePressed), this); + + getPage()->setContent("toolbar", button); +} + +void ListView::deleteNewContactButton() +{ + //Todo +} + +void ListView::insertMyProfileGroupItem() +{ + auto group = new GroupItem("IDS_PB_HEADER_ME"); + m_Genlist->insert(group, nullptr, getNextSectionItem(SectionMyProfile)); + elm_genlist_item_select_mode_set(group->getObjectItem(), ELM_OBJECT_SELECT_MODE_NONE); + + m_Sections[SectionMyProfile] = group; +} + void ListView::updateMyProfileItem(const char *view_uri) { - elm_genlist_item_subitems_clear(m_MyProfileGroup->getObjectItem()); + elm_genlist_item_subitems_clear(m_Sections[SectionMyProfile]->getObjectItem()); MyProfileItem *item = new MyProfileItem(MyProfilePtr(new MyProfile())); - m_Genlist->insert(item, m_MyProfileGroup); + m_Genlist->insert(item, m_Sections[SectionMyProfile]); item->setSelectedCallback([this, item]() { int id = item->getMyProfile().getId(); @@ -147,6 +316,20 @@ void ListView::updateMyProfileItem(const char *view_uri) }); } +Evas_Object *ListView::createIndex(Evas_Object *parent) +{ + m_Index = elm_index_add(parent); + elm_index_autohide_disabled_set(m_Index, EINA_TRUE); + elm_index_omit_enabled_set(m_Index, EINA_TRUE); + + evas_object_smart_callback_add(m_Index, "changed", + (Evas_Smart_Cb) makeCallback(&ListView::onIndexChanged), this); + evas_object_smart_callback_add(m_Index, "selected", + (Evas_Smart_Cb) makeCallback(&ListView::onIndexSelected), this); + + return m_Index; +} + Elm_Object_Item *ListView::insertIndexItem(const char *indexLetter, Elm_Object_Item *nextItem) { Elm_Object_Item *indexItem = nullptr; @@ -161,7 +344,7 @@ Elm_Object_Item *ListView::insertIndexItem(const char *indexLetter, Elm_Object_I return indexItem; } -PersonGroupItem *ListView::insertGroupItem(UniString indexLetter, PersonGroupItem *nextGroup) +PersonGroupItem *ListView::insertPersonGroupItem(UniString indexLetter, PersonGroupItem *nextGroup) { Elm_Object_Item *indexItem = insertIndexItem(indexLetter.getUtf8Str().c_str(), nextGroup ? nextGroup->getIndexItem() : nullptr); @@ -171,24 +354,26 @@ PersonGroupItem *ListView::insertGroupItem(UniString indexLetter, PersonGroupIte elm_genlist_item_select_mode_set(item->getObjectItem(), ELM_OBJECT_SELECT_MODE_NONE); elm_object_item_data_set(indexItem, item->getObjectItem()); - m_Groups.insert({ item->getTitle(), item }); + m_PersonGroups.insert({ item->getTitle(), item }); + m_Sections[SectionPerson] = m_PersonGroups.begin()->second; return item; } -void ListView::deleteGroupItem(PersonGroupItem *group) +void ListView::deletePersonGroupItem(PersonGroupItem *group) { elm_object_item_del(group->getIndexItem()); elm_index_level_go(m_Index, 0); - m_Groups.erase(group->getTitle()); + m_PersonGroups.erase(group->getTitle()); + m_Sections[SectionPerson] = !m_PersonGroups.empty() ? m_PersonGroups.begin()->second : nullptr; delete group; } -PersonGroupItem *ListView::getNextGroupItem(const Utils::UniString &indexLetter) +PersonGroupItem *ListView::getNextPersonGroupItem(const Utils::UniString &indexLetter) { - auto it = m_Groups.lower_bound(indexLetter); - if (it != m_Groups.end()) { + auto it = m_PersonGroups.lower_bound(indexLetter); + if (it != m_PersonGroups.end()) { return it->second; } @@ -199,16 +384,17 @@ PersonItem *ListView::createPersonItem(PersonPtr person) { using namespace std::placeholders; - PersonItem *item = new PersonItem(std::move(person)); + PersonItem *item = new PersonItem(std::move(person), getItemMode(m_ViewMode)); m_Provider.setChangeCallback(item->getPerson(), std::bind(&ListView::onPersonChanged, this, _1, _2, item)); item->setSelectedCallback([this, item]() { - int id = 0; - contacts_record_get_int(item->getPerson().getRecord(), _contacts_person.display_contact_id, &id); - - getNavigator()->navigateTo(new Input::InputView(id)); + switch (m_ViewMode) { + case ModeDefault: launchPersonDetail(item); break; + case ModeMultipick: onItemChecked(item); break; + default: break; + } }); return item; @@ -220,16 +406,18 @@ void ListView::insertPersonItem(PersonItem *item) PersonItem *nextItem = nullptr; const UniString &indexLetter = item->getPerson().getIndexLetter(); - auto it = m_Groups.find(indexLetter); - if (it != m_Groups.end()) { + auto it = m_PersonGroups.find(indexLetter); + if (it != m_PersonGroups.end()) { group = it->second; nextItem = getNextPersonItem(it->second, item->getPerson()); } else { - PersonGroupItem *nextGroup = getNextGroupItem(indexLetter); - group = insertGroupItem(indexLetter, nextGroup); + PersonGroupItem *nextGroup = getNextPersonGroupItem(indexLetter); + group = insertPersonGroupItem(indexLetter, nextGroup); } m_Genlist->insert(item, group, nextItem); + + ++m_PersonCount; } void ListView::updatePersonItem(PersonItem *item, Model::PersonPtr person) @@ -243,7 +431,7 @@ void ListView::updatePersonItem(PersonItem *item, Model::PersonPtr person) insertPersonItem(item); if (oldGroup->empty()) { - deleteGroupItem(oldGroup); + deletePersonGroupItem(oldGroup); } } else { const char *oldImagePath = item->getPerson().getImagePath(); @@ -266,8 +454,10 @@ void ListView::deletePersonItem(PersonItem *item) m_Provider.unsetChangeCallback(item->getPerson()); delete item; + --m_PersonCount; + if (oldGroup->empty()) { - deleteGroupItem(oldGroup); + deletePersonGroupItem(oldGroup); } } @@ -283,6 +473,14 @@ PersonItem *ListView::getNextPersonItem(PersonGroupItem *group, const Person &pe return nullptr; } +void ListView::launchPersonDetail(PersonItem *item) +{ + int id = 0; + contacts_record_get_int(item->getPerson().getRecord(), _contacts_person.display_contact_id, &id); + + getNavigator()->navigateTo(new Input::InputView(id)); +} + void ListView::onIndexChanged(Evas_Object *index, Elm_Object_Item *indexItem) { Elm_Object_Item *genlistItem = (Elm_Object_Item *) elm_object_item_data_get(indexItem); @@ -300,17 +498,6 @@ void ListView::onCreatePressed() getNavigator()->navigateTo(new Input::InputView()); } -void ListView::onMenuPressed() -{ - Ui::Menu *menu = new Ui::Menu(); - menu->create(getEvasObject()); - - menu->addItem("IDS_PB_OPT_SETTINGS", [this] { - getNavigator()->navigateTo(new Settings::MainView()); - }); - menu->show(); -} - void ListView::onPersonInserted(PersonPtr person) { insertPersonItem(createPersonItem(std::move(person))); @@ -324,3 +511,11 @@ void ListView::onPersonChanged(PersonPtr person, contacts_changed_e changeType, updatePersonItem(item, std::move(person)); } } + +void ListView::onItemChecked(PersonItem *item) +{ + item->isChecked() ? ++m_CheckedCount : --m_CheckedCount; + updateTitle(); + + //Todo: Make "Select all" calculations +} diff --git a/lib-contact/src/Contacts/List/PersonItem.cpp b/lib-contact/src/Contacts/List/PersonItem.cpp index b17554f3..8ccf78c6 100644 --- a/lib-contact/src/Contacts/List/PersonItem.cpp +++ b/lib-contact/src/Contacts/List/PersonItem.cpp @@ -22,11 +22,11 @@ using namespace Contacts::List; using namespace Contacts::List::Model; -PersonItem::PersonItem(PersonPtr person, ItemMode mode) +PersonItem::PersonItem(PersonPtr person, Mode mode) : m_Person(std::move(person)), m_ItemMode(mode), m_Checked(false) { } -void PersonItem::setMode(ItemMode mode) +void PersonItem::setMode(Mode mode) { m_ItemMode = mode; elm_genlist_item_fields_update(getObjectItem(), PART_CHECK, ELM_GENLIST_ITEM_FIELD_CONTENT); @@ -54,7 +54,7 @@ void PersonItem::setSelectedCallback(SelectedCallback callback) void PersonItem::onSelected() { - if (m_ItemMode == PickMode) { + if (m_ItemMode == ModePick) { m_Checked = !m_Checked; elm_check_state_set(getCheck(), m_Checked); } @@ -88,7 +88,7 @@ Evas_Object *PersonItem::getContent(Evas_Object *parent, const char *part) m_Person->getImagePath()); thumbnail->setSizeHint(true); return thumbnail->getEvasObject(); - } else if (m_ItemMode == PickMode && strcmp(part, PART_CHECK) == 0) { + } else if (m_ItemMode == ModePick && strcmp(part, PART_CHECK) == 0) { Elm_Check *check = elm_check_add(parent); elm_check_state_set(check, m_Checked); return check;