From fa4fced5cf0eb84789c0815cbbd39289b33ed463 Mon Sep 17 00:00:00 2001 From: Lukasz Stanislawski Date: Tue, 6 Sep 2016 14:30:06 +0200 Subject: [PATCH] Add Delete Alarm view and presenter. Add possibility to delete exitsing alarms by using "menu" hardware button and pressing "delete" item. The new view with selectable alarms is being pushed. When alarms are begin deleted the AlarmRemovedEvent is being triggered, which allows to synchronize other views (eg. AlarmView) Change-Id: Ifa41318fdb5c9930bb6b7e3dfb6931ee3e21db13 --- clock/inc/Controller/MainController.h | 9 +- clock/inc/Internal/AlarmProviderFile.h | 2 +- clock/inc/Model/AlarmEvent.h | 7 + clock/inc/Model/AlarmProvider.h | 2 +- clock/inc/Model/AlarmProviderEvent.h | 4 +- clock/inc/Presenter/AlarmPresenter.h | 5 + clock/inc/Presenter/DeleteAlarmPresenter.h | 38 ++++ clock/inc/View/AlarmView.h | 20 +- clock/inc/View/DeleteAlarmView.h | 69 +++++++ clock/res/edje/alarm.edc | 63 ++++++ clock/src/Controller/MainController.cpp | 27 ++- clock/src/Model/AlarmEvent.cpp | 14 ++ clock/src/Model/AlarmProviderEvent.cpp | 2 +- clock/src/Model/AlarmProviderFile.cpp | 9 +- clock/src/Presenter/AlarmPresenter.cpp | 31 ++- clock/src/Presenter/DeleteAlarmPresenter.cpp | 44 +++++ clock/src/Utils/EventBus.cpp | 3 + clock/src/View/AlarmView.cpp | 89 ++++++--- clock/src/View/DeleteAlarmView.cpp | 282 +++++++++++++++++++++++++++ 19 files changed, 676 insertions(+), 44 deletions(-) create mode 100644 clock/inc/Presenter/DeleteAlarmPresenter.h create mode 100644 clock/inc/View/DeleteAlarmView.h create mode 100644 clock/src/Presenter/DeleteAlarmPresenter.cpp create mode 100644 clock/src/View/DeleteAlarmView.cpp diff --git a/clock/inc/Controller/MainController.h b/clock/inc/Controller/MainController.h index 06d4f92..20bc60d 100644 --- a/clock/inc/Controller/MainController.h +++ b/clock/inc/Controller/MainController.h @@ -17,6 +17,8 @@ #ifndef _CLOCK_MAIN_CONTROLLER_H_ #define _CLOCK_MAIN_CONTROLLER_H_ +#include "Utils/EventBus.h" + /** * @file MainController.h */ @@ -89,7 +91,12 @@ namespace controller { /** * @brief Creates new "Edit/Create" alarm page. */ - void CreateNewAlarmPage(); + void CreateNewAlarmPage(utils::Event *e); + + /** + * @brief Creates new "Delete" alarm page. + */ + void CreateNewDeleteAlarmsPage(utils::Event *e); }; } diff --git a/clock/inc/Internal/AlarmProviderFile.h b/clock/inc/Internal/AlarmProviderFile.h index 2d530ea..bc146eb 100644 --- a/clock/inc/Internal/AlarmProviderFile.h +++ b/clock/inc/Internal/AlarmProviderFile.h @@ -13,7 +13,7 @@ namespace internal { std::vector> GetAlarms(); model::Alarm* GetAlarmWithId(model::AlarmId id); void Add(model::Alarm& alarm); - void Remove(model::Alarm& alarm); + void Remove(std::reference_wrapper alarm); AlarmProviderFile(utils::IReader &r); ~AlarmProviderFile(); void Serialize(utils::IWriter &w) const; diff --git a/clock/inc/Model/AlarmEvent.h b/clock/inc/Model/AlarmEvent.h index 347ee35..be7bc77 100644 --- a/clock/inc/Model/AlarmEvent.h +++ b/clock/inc/Model/AlarmEvent.h @@ -27,6 +27,13 @@ namespace model { private: static int custom_type_; }; + class AlarmDeleteRequestEvent : public utils::Event { + public: + AlarmDeleteRequestEvent(); + static int EventType(); + private: + static int custom_type_; + }; } /* model */ #endif diff --git a/clock/inc/Model/AlarmProvider.h b/clock/inc/Model/AlarmProvider.h index 0d37997..0409727 100644 --- a/clock/inc/Model/AlarmProvider.h +++ b/clock/inc/Model/AlarmProvider.h @@ -34,7 +34,7 @@ namespace model { virtual std::vector> GetAlarms() = 0; virtual Alarm *GetAlarmWithId(AlarmId id) = 0; virtual void Add(Alarm& alarm) = 0; - virtual void Remove(Alarm& alarm) = 0; + virtual void Remove(std::reference_wrapper alarm) = 0; protected: AlarmProvider() {} virtual ~AlarmProvider() {} diff --git a/clock/inc/Model/AlarmProviderEvent.h b/clock/inc/Model/AlarmProviderEvent.h index 630e507..5350566 100644 --- a/clock/inc/Model/AlarmProviderEvent.h +++ b/clock/inc/Model/AlarmProviderEvent.h @@ -24,7 +24,7 @@ namespace model { class AlarmAddedEvent : public utils::Event { public: AlarmAddedEvent(Alarm &alarm); - const Alarm& GetAlarm() const { return alarm_; } + Alarm& GetAlarm() { return alarm_; } static int EventType(); private: Alarm &alarm_; @@ -33,7 +33,7 @@ namespace model { class AlarmRemovedEvent : public utils::Event { public: AlarmRemovedEvent(Alarm &alarm); - const Alarm& GetAlarm() const { return alarm_; } + Alarm& GetAlarm() { return alarm_; } static int EventType(); private: Alarm &alarm_; diff --git a/clock/inc/Presenter/AlarmPresenter.h b/clock/inc/Presenter/AlarmPresenter.h index 3528843..95cc15c 100644 --- a/clock/inc/Presenter/AlarmPresenter.h +++ b/clock/inc/Presenter/AlarmPresenter.h @@ -21,6 +21,8 @@ #include "Model/AlarmProvider.h" #include "Model/AlarmProviderEvent.h" +#include + namespace presenter { class AlarmPresenter { public: @@ -34,6 +36,9 @@ namespace presenter { void OnAddButtonClicked(); void OnItemActiveStatusChanged(int idx); void OnAlarmAddedEvent(utils::Event *e); + void OnAlarmRemovedEvent(utils::Event *e); + void OnDeleteItemClicked(); + std::map> alarms_; }; } /* presenters */ diff --git a/clock/inc/Presenter/DeleteAlarmPresenter.h b/clock/inc/Presenter/DeleteAlarmPresenter.h new file mode 100644 index 0000000..14a737c --- /dev/null +++ b/clock/inc/Presenter/DeleteAlarmPresenter.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _CLOCK_PRESENTER_DELETE_ALARM_H_ +#define _CLOCK_PRESENTER_DELETE_ALARM_H_ + +#include "Model/AlarmProvider.h" +#include "View/DeleteAlarmView.h" + +#include + +namespace presenter { + class DeleteAlarmPresenter { + public: + DeleteAlarmPresenter(view::DeleteAlarmView *view, model::AlarmProvider *model); + private: + view::DeleteAlarmView *view_; + model::AlarmProvider *model_; + void OnDeleteButtonClicked(); + void OnCancelButtonClicked(); + std::map> alarms_; + }; +} /* presenter */ + +#endif diff --git a/clock/inc/View/AlarmView.h b/clock/inc/View/AlarmView.h index 4ae65a2..3cbfae2 100644 --- a/clock/inc/View/AlarmView.h +++ b/clock/inc/View/AlarmView.h @@ -33,7 +33,7 @@ namespace view { AlarmView(); void Clear(); int ItemAppend(utils::Time time, const char *name, - const model::WeekFlags flags, bool active); + const model::WeekFlags flags, bool active); void RemoveItem(int idx); void ItemUpdate(int idx, utils::Time time, const char *name, const model::WeekFlags flags, bool active); @@ -43,6 +43,7 @@ namespace view { void SetItemToggleCallback(ToggleCallback func); void SetItemSelectCallback(SelectCallback func);; void SetButtonClickedCallback(ButtonClickedCallback func); + void SetDeleteItemClickedCallback(ButtonClickedCallback func) { onDeleteClicked_ = func;} Evas_Object *GetEvasObject(); private: static Elm_Genlist_Item_Class alarm_itc; @@ -52,11 +53,18 @@ namespace view { static void ItemClicked(void *data, Evas_Object *obj, void *info); static void ItemRealized(void *data, Evas_Object *obj, void *info); static void ButtonClicked(void *data, Evas_Object *obj, void *info); - Evas_Object *genlist; - Evas_Object *content; - SelectCallback onSelected; - ToggleCallback onToggled; - ButtonClickedCallback onClicked;; + static void MoreButtonClicked(void *data, Evas_Object *obj, void *info); + static void DismissPopupCallback(void *data, Evas_Object *obj, void *info); + static void PopupDeleteItemCallback(void *data, Evas_Object *obj, void *info); + + Evas_Object *genlist_; + Evas_Object *content_; + Evas_Object *popup_; + SelectCallback onSelected_; + ToggleCallback onToggled_; + ButtonClickedCallback onClicked_; + ButtonClickedCallback onDeleteClicked_; + void ShowDeletePopup(); }; } diff --git a/clock/inc/View/DeleteAlarmView.h b/clock/inc/View/DeleteAlarmView.h new file mode 100644 index 0000000..3fa9083 --- /dev/null +++ b/clock/inc/View/DeleteAlarmView.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 _CLOCK_DELETE_ALARM_VIEW_ +#define _CLOCK_DELETE_ALARM_VIEW_ + +#include "View/PageView.h" +#include "Model/WeekFlags.h" +#include "Utils/Time.h" + +#include + +namespace view { + class DeleteAlarmView : public PageView { + public: + typedef std::function ButtonClickedCallback; + + DeleteAlarmView(); + + void RegisterCancelButtonClickedCallback(ButtonClickedCallback cb) { onCancelButtonClicked_ = cb; } + void RegisterDeleteButtonClickedCallback(ButtonClickedCallback cb) { onDeleteButtonClicked_ = cb; } + Evas_Object *GetEvasObject() { return content_; } + + int ItemAppend(utils::Time time, const char *name, + const model::WeekFlags flags, bool active); + std::vector GetSelectedItems() const; + protected: + virtual void CreateContent(); + virtual void DestroyContent(); + private: + Evas_Object *content_; + Evas_Object *left_btn_; + Evas_Object *right_btn_; + + ButtonClickedCallback onDeleteButtonClicked_; + ButtonClickedCallback onCancelButtonClicked_; + + void SelectAllStateSet(bool value); + void UpdateTitle(void); + + bool all_selected_; + Evas_Object *all_selected_check_; + + // EFL callbacks + static void OnCancelButtonClickedCb(void *data, Evas_Object *obj, void *event); + static void OnDeleteButtonClickedCb(void *data, Evas_Object *obj, void *event); + static void ItemRealized(void *data, Evas_Object *obj, void *event); + static void ItemSelectToggle(void *data, Evas_Object *obj, void *event); + static void ItemSelected(void *data, Evas_Object *obj, void *event); + static void ItemSelectAllClicked(void *data, Evas_Object *obj, void *event); + + void CreateSelectAllItem(); + }; +} /* view */ + +#endif diff --git a/clock/res/edje/alarm.edc b/clock/res/edje/alarm.edc index 6859a1b..1b8a96c 100644 --- a/clock/res/edje/alarm.edc +++ b/clock/res/edje/alarm.edc @@ -158,4 +158,67 @@ collections { target: "time"; } } + group { name: "elm/genlist/item/select_all/default"; + styles { + style { name: "font_normal"; + base: "font=Tizen:style=Light color=#000000FF font_size=40 ellipsis=1.0"; + } + } + data.item: "texts" "elm.text"; + data.item: "contents" "sw.check"; + data.item: "banded_bg_area" "elm.swallow.bg"; + parts { + spacer { "base"; scale; + desc { "default"; + min: 0 120; + } + } + swallow { "elm.swallow.bg"; + desc { "default"; + rel1.to: "base"; + rel2.to: "base"; + } + } + spacer { "padding.left"; scale; + desc { "default"; + fixed: 1 0; + min: 32 0; + max: 32 -1; + align: 0.0 0.5; + rel1.to: "base"; + rel2.to: "base"; + } + } + spacer { "padding.right"; scale; + desc { "default"; + fixed: 1 0; + min: 32 0; + max: 32 -1; + align: 1.0 0.5; + rel1.to: "base"; + rel2.to: "base"; + } + } + textblock { "elm.text"; scale; + desc { "default"; + fixed: 0 1; + min: 0 93; + max: -1 93; + rel1 { relative: 1.0 0.0; to_x: "padding.left"; to_y: "base"; } + rel2.to: "base"; + text.style: "font_normal"; + } + } + swallow { "sw.check"; scale; + desc { "default"; + fixed: 1 1; + align: 1.0 0.5; + min: 80 80; + max: 80 80; + rel1.to: "base"; + rel2 { relative: 0.0 1.0; to: "padding.right"; } + } + } + } + } } diff --git a/clock/src/Controller/MainController.cpp b/clock/src/Controller/MainController.cpp index a2d2beb..13b191d 100644 --- a/clock/src/Controller/MainController.cpp +++ b/clock/src/Controller/MainController.cpp @@ -21,12 +21,15 @@ #include "View/EditAlarmView.h" #include "Presenter/EditAlarmPresenter.h" #include "Model/AlarmEvent.h" +#include "View/DeleteAlarmView.h" +#include "Presenter/DeleteAlarmPresenter.h" using namespace controller; using namespace view; using namespace utils; using namespace presenter; using namespace model; +using std::placeholders::_1; MainController &MainController::GetInstance() { @@ -54,17 +57,23 @@ int MainController::Init() MainView::GetInstance(); MainView::GetInstance().CreateContent(); - EventBus::RegisterHandler(AlarmCreateRequestEvent::EventType(), std::bind(&MainController::CreateNewAlarmPage, this)); + EventBus::RegisterHandler(AlarmCreateRequestEvent::EventType(), + std::bind(&MainController::CreateNewAlarmPage, this, _1)); + EventBus::RegisterHandler(AlarmDeleteRequestEvent::EventType(), + std::bind(&MainController::CreateNewDeleteAlarmsPage, this, _1)); return 0; } void MainController::Deinit() { - EventBus::DeregisterHandler(AlarmCreateRequestEvent::EventType(), std::bind(&MainController::CreateNewAlarmPage, this)); + EventBus::DeregisterHandler(AlarmCreateRequestEvent::EventType(), + std::bind(&MainController::CreateNewAlarmPage, this, _1)); + EventBus::DeregisterHandler(AlarmDeleteRequestEvent::EventType(), + std::bind(&MainController::CreateNewDeleteAlarmsPage, this, _1)); } -void MainController::CreateNewAlarmPage() +void MainController::CreateNewAlarmPage(Event *e) { static EditAlarmView *view; static EditAlarmPresenter *presenter; @@ -75,3 +84,15 @@ void MainController::CreateNewAlarmPage() view = new EditAlarmView(); presenter = new EditAlarmPresenter(nullptr, *view); } + +void MainController::CreateNewDeleteAlarmsPage(Event *e) +{ + static DeleteAlarmView *view; + static DeleteAlarmPresenter *presenter; + + if (view) delete view; + if (presenter) delete presenter; + + view = new DeleteAlarmView(); + presenter = new DeleteAlarmPresenter(view, AlarmProvider::GetInstance()); +} diff --git a/clock/src/Model/AlarmEvent.cpp b/clock/src/Model/AlarmEvent.cpp index 636704a..8fcc0c6 100644 --- a/clock/src/Model/AlarmEvent.cpp +++ b/clock/src/Model/AlarmEvent.cpp @@ -4,6 +4,7 @@ using namespace model; using namespace utils; int AlarmCreateRequestEvent::custom_type_; +int AlarmDeleteRequestEvent::custom_type_; AlarmCreateRequestEvent::AlarmCreateRequestEvent() : Event(AlarmCreateRequestEvent::EventType()) @@ -17,3 +18,16 @@ int AlarmCreateRequestEvent::EventType() } return custom_type_; } + +AlarmDeleteRequestEvent::AlarmDeleteRequestEvent() : + Event(AlarmDeleteRequestEvent::EventType()) +{ +} + +int AlarmDeleteRequestEvent::EventType() +{ + if (custom_type_ == 0) { + custom_type_ = EventBus::RegisterNewEventType(); + } + return custom_type_; +} diff --git a/clock/src/Model/AlarmProviderEvent.cpp b/clock/src/Model/AlarmProviderEvent.cpp index 5507bd9..99cb2ae 100644 --- a/clock/src/Model/AlarmProviderEvent.cpp +++ b/clock/src/Model/AlarmProviderEvent.cpp @@ -20,7 +20,7 @@ int AlarmAddedEvent::EventType() } AlarmRemovedEvent::AlarmRemovedEvent(Alarm &alarm) : - Event(AlarmAddedEvent::EventType()), alarm_(alarm) + Event(AlarmRemovedEvent::EventType()), alarm_(alarm) { } diff --git a/clock/src/Model/AlarmProviderFile.cpp b/clock/src/Model/AlarmProviderFile.cpp index 3ebf038..abbe694 100644 --- a/clock/src/Model/AlarmProviderFile.cpp +++ b/clock/src/Model/AlarmProviderFile.cpp @@ -22,16 +22,19 @@ void AlarmProviderFile::Add(model::Alarm& alarm) alarms.push_back(alarm); EventBus::FireEvent(new AlarmAddedEvent(alarm)); } + Sync(); } -void AlarmProviderFile::Remove(model::Alarm& alarm) +void AlarmProviderFile::Remove(std::reference_wrapper alarm) { - auto it = std::find(alarms.begin(), alarms.end(), alarm); + auto it = std::find(alarms.begin(), alarms.end(), alarm.get()); if (it != alarms.end()) { - alarms.erase(it); EventBus::FireEvent(new AlarmRemovedEvent(alarm)); + alarm.get().Deactivate(); + alarms.erase(it); } + Sync(); } AlarmProviderFile::AlarmProviderFile(IReader &r) diff --git a/clock/src/Presenter/AlarmPresenter.cpp b/clock/src/Presenter/AlarmPresenter.cpp index e396774..60a701b 100644 --- a/clock/src/Presenter/AlarmPresenter.cpp +++ b/clock/src/Presenter/AlarmPresenter.cpp @@ -13,9 +13,12 @@ using std::placeholders::_1; AlarmPresenter::AlarmPresenter(AlarmView *v, AlarmProvider *m) : view(v), model(m) { view->SetButtonClickedCallback(std::bind(&AlarmPresenter::OnAddButtonClicked, this)); + view->SetDeleteItemClickedCallback(std::bind(&AlarmPresenter::OnDeleteItemClicked, this)); EventBus::RegisterHandler(AlarmAddedEvent::EventType(), std::bind(&AlarmPresenter::OnAlarmAddedEvent, this, _1)); + EventBus::RegisterHandler(AlarmRemovedEvent::EventType(), + std::bind(&AlarmPresenter::OnAlarmRemovedEvent, this, _1)); ShowAll(); } @@ -24,6 +27,8 @@ AlarmPresenter::~AlarmPresenter() { EventBus::DeregisterHandler(AlarmAddedEvent::EventType(), std::bind(&AlarmPresenter::OnAlarmAddedEvent, this, _1)); + EventBus::DeregisterHandler(AlarmRemovedEvent::EventType(), + std::bind(&AlarmPresenter::OnAlarmRemovedEvent, this, _1)); } void AlarmPresenter::ShowAll() @@ -33,11 +38,12 @@ void AlarmPresenter::ShowAll() view->Clear(); for (auto a: alarms) { - view->ItemAppend( + int id = view->ItemAppend( a.get().GetTime(), a.get().GetName().c_str(), a.get().GetWeekFlags(), a.get().IsActivated()); + alarms_.insert(std::map>::value_type (id, std::reference_wrapper(a))); } } @@ -77,9 +83,30 @@ void AlarmPresenter::OnAlarmAddedEvent(Event *e) AlarmAddedEvent *ev = dynamic_cast(e); - view->ItemAppend( + int id = view->ItemAppend( ev->GetAlarm().GetTime(), ev->GetAlarm().GetName().c_str(), ev->GetAlarm().GetWeekFlags(), ev->GetAlarm().IsActivated()); + alarms_.insert(std::map>::value_type (id, std::reference_wrapper(ev->GetAlarm()))); +} + +void AlarmPresenter::OnDeleteItemClicked() +{ + EventBus::FireEvent(new AlarmDeleteRequestEvent()); +} + +void AlarmPresenter::OnAlarmRemovedEvent(Event *e) +{ + if (!e || (e->GetType() != AlarmRemovedEvent::EventType())) + return; + + AlarmRemovedEvent *ev = dynamic_cast(e); + for (auto it = alarms_.begin(); it != alarms_.end(); ++it) { + if (ev->GetAlarm() == it->second.get()) { + view->RemoveItem(it->first); + alarms_.erase(it); + break; + } + } } diff --git a/clock/src/Presenter/DeleteAlarmPresenter.cpp b/clock/src/Presenter/DeleteAlarmPresenter.cpp new file mode 100644 index 0000000..7d55ec8 --- /dev/null +++ b/clock/src/Presenter/DeleteAlarmPresenter.cpp @@ -0,0 +1,44 @@ +#include "Presenter/DeleteAlarmPresenter.h" + +using namespace model; +using namespace view; + +namespace presenter { +DeleteAlarmPresenter::DeleteAlarmPresenter(DeleteAlarmView *view, AlarmProvider *model) + : view_(view), model_(model) +{ + view->RegisterCancelButtonClickedCallback( + std::bind(&DeleteAlarmPresenter::OnCancelButtonClicked, this) + ); + view->RegisterDeleteButtonClickedCallback( + std::bind(&DeleteAlarmPresenter::OnDeleteButtonClicked, this) + ); + + std::vector> alarms = model_->GetAlarms(); + + for (auto a: alarms) { + int id = view_->ItemAppend( + a.get().GetTime(), + a.get().GetName().c_str(), + a.get().GetWeekFlags(), + a.get().IsActivated()); + alarms_.insert(std::map>::value_type (id, std::reference_wrapper(a))); + } +} + +void DeleteAlarmPresenter::OnDeleteButtonClicked() +{ + std::vector deleted = view_->GetSelectedItems(); + + for (auto idx: deleted) { + model_->Remove(alarms_.find(idx)->second); + } + view_->PopPage(); +} + +void DeleteAlarmPresenter::OnCancelButtonClicked() +{ + view_->PopPage(); +} + +} diff --git a/clock/src/Utils/EventBus.cpp b/clock/src/Utils/EventBus.cpp index d28c847..44cb84e 100644 --- a/clock/src/Utils/EventBus.cpp +++ b/clock/src/Utils/EventBus.cpp @@ -1,6 +1,8 @@ #include "Utils/EventBus.h" #include +#include "log.h" + using namespace utils; int EventBus::RegisterNewEventType() @@ -37,6 +39,7 @@ void EventBus::DeregisterHandler(int type, std::function func) void EventBus::FireEvent(Event *event) { EventBus &bus = GetInstance(); + DBG("Fire %d event", event->GetType()); for (auto func: bus.callbacks_[event->GetType()]) { func(event); } diff --git a/clock/src/View/AlarmView.cpp b/clock/src/View/AlarmView.cpp index 78e2409..fc920e9 100644 --- a/clock/src/View/AlarmView.cpp +++ b/clock/src/View/AlarmView.cpp @@ -132,24 +132,24 @@ void AlarmView::Del(void *data, Evas_Object *obj) AlarmView::AlarmView() { /* Base Layout */ - content = elm_layout_add(MainView::GetInstance().GetEvasObject()); - evas_object_size_hint_weight_set(content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - elm_layout_theme_set(content, "layout", "application", "default"); - evas_object_show(content); + content_ = elm_layout_add(MainView::GetInstance().GetEvasObject()); + evas_object_size_hint_weight_set(content_, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_layout_theme_set(content_, "layout", "application", "default"); + evas_object_show(content_); /* Genlist */ - genlist = elm_genlist_add(content); - elm_genlist_homogeneous_set(genlist, EINA_TRUE); - evas_object_size_hint_expand_set(genlist, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(genlist, EVAS_HINT_FILL, EVAS_HINT_FILL); - evas_object_smart_callback_add(genlist, "realized", AlarmView::ItemRealized, this); - evas_object_show(genlist); + genlist_ = elm_genlist_add(content_); + elm_genlist_homogeneous_set(genlist_, EINA_TRUE); + evas_object_size_hint_expand_set(genlist_, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(genlist_, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(genlist_, "realized", AlarmView::ItemRealized, this); + evas_object_show(genlist_); - elm_object_content_set(content, genlist); + elm_object_content_set(content_, genlist_); /* Floating Button */ - Evas_Object *fb = eext_floatingbutton_add(content); - elm_object_part_content_set(content, "elm.swallow.floatingbutton", fb); + Evas_Object *fb = eext_floatingbutton_add(content_); + elm_object_part_content_set(content_, "elm.swallow.floatingbutton", fb); /* Floating Button 1 */ Evas_Object *btn = elm_button_add(fb); @@ -161,11 +161,22 @@ AlarmView::AlarmView() elm_object_part_content_set(fb, "button1", btn); elm_theme_extension_add(NULL, Utils::GetAppResourcePath(Utils::APP_DIR_RESOURCE, "edje/alarm.edj")); + + eext_object_event_callback_add(content_, EEXT_CALLBACK_MORE, + AlarmView::MoreButtonClicked, this); +} + +void AlarmView::MoreButtonClicked(void *data, Evas_Object *obj, void *info) +{ + AlarmView *view = static_cast(data); + + DBG("More button clicked"); + view->ShowDeletePopup(); } void AlarmView::Clear() { - elm_genlist_clear(genlist); + elm_genlist_clear(genlist_); } int AlarmView::ItemAppend(Time time, const char *name, const WeekFlags flags, bool active) @@ -178,20 +189,20 @@ int AlarmView::ItemAppend(Time time, const char *name, const WeekFlags flags, b data->active = active; data->time = time; - data->it = elm_genlist_item_append(genlist, + data->it = elm_genlist_item_append(genlist_, &alarm_itc, data, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); - return elm_genlist_item_index_get(data->it); + return (uintptr_t)data->it; } void AlarmView::ItemUpdate(int idx, Time time, const char *name, const WeekFlags flags, bool active) { - Elm_Object_Item *it = elm_genlist_nth_item_get(genlist, idx); + Elm_Object_Item *it = (Elm_Object_Item*)idx; if (!it) return; ItemData *data = static_cast(elm_object_item_data_get(it)); @@ -207,32 +218,62 @@ void AlarmView::ItemUpdate(int idx, Time time, const char *name, void AlarmView::RemoveItem(int idx) { - //Elm_Object_Item *it = elm_genlist_item_nth_get(idx); - //if (it) elm_object_item_del(it); + Elm_Object_Item *it = (Elm_Object_Item*)idx; + if (it) elm_object_item_del(it); } void AlarmView::SetItemToggleCallback(ToggleCallback func) { - onToggled = std::move(func); + onToggled_ = std::move(func); } void AlarmView::SetItemSelectCallback(SelectCallback func) { - onSelected = std::move(func); + onSelected_ = std::move(func); } void AlarmView::SetButtonClickedCallback(ButtonClickedCallback func) { - onClicked = std::move(func); + onClicked_ = std::move(func); } Evas_Object *AlarmView::GetEvasObject() { - return content; + return content_; } void AlarmView::ButtonClicked(void *data, Evas_Object *obj, void *event_info) { AlarmView *view = static_cast(data); - if (view->onClicked) view->onClicked(); + if (view->onClicked_) view->onClicked_(); +} + +void AlarmView::DismissPopupCallback(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *popup = static_cast(data); + evas_object_del(popup); +} + +void AlarmView::PopupDeleteItemCallback(void *data, Evas_Object *obj, void *event_info) +{ + AlarmView *view = static_cast(data); + if (view->onDeleteClicked_) view->onDeleteClicked_(); + evas_object_del(view->popup_); +} + +void AlarmView::ShowDeletePopup() +{ + popup_ = elm_popup_add(elm_object_top_widget_get(content_)); + elm_popup_align_set(popup_, ELM_NOTIFY_ALIGN_FILL, 1.0); + evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_smart_callback_add(popup_, "block,clicked", AlarmView::DismissPopupCallback, popup_); + eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK, AlarmView::DismissPopupCallback, popup_); + + Evas_Object *list = elm_list_add(popup_); + elm_list_mode_set(list, ELM_LIST_EXPAND); + evas_object_show(list); + + elm_list_item_append(list, "Delete", NULL, NULL, AlarmView::PopupDeleteItemCallback, this); + elm_object_content_set(popup_, list); + evas_object_show(popup_); } diff --git a/clock/src/View/DeleteAlarmView.cpp b/clock/src/View/DeleteAlarmView.cpp new file mode 100644 index 0000000..964db0c --- /dev/null +++ b/clock/src/View/DeleteAlarmView.cpp @@ -0,0 +1,282 @@ +#include "View/DeleteAlarmView.h" +#include "log.h" + +#include + +using namespace model; +using namespace utils; + +namespace view { + +struct ItemData { + DeleteAlarmView *instance; + char *name; + bool active; + bool selected; + WeekFlags flags; + Time time; + Elm_Object_Item *it; + Evas_Object *check; +}; + +static char *WeekFlag2FormattedString(WeekFlags flags) +{ + std::stringstream weekflags; + + weekflags << (flags.IsOn(WeekDay::MONDAY) ? "M" : "M"); + weekflags << (flags.IsOn(WeekDay::TUESDAY) ? "T" : "T"); + weekflags << (flags.IsOn(WeekDay::WEDNESDAY) ? "W" : "W"); + weekflags << (flags.IsOn(WeekDay::THURSDAY) ? "T" : "T"); + weekflags << (flags.IsOn(WeekDay::FRIDAY) ? "F" : "F"); + weekflags << (flags.IsOn(WeekDay::SATURDAY) ? "S" : "S"); + weekflags << (flags.IsOn(WeekDay::SUNDAY) ? "S" : "S"); + + return strdup(weekflags.str().c_str()); +} + +static char *Time2FormattedString(const Time &time) +{ + std::stringstream formatted_time; + + formatted_time << time.Format(FORMAT_12H); + formatted_time << " "; + formatted_time << time.Meridiem(); + formatted_time << ""; + + return strdup(formatted_time.str().c_str()); +} + +DeleteAlarmView::DeleteAlarmView() + : all_selected_(false) +{ + PushPage(); +} + +void DeleteAlarmView::ItemSelectToggle(void *data, Evas_Object *obj, void *event) +{ + ItemData *id = static_cast(data); + id->selected = !id->selected; + if (!id->selected) { + id->instance->all_selected_ = false; + elm_check_state_set(id->instance->all_selected_check_, id->instance->all_selected_); + } + id->instance->UpdateTitle(); +} + +void DeleteAlarmView::ItemSelected(void *data, Evas_Object *obj, void *event) +{ + ItemData *id = static_cast(data); + id->selected = !id->selected; + if (id->check) { + elm_check_state_set(id->check, id->selected); + } + if (!id->selected) { + id->instance->all_selected_ = false; + elm_check_state_set(id->instance->all_selected_check_, id->instance->all_selected_); + } + id->instance->UpdateTitle(); + elm_genlist_item_selected_set(id->it, EINA_FALSE); +} + +void DeleteAlarmView::CreateContent() +{ + elm_object_item_style_set(navi_item_, "basic"); + + // left toolbar button + left_btn_ = elm_button_add(GetNaviframe()); + elm_object_text_set(left_btn_, "CANCEL"); + elm_object_style_set(left_btn_, "naviframe/title_left"); + evas_object_smart_callback_add(left_btn_, "clicked", OnCancelButtonClickedCb, this); + evas_object_show(left_btn_); + + // right toolbar button + right_btn_ = elm_button_add(GetNaviframe()); + elm_object_style_set(right_btn_, "naviframe/title_right"); + elm_object_text_set(right_btn_, "DELETE"); + evas_object_smart_callback_add(right_btn_, "clicked", OnDeleteButtonClickedCb, this); + evas_object_show(right_btn_); + + // main scrollable content + content_ = elm_genlist_add(GetNaviframe()); + evas_object_size_hint_expand_set(content_, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(content_, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_genlist_mode_set(content_, ELM_LIST_COMPRESS); + elm_genlist_homogeneous_set(content_, EINA_TRUE); + evas_object_smart_callback_add(content_, "realized", DeleteAlarmView::ItemRealized, this); + evas_object_show(content_); + + // fill created parts in object item + elm_object_item_part_text_set(navi_item_, "elm.text.title", "0 selected"); + elm_object_item_part_content_set(navi_item_, "title_left_btn", left_btn_); + elm_object_item_part_content_set(navi_item_, "title_right_btn", right_btn_); + elm_object_item_content_set(navi_item_, content_); + + CreateSelectAllItem(); +} + +void DeleteAlarmView::ItemSelectAllClicked(void *data, Evas_Object *obj, void *event) +{ + Elm_Object_Item *it = static_cast(event); + DeleteAlarmView *view = static_cast(data); + + view->all_selected_ = !view->all_selected_; + + view->SelectAllStateSet(view->all_selected_); + if (view->all_selected_check_) + elm_check_state_set(view->all_selected_check_, view->all_selected_); + + view->UpdateTitle(); + elm_genlist_item_selected_set(it, EINA_FALSE); +} + +void DeleteAlarmView::CreateSelectAllItem() +{ + Elm_Genlist_Item_Class *itc = elm_genlist_item_class_new(); + Elm_Genlist_Item *it; + + itc->item_style = "select_all"; + itc->func.text_get = [](void *data, Evas_Object *obj, const char *part) -> char* { + if (!strcmp(part, "elm.text")) { + return strdup("Select all"); + } + return nullptr; + }; + itc->func.content_get = [](void *data, Evas_Object *obj, const char *part) -> Evas_Object* { + DeleteAlarmView *view = static_cast(data); + if (!strcmp(part, "sw.check")) { + view->all_selected_check_ = elm_check_add(obj); + elm_check_state_set(view->all_selected_check_, view->all_selected_); + evas_object_show(view->all_selected_check_); + return view->all_selected_check_; + } + return nullptr; + }; + it = elm_genlist_item_append(content_, itc, this, NULL, ELM_GENLIST_ITEM_NONE, + DeleteAlarmView::ItemSelectAllClicked, this); + elm_genlist_item_select_mode_set(it, ELM_OBJECT_SELECT_MODE_ALWAYS); + + elm_genlist_item_class_unref(itc); +} + +void DeleteAlarmView::ItemRealized(void *data, Evas_Object *obj, void *info) +{ + Elm_Object_Item *it = static_cast(info); + ItemData *id = static_cast(elm_object_item_data_get(it)); + + // return if select all item + if (!id) return; + + if (id->active) + elm_object_item_signal_emit(id->it, "alarm,state,enabled", "clock"); + else + elm_object_item_signal_emit(id->it, "alarm,state,disabled", "clock"); +} + +void DeleteAlarmView::DestroyContent() +{ + evas_object_del(content_); + evas_object_del(left_btn_); + evas_object_del(right_btn_); +} + +void DeleteAlarmView::OnCancelButtonClickedCb(void *data, Evas_Object *obj, void *event) +{ + DeleteAlarmView *view = static_cast(data); + if (view->onCancelButtonClicked_) view->onCancelButtonClicked_(); +} + +void DeleteAlarmView::OnDeleteButtonClickedCb(void *data, Evas_Object *obj, void *event) +{ + DeleteAlarmView *view = static_cast(data); + if (view->onDeleteButtonClicked_) view->onDeleteButtonClicked_(); +} + +int DeleteAlarmView::ItemAppend(utils::Time time, const char *name, + const model::WeekFlags flags, bool active) +{ + ItemData *data = new ItemData; + Elm_Genlist_Item_Class *itc; + + data->instance = this; + data->name = name ? strdup(name) : nullptr; + data->flags = flags; + data->active = active; + data->time = time; + data->selected = false; + + itc = elm_genlist_item_class_new(); + itc->item_style = "alarm"; + itc->func.content_get = [](void *data, Evas_Object *obj, const char *part) -> Evas_Object* { + ItemData *id = static_cast(data); + if (!strcmp(part, "onoff")) { + id->check = elm_check_add(obj); + evas_object_propagate_events_set(id->check, EINA_FALSE); + elm_check_state_set(id->check, id->selected ? EINA_TRUE : EINA_FALSE); + evas_object_smart_callback_add(id->check, "changed", DeleteAlarmView::ItemSelectToggle, id); + evas_object_show(id->check); + return id->check; + } + return nullptr; + }; + itc->func.text_get = [](void *data, Evas_Object *obj, const char *part) -> char* { + ItemData *id = static_cast(data); + if (!strcmp(part, "name")) + return strdup(id->name); + if (!strcmp(part, "time")) + return Time2FormattedString(id->time); + if (!strcmp(part, "weekflags")) + return WeekFlag2FormattedString(id->flags); + return NULL; + }; + itc->func.del = [](void *data, Evas_Object *obj) { + ItemData *id = static_cast(data); + delete id->name; + delete id; + }; + + data->it = elm_genlist_item_append(content_, + itc, + data, + NULL, + ELM_GENLIST_ITEM_NONE, + DeleteAlarmView::ItemSelected, data); + elm_genlist_item_class_unref(itc); + + return (uintptr_t)data->it; +} + +std::vector DeleteAlarmView::GetSelectedItems() const +{ + std::vector selected_ids; + Elm_Object_Item *it = elm_genlist_nth_item_get(content_, 1); + + while (it) { + ItemData *data = static_cast(elm_object_item_data_get(it)); + if (data->selected) + selected_ids.push_back((uintptr_t)it); + it = elm_genlist_item_next_get(it); + } + return selected_ids; +} + +void DeleteAlarmView::SelectAllStateSet(bool state) +{ + Elm_Object_Item *it = elm_genlist_nth_item_get(content_, 1); + + while (it) { + ItemData *data = static_cast(elm_object_item_data_get(it)); + data->selected = state; + if (data->check) elm_check_state_set(data->check, data->selected); + it = elm_genlist_item_next_get(it); + } +} + +void DeleteAlarmView::UpdateTitle() +{ + char buf[64]; + std::vector ids = GetSelectedItems(); + snprintf(buf, sizeof(buf), "%d selected", ids.size()); + elm_object_item_part_text_set(navi_item_, "elm.text.title", buf); +} + +} -- 2.7.4