void update(void *data);
/**
+ * @return Whether is standalone (not managed by DataProvider).
+ */
+ bool isStandalone() const;
+
+ /**
+ * @brief Set whether item is standalone or managed by DataProvider.
+ * @param[in] isStandalone Whether item is standalone
+ */
+ void setStandalone(bool isStandalone);
+
+ /**
* @brief Set update callback.
* @param[in] callback Update callback
*/
protected:
/**
- * @brief Mark item as updated without calling update().
- * @param[in] changes Which item data was updated
+ * @brief Mark item as changed with specified change type.
+ * @param[in] changeType Item change type
+ * @param[in] changes Which item data was updated if type is ChangeUpdate
+ */
+ void setChanged(ChangeType changeType, int changes = 0);
+
+ /**
+ * @brief Called after setStandalone() to change item standalone state.
+ * @param[in] isStandalone Whether item is standalone
*/
- void setUpdated(int changes);
+ virtual void onStandalone(bool isStandalone) { }
/**
* @brief Called after update() to update item data.
friend class DataProvider;
void onUpdated();
+ bool m_IsStandalone;
int m_Changes;
ChangeType m_ChangeType;
using namespace Model2;
DataItem::DataItem()
- : m_Changes(0), m_ChangeType(ChangeNone)
+ : m_IsStandalone(false), m_Changes(0), m_ChangeType(ChangeNone)
{
}
{
m_Changes |= onUpdate(data);
m_ChangeType = ChangeUpdate;
+
+ if (m_IsStandalone) {
+ onUpdated();
+ }
+}
+
+bool DataItem::isStandalone() const
+{
+ return m_IsStandalone;
+}
+
+void DataItem::setStandalone(bool isStandalone)
+{
+ if (m_IsStandalone != isStandalone) {
+ m_IsStandalone = isStandalone;
+ onStandalone(m_IsStandalone);
+ }
}
void DataItem::setUpdateCallback(UpdateCallback callback)
m_OnDeleted = std::move(callback);
}
-void DataItem::setUpdated(int changes)
+void DataItem::setChanged(ChangeType changeType, int changes)
{
if (m_ChangeType == ChangeNone) {
- m_ChangeType = ChangeUpdate;
+ m_ChangeType = changeType;
+ }
+ if (changeType == ChangeUpdate) {
+ m_Changes |= changes;
}
- m_Changes |= changes;
+ if (m_IsStandalone) {
+ onUpdated();
+ }
}
void DataItem::onUpdated()
public:
/**
* @brief Create members list view.
- * @param[in] id Group id
- * @param[in] provider Group provider
+ * @param[in] provider Group members provider
*/
- MembersListView(int id, Model::MembersProvider *provider);
+ MembersListView(Model::MembersProvider *provider);
private:
enum EditType {
virtual void onPageAttached(Ui::NavigatorPage *page) override;
virtual void onMenuPressed() override;
+ virtual void onInitialized() override;
virtual void onUpdateFinished() override;
- std::string getTitle() const;
+ void updateTitle();
void onAddSelected();
void onRemoveSelected();
private:
friend class GroupsProvider;
-
const Utils::UniString &getSortValue() const;
- virtual int onUpdate(void *data) override;
+
void updateMembersCount();
+ virtual int onUpdate(void *data) override;
+ virtual void onStandalone(bool isStandalone) override;
+ void onGroupsChanged(const char *uri);
+
+ void setChangeCallback();
+ void unsetChangeCallback();
- Common::GroupType m_Type;
contacts_record_h m_Record;
+ int m_DbVersion;
+
+ Common::GroupType m_Type;
mutable Utils::UniString m_SortValue;
int m_MembersCount;
};
{
public:
/**
- * @brief Determines which items are displayed.
+ * @brief Determines which items are displayed.
*/
enum Mode
{
- ModeDefault, /**< Group's members are displayed */
- ModeExclude /**< Displayed all contacts which are not group's members */
+ ModeDefault, /**< Group's members are displayed */
+ ModeExclude /**< Displayed all contacts which are not group's members */
};
/**
* @brief Constructor.
* @param[in] groupId Group id
* @param[in] mode Members mode
- * @param[in] type Fiter type
+ * @param[in] type Filter type
*/
explicit MembersProvider(int groupId, Mode mode = ModeDefault,
int type = FilterNone);
- virtual ~MembersProvider() override;
+
+ /**
+ * @return Group ID.
+ */
+ int getGroupId() const;
private:
virtual contacts_filter_h getFilter() const override;
virtual contacts_list_h getPersonList() const override;
virtual contacts_record_h getPersonRecord(int id, IdType idType) const override;
-
contacts_list_h getMembersList() const;
- void onGroupChanged(const char *uri);
-
int m_GroupId;
Mode m_Mode;
- int m_GroupDbVersion;
};
}
}
Model::PersonProvider *getProvider() const;
/**
- * @brief Called when updating is finished
+ * @brief Called when provider initialization is finished.
+ */
+ virtual void onInitialized();
+
+ /**
+ * @brief Called when updating is finished.
*/
virtual void onUpdateFinished();
return;
}
- navigator->navigateTo(new MembersListView(m_Group.getId(),
- new MembersProvider(m_Group.getId())));
+ navigator->navigateTo(new MembersListView(new MembersProvider(m_Group.getId())));
}
unsigned int propertyId;
const char *scheme;
} composerData[] = {
- /*ComposerMessage = */ { Contacts::FilterNumber, CONTACTS_PERSON_PROPERTY_NUMBER,
+ /* ComposerMessage = */ { Contacts::FilterNumber, CONTACTS_PERSON_PROPERTY_NUMBER,
_contacts_number._uri, _contacts_number.number, "sms:" },
- /*ComposerEmail = */ { Contacts::FilterEmail, CONTACTS_PERSON_PROPERTY_EMAIL,
+ /* ComposerEmail = */ { Contacts::FilterEmail, CONTACTS_PERSON_PROPERTY_EMAIL,
_contacts_email._uri, _contacts_email.email, "mailto:" }
};
}
-MembersListView::MembersListView(int id, MembersProvider *provider)
- : ListView(provider), m_Group(id)
+MembersListView::MembersListView(MembersProvider *provider)
+ : ListView(provider), m_Group(provider->getGroupId())
{
setAddButtonVisibility(false);
setNoContentHelpText("IDS_PB_BODY_AFTER_YOU_ADD_CONTACTS_THEY_WILL_BE_SHOWN_HERE");
for (size_t i = ListView::SectionFirst; i < ListView::SectionMax; ++i) {
setSectionVisibility(static_cast<ListView::SectionId>(i), false);
}
+
+ m_Group.setStandalone(true);
+ m_Group.setUpdateCallback([this](int changes) {
+ updateTitle();
+ });
+ m_Group.setDeleteCallback([this] {
+ getPage()->close();
+ });
}
void MembersListView::onPageAttached(NavigatorPage *page)
{
- if (getSelectMode() == SelectNone) {
- page->setTitle(getTitle().c_str());
- } else {
- SelectView::onPageAttached(page);
- }
+ SelectView::onPageAttached(page);
+ updateTitle();
}
void MembersListView::onMenuPressed()
menu->show();
}
+void MembersListView::onInitialized()
+{
+ ListView::onInitialized();
+ updateTitle();
+}
+
void MembersListView::onUpdateFinished()
{
ListView::onUpdateFinished();
-
- if (getSelectMode() == SelectNone) {
- getPage()->setTitle(getTitle().c_str());
- }
+ updateTitle();
}
-std::string MembersListView::getTitle() const
+void MembersListView::updateTitle()
{
- const char *name = (m_Group.getType() == GroupCustom) ? m_Group.getName()
- : _(getDefaultGroupName(m_Group.getType()));
+ Ui::NavigatorPage *page = getPage();
+ if (!page || getSelectMode() != SelectNone) {
+ return;
+ }
+
+ const char *name = (m_Group.getType() == GroupCustom) ?
+ m_Group.getName() : _(getDefaultGroupName(m_Group.getType()));
- char title[BUFFER_SIZE] = { 0, };
int count = getProvider()->getDataList().size();
- if (count) {
- snprintf(title, sizeof(title), "%s (%d)", name, count);
- } else {
- snprintf(title, sizeof(title), "%s", name);
+ if (count == 0) {
+ page->setTitle(name);
+ return;
}
- return std::string(title);
+
+ char title[BUFFER_SIZE];
+ snprintf(title, sizeof(title), "%s (%d)", name, count);
+ page->setTitle(title);
}
void MembersListView::onAddSelected()
bool MembersListView::onRemoveFinished()
{
setSelectMode(SelectNone);
- getPage()->setTitleVisibility(true);
- getPage()->setTitle(getTitle().c_str());
setCancelCallback(nullptr);
setSelectCallback(nullptr);
+
+ getPage()->setTitleVisibility(true);
+ updateTitle();
+
return false;
}
void MembersListView::onSendSelected(ComposerType composerType)
{
- MembersListView *view = new MembersListView(m_Group.getId(), new MembersProvider(m_Group.getId(),
+ MembersListView *view = new MembersListView(new MembersProvider(m_Group.getId(),
MembersProvider::ModeDefault, composerData[composerType].type));
view->setSelectMode(SelectMulti);
view->setNoContentHelpText("");
#include "Contacts/Groups/Model/Group.h"
#include "Contacts/Groups/Model/Queries.h"
+#include "Common/Database/RecordIterator.h"
#include "Common/Database/RecordUtils.h"
+
+#include "Utils/Callback.h"
#include "Utils/Logger.h"
using namespace Common::Database;
using namespace Contacts::Groups::Model;
-Group::Group(int id)
+namespace
{
- if (id) {
- contacts_db_get_record(_contacts_group._uri, id, &m_Record);
- } else {
- contacts_record_create(_contacts_group._uri, &m_Record);
+ contacts_record_h fetchGroupRecord(int id)
+ {
+ contacts_record_h record = nullptr;
+ if (id) {
+ contacts_db_get_record(_contacts_group._uri, id, &record);
+ } else {
+ contacts_record_create(_contacts_group._uri, &record);
+ }
+
+ return record;
}
- m_Type = Common::getGroupType(getName());
- m_MembersCount = Model::getMembersCount(id);
+}
+
+Group::Group(int id)
+ : Group(fetchGroupRecord(id))
+{
}
Group::Group(contacts_record_h record)
- : m_Record(record)
+ : m_Record(record), m_DbVersion(0)
{
m_Type = Common::getGroupType(getName());
m_MembersCount = Model::getMembersCount(getId());
Group::~Group()
{
+ if (isStandalone()) {
+ unsetChangeCallback();
+ }
+
contacts_record_destroy(m_Record, true);
}
return m_SortValue;
}
+void Group::updateMembersCount()
+{
+ m_MembersCount = Model::getMembersCount(getId());
+ setChanged(Model2::ChangeUpdate, ChangedMembersCount);
+}
+
int Group::onUpdate(void *data)
{
contacts_record_h record = (contacts_record_h) data;
return changes;
}
-void Group::updateMembersCount()
+void Group::onStandalone(bool isStandalone)
{
- m_MembersCount = Model::getMembersCount(getId());
- setUpdated(ChangedMembersCount);
+ if (isStandalone) {
+ setChangeCallback();
+ } else {
+ unsetChangeCallback();
+ }
+}
+
+void Group::onGroupsChanged(const char *uri)
+{
+ contacts_list_h changes = nullptr;
+ contacts_db_get_changes_by_version(_contacts_group_updated_info._uri, 0,
+ m_DbVersion, &changes, &m_DbVersion);
+
+ for (auto &&record : makeRange(changes)) {
+ int groupId = getRecordInt(record, _contacts_group_updated_info.group_id);
+ if (groupId == getId()) {
+ int changeType = getRecordInt(record, _contacts_group_updated_info.type);
+ if (changeType == CONTACTS_CHANGE_UPDATED) {
+ update(fetchGroupRecord(getId()));
+ } else if (changeType == CONTACTS_CHANGE_DELETED) {
+ setChanged(Model2::ChangeDelete);
+ }
+ break;
+ }
+ }
+
+ contacts_list_destroy(changes, true);
+}
+
+void Group::setChangeCallback()
+{
+ contacts_db_get_current_version(&m_DbVersion);
+ contacts_db_add_changed_cb(_contacts_group._uri,
+ makeCallbackWithLastParam(&Group::onGroupsChanged), this);
+}
+
+void Group::unsetChangeCallback()
+{
+ contacts_db_remove_changed_cb(_contacts_group._uri,
+ makeCallbackWithLastParam(&Group::onGroupsChanged), this);
+ m_DbVersion = 0;
}
MembersProvider::MembersProvider(int groupId, Mode mode, int type)
: PersonProvider(type), m_GroupId(groupId), m_Mode(mode)
{
- contacts_db_get_current_version(&m_GroupDbVersion);
- contacts_db_add_changed_cb(_contacts_group._uri,
- makeCallbackWithLastParam(&MembersProvider::onGroupChanged), this);
}
-MembersProvider::~MembersProvider()
+int MembersProvider::getGroupId() const
{
- contacts_db_remove_changed_cb(_contacts_group._uri,
- makeCallbackWithLastParam(&MembersProvider::onGroupChanged), this);
+ return m_GroupId;
}
contacts_filter_h MembersProvider::getFilter() const
contacts_query_destroy(query);
return list;
}
-
-void MembersProvider::onGroupChanged(const char *uri)
-{
- contacts_list_h changes = nullptr;
- contacts_db_get_changes_by_version(_contacts_group_updated_info._uri, 0,
- m_GroupDbVersion, &changes, &m_GroupDbVersion);
- bool isChanged = false;
-
- for (auto &&record : makeRange(changes)) {
- if (getRecordInt(record, _contacts_group_updated_info.group_id) != m_GroupId) {
- continue;
- }
- int changeType = getRecordInt(record, _contacts_group_updated_info.type);
- switch (changeType) {
- case CONTACTS_CHANGE_UPDATED:
- isChanged = true;
- break;
- }
- }
- contacts_list_destroy(changes, true);
-
- if (isChanged) {
- onUpdateFinished();
- }
-}
return m_PersonProvider;
}
+void ListView::onInitialized()
+{
+ fillPersonList();
+ updateSections();
+ updateEmptyState();
+ if (auto item = m_Genlist->getFirstItem()) {
+ item->scrollTo();
+ }
+ elm_index_level_go(m_Index, 0);
+ if (m_OnFillFinished) {
+ m_OnFillFinished();
+ }
+}
+
void ListView::onUpdateFinished()
{
elm_index_level_go(m_Index, 0);
fillLayout();
updateSection(SectionMyProfile);
- m_SearchProvider.initialize([this] {
- fillPersonList();
- updateSections();
- updateEmptyState();
- if (auto item = m_Genlist->getFirstItem()) {
- item->scrollTo();
- }
- elm_index_level_go(m_Index, 0);
- if (m_OnFillFinished) {
- m_OnFillFinished();
- }
- });
-
+ m_SearchProvider.initialize(std::bind(&ListView::onInitialized, this));
m_SearchProvider.setInsertCallback(std::bind(&ListView::onPersonInserted, this, _1));
m_PersonProvider->setUpdateFinishedCallback(std::bind(&ListView::onUpdateFinished, this));
}