[AlarmListView] Date picker feature. 06/142106/8 submit/tizen/20170807.062126 submit/tizen/20170807.062634
authorKamil Lipiszko <k.lipiszko@samsung.com>
Wed, 2 Aug 2017 12:16:28 +0000 (14:16 +0200)
committerKamil Lipiszko <k.lipiszko@samsung.com>
Sun, 6 Aug 2017 13:18:57 +0000 (15:18 +0200)
Enable to create alarm that is called only once at the selected date.

Change-Id: I24358e8b8d8bd2729deba1475569e4766aa319bf

14 files changed:
clock/inc/Model/WeekFlags.h
clock/inc/Utils/Time.h
clock/inc/View/AlarmListView.h
clock/inc/View/EditAlarmView.h
clock/res/edje/alarm.edc
clock/res/edje/edit_alarm.edc
clock/src/Model/Alarm.cpp
clock/src/Model/WeekFlags.cpp
clock/src/Presenter/AlarmListPresenter.cpp
clock/src/Presenter/EditAlarmPresenter.cpp
clock/src/Utils/PopupManager.cpp
clock/src/Utils/Time.cpp
clock/src/View/AlarmListView.cpp
clock/src/View/EditAlarmView.cpp

index a4e1a8fc584d4ab109dfc8656ec3665a16f538b3..fc13c551d831156d4fe0ee1d8584aac0e69a304a 100644 (file)
@@ -57,7 +57,7 @@ namespace model {
                         */
                        WeekFlags(utils::IReader &r);
 
-                       /** 
+                       /**
                         * @brief Default constructor using WeekDay flags
                         * @param[in] day day mask.
                         */
@@ -69,12 +69,17 @@ namespace model {
                         */
                        void AddDay(WeekDay day);
 
-                       /** 
+                       /**
                         * @brief Remove day flag from week flags
                         * @param[in] day to remove.
                         */
                        void RemoveDay(WeekDay day);
 
+                       /**
+                        * @brief Clear flags.
+                        */
+                       void Clear();
+
                        /**
                         * @brief Check if flag is set for given day
                         * @param[in] day to check.
index b9249e302845a2fe2b125fc120d8fbd82cc9becc..6ce191ea65286eabc7f02ef44614701fd1b030a0 100644 (file)
@@ -63,6 +63,13 @@ namespace utils {
                         */
                        Time(const Time &tm);
 
+                       /**
+                        * @brief Constructor from tm structure
+                        */
+
+                       Time(const tm &time) : Time(time.tm_year + 1900, Time::Int2Month(time.tm_mon),
+                                               time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, 0) {}
+
                        /**
                         * @brief Creates new Time in given timezone
                         *
@@ -151,6 +158,26 @@ namespace utils {
                         */
                        static Time Now(void);
 
+                       /**
+                        * Return difference between times in days
+                        *
+                        * @param end End of the time
+                        * @param start Start of the time
+                        *
+                        * @return Number of days
+                        */
+                       static int DateCompare(const Time &end, const Time &start);
+
+                       /**
+                        * Return difference between hours in seconds
+                        *
+                        * @param end End of the time
+                        * @param start Start of the time
+                        *
+                        * @return Number of seconds
+                        */
+                       static int TimeCompare(const Time &end, const Time &start);
+
                        /**
                         * @brief Returns Time adjusted to localtime.
                         */
@@ -197,11 +224,39 @@ namespace utils {
                         */
                        static int GetTimezoneOffset(const char *timezone);
 
+                       /**
+                        * @brief Converts number into the Time::Month
+                        *
+                        * @param month Number of the month [0 - 11]
+                        *
+                        * @return Time::Month with related number
+                        */
+                       static Time::Month Int2Month(int month);
+
                        /**
                         * @brief Get current timezone
                         */
                        static const std::string &GetCurrentTimezone();
 
+                       /**
+                        * @brief If time already passed, get next day.
+                        *
+                        * @param time The time
+                        *
+                        * @return Passed time or next day if already passed.
+                        */
+                       static Time GetUpcoming(const Time &time);
+
+                       /**
+                        * @brief Get total time difference
+                        *
+                        * @param start Start time
+                        * @param end End time
+                        *
+                        * @return Difference between times in seconds
+                        */
+                       static int Difftime(const Time &end, const Time &start);
+
                private:
                        Time(double milliseconds, const std::string &tz);
 
@@ -216,6 +271,8 @@ namespace utils {
                                        const char *skeleton);
                        static std::string GenerateBestPattern(const char *locale,
                                        const char *skeleton, unsigned int m = 2);
+
+                       static constexpr int SECONDS_PER_DAY = 24 * 60 * 60;
        };
 } /* utils */
 
index 9d2d9add01e6b2fc25c7b839e17eb88969216cfd..e4f138ba82f95a9cd62b654a64ab85ff583f3382 100644 (file)
@@ -151,6 +151,7 @@ namespace view {
                        void CreateNoContentLayout(Evas_Object *parent);
                        static void SetItemCheckboxStatus(Elm_Object_Item *item, bool is_snoozed);
                        static void SetItemActiveStatus(Elm_Object_Item *it, bool active);
+                       static void SetItemVisibleDateOnly(Elm_Object_Item *it, model::WeekFlags flags);
                        static void SetCheckboxStatus(Evas_Object *check, bool is_snoozed);
                        static void UpdateItemData(ItemData *data);
        };
index 5377406004024afc7b887e74c1152d3c301c1e49..1f72d9a0495aa462225ae48b09f61b36c5ac17fb 100644 (file)
@@ -155,6 +155,27 @@ namespace view {
                         */
                        bool IsDiscardPopupVisible() const;
 
+                       /**
+                        * @brief Shows date picker popup
+                        */
+                       void ShowDatePickerPopup();
+
+                       /**
+                        * @brief Hides date picker popup
+                        */
+                       void HideDatePickerPopup();
+
+                       /**
+                        * @brief Creates formatted relative date
+                        *
+                        * @param relativeTo Time the time is relative
+                        * @param time The time
+                        *
+                        * @return Formatted date
+                        */
+                       static std::string GetRelativeDateFormat(const utils::Time &relativeTo,
+                                       const utils::Time &time);
+
                protected:
                        virtual void CreateContent(Evas_Object *parent);
                        virtual void DestroyContent();
@@ -167,10 +188,13 @@ namespace view {
                        Evas_Object *icon_slider_;
                        Evas_Object *discard_popup_;
                        Evas_Object *type_popup_;
+                       Evas_Object *datepicker_popup_;
+                       Evas_Object *calendar_;
 
                        /* child view of EditAlarmView */
                        WeekFlagsView week_flags_view_;
 
+                       Elm_Object_Item *date_it_;
                        Elm_Object_Item *type_it_;
                        Elm_Object_Item *repeat_it_;
                        Elm_Object_Item *volume_it_;
@@ -196,19 +220,28 @@ namespace view {
                        static void SnoozeItemSelectedCallback(void *data, Evas_Object *obj, void *event);
                        static void ChooseAlarmToneItemSelectedCallback(void *data, Evas_Object *obj, void *event);
                        static void BackButtonOnMainClicked(void *data, Evas_Object *obj, void *event);
+                       static void BackButtonOnDatepickerClicked(void *data, Evas_Object *obj, void *event);
                        static void PopupCancelButtonClicked(void *data, Evas_Object *obj, void *event_info);
                        static void PopupDiscardButtonClicked(void *data, Evas_Object *obj, void *event_info);
+                       static void DateButtonClicked(void *data, Evas_Object *obj, void *event_info);
                        static void Del(void *data, Evas_Object *obj, void *event_info);
+                       static void PopupDatePickerCancelClicked(void *data, Evas_Object *obj, void *event_info);
+                       static void PopupDatePickerSetClicked(void *data, Evas_Object *obj, void *event_info);
+                       static void PopupDatePickerDateChanged(void *data, Evas_Object *obj, void *event_info);
 
                        void CreateGenlistItems();
                        void ShowSetTypePopup();
                        void OnWeekFlagsPagePopped();
+                       void PopupDatePickerCreateCalendar();
 
                        void UpdateVolumeIcon(bool mute);
                        void UpdateAlarmType(bool mute);
+                       void UpdateTime(utils::Time time);
+                       void UpdateView();
                        utils::RingtonePicker picker_;
                        void RingtonePathUpdateCallback();
                        const char *GetTitle();
+                       std::string GetDate();
 
                        utils::Connection time_format_change_listener_;
                        void TimeFormatChanged();
index 0621d40591d464f3e0145222776fe13d5a34424a..e1381e9eaa1f373ae759c1a25dcd99f608a18c73 100644 (file)
@@ -41,6 +41,15 @@ collections {
                                name: "font3_dim";
                                base: "font=Tizen:style=Regular color=#00000066 font_size=32 ellipsis=1.0";
                        }
+                       //TODO: Below fonts do not exist in GUI guide
+                       style {
+                               name: "date_normal";
+                               base: "font=Tizen:style=Regular color=#59b03aff font_size=32 ellipsis=1.0";
+                       }
+                       style {
+                               name: "date_dim";
+                               base: "font=Tizen:style=Regular color=#59b03a66 font_size=32 ellipsis=1.0";
+                       }
                        style {
                                name: "font_weekflags_normal";
                                base: "font=Tizen:style=Regular font_size=32";
@@ -54,7 +63,7 @@ collections {
                                tag: "off" "+ color=#b3b3b366";
                        }
                }
-               data.item: "texts" "time name weekflags ampm";
+               data.item: "texts" "time name weekflags ampm date";
                data.item: "contents" "onoff";
                data.item: "banded_bg_area" "elm.swallow.bg";
                parts {
@@ -100,6 +109,7 @@ collections {
                                        text.style: "font1_normal";
                                        text.min: 1 0;
                                        text.max: 1 0;
+                                       text.elipsis: -1;
                                }
                                desc { "disabled";
                                        inherit: "default";
@@ -182,6 +192,10 @@ collections {
                                        inherit: "default";
                                        text.style: "font_weekflags_dim";
                                }
+                               desc { "date";
+                                       inherit: "default";
+                                       visible: 0;
+                               }
                        }
                        group { "repeat"; scale;
                                source: "repeat-icon";
@@ -203,6 +217,9 @@ collections {
                                        max: 0 0;
                                        visible: 0;
                                }
+                               desc { "date";
+                                       inherit: "hidden";
+                               }
                        }
                        textblock { "name"; scale;
                                desc { "default";
@@ -222,6 +239,33 @@ collections {
                                        inherit: "default";
                                        text.style: "font3_dim";
                                }
+                               desc { "date";
+                                       inherit: "default";
+                                       visible: 0;
+                               }
+                       }
+                       textblock { "date"; scale;
+                               desc { "default";
+                                       fixed: 1 1;
+                                       min: 268 43;
+                                       max: 268 43;
+                                       align: 0.0 0.5;
+                                       rel1 {
+                                               relative: 1.0 0.0;
+                                               to_x: "repeat";
+                                               to_y: "spacer.name.week";
+                                       }
+                                       rel2.to: "spacer.name.week";
+                                       text.style: "date_normal";
+                               }
+                               desc { "disabled";
+                                       inherit: "default";
+                                       text.style: "date_dim";
+                               }
+                               desc { "hidden";
+                                       inherit: "default";
+                                       visible: 0;
+                               }
                        }
                }
                program { "enabled";
@@ -232,6 +276,7 @@ collections {
                        target: "weekflags";
                        target: "time";
                        target: "ampm";
+                       target: "date";
                        after: "enable,repeat";
                }
                program { "disabled";
@@ -242,6 +287,7 @@ collections {
                        target: "weekflags";
                        target: "time";
                        target: "ampm";
+                       target: "date";
                        after: "disable,repeat";
                }
                program { "show,repeat,icon";
@@ -264,6 +310,20 @@ collections {
                        action: SIGNAL_EMIT "state,enabled" "";
                        target: "repeat";
                }
+               program { "show,date,only";
+                       signal: "alarm,state,date,visible";
+                       source: "clock";
+                       action: STATE_SET "date" 0.0;
+                       target: "repeat";
+                       target: "weekflags";
+                       target: "name";
+               }
+               program { "hide,date";
+                       signal: "alarm,state,date,hidden";
+                       source: "clock";
+                       action: STATE_SET "hidden" 0.0;
+                       target: "date";
+               }
        }
        group { name: "repeat-icon";
                images {
index 2b17f9a872a2de1515fccd63f7bec0c1324279d8..037f4d2d2d3f6613fbf5e62d3869c9c3f4af10f0 100644 (file)
 
 #include "color_classes.edc"
 
+externals {
+        external: "feedback";
+}
+
+
 collections {
+       plugins {
+               plugin {
+                       name: "touch_sound_plugin";
+                       source: "feedback";
+                       param: "FEEDBACK_TYPE_SOUND FEEDBACK_PATTERN_TAP";
+               }
+       }
        base_scale: 2.6;
        group { name: "elm/genlist/item/alarm:editfield/default";
                styles {
@@ -169,4 +181,203 @@ collections {
                        }
                }
        }
+       group { name: "elm/genlist/item/alarm:timepicker/default";
+               data.item: "texts" "elm.text.date";
+               data.item: "contents" "elm.swallow.btn elm.swallow.timepicker";
+               data.item: "banded_bg_area" "elm.swallow.bg";
+               styles {
+                       style {
+                               name: "ATO0022";
+                               base: "font=Tizen:style=Light color=#3db9cc wrap=none font_size=34 align=center";
+                       }
+               }
+               parts {
+                       spacer { "base"; scale;
+                               desc {
+                                       min: 0 474;
+                               }
+                       }
+                       swallow { "elm.swallow.bg"; scale;
+                               desc { "default";
+                                       rel1.to: "base";
+                                       rel2.to: "base";
+                               }
+                       }
+                       swallow { "elm.swallow.timepicker"; scale;
+                               desc {
+                                       min: 0 392;
+                                       max: -1 392;
+                                       fixed: 0 1;
+                                       align: 0.5 1.0;
+                                       rel1 {
+                                               relative: 0.0 1.0;
+                                               to_x: "base";
+                                               to_y: "pd.date.timepicker";
+                                       }
+                                       rel2.to: "base";
+                               }
+                       }
+                       spacer { "pd.top"; scale;
+                               desc {
+                                       min: 0 32;
+                                       max: -1 32;
+                                       align: 0.5 0.0;
+                                       fixed: 0 1;
+                               }
+                       }
+                       spacer { "pd.left"; scale;
+                               desc {
+                                       min: 52 0;
+                                       max: 52 -1;
+                                       fixed: 1 0;
+                                       align: 0.0 0.5;
+                               }
+
+                       }
+                       spacer { "pd.right"; scale;
+                               desc {
+                                       min: 60 0;
+                                       max: 60 -1;
+                                       fixed: 1 0;
+                                       align: 1.0 0.5;
+                               }
+
+                       }
+                       spacer { "pd.text.btn"; scale;
+                               desc {
+                                       min: 40 0;
+                                       max: 40 -1;
+                                       fixed: 1 0;
+                                       align: 0.0 0.0;
+                                       rel1 {
+                                               relative: 1.0 1.0;
+                                               to_x: "elm.text.date";
+                                               to_y: "pd.top";
+                                       }
+                               }
+                       }
+                       spacer { "pd.date.timepicker"; scale;
+                               desc {
+                                       min: 0 32;
+                                       max: -1 32;
+                                       fixed: 0 1;
+                                       align: 0.5 0.0;
+                                       rel1 {
+                                               relative: 0.0 1.0;
+                                               to_y: "elm.text.date";
+                                       }
+                               }
+                       }
+                       textblock { "elm.text.date"; scale;
+                               desc {
+                                       min: 408 45;
+                                       max: 408 45;
+                                       fixed: 1 1;
+                                       align: 0.0 0.0;
+                                       rel1 {
+                                               relative: 1.0 1.0;
+                                               to_x: "pd.left";
+                                               to_y: "pd.top";
+                                       }
+                                       text {
+                                               style: "ATO0022";
+                                               elipsis: -1;
+                                               align: 0.5 0.5;
+                                               min: 1 0;
+                                               max: 1 0;
+                                       }
+                               }
+                       }
+                       swallow { "elm.swallow.btn"; scale;
+                               desc {
+                                       min: 160 50;
+                                       max: 160 50;
+                                       fixed: 1 1;
+                                       align: 0.0 0.0;
+                                       rel1 {
+                                               relative: 1.0 1.0;
+                                               to_x: "pd.text.btn";
+                                               to_y: "pd.top";
+                                       }
+                                       rel2 {
+                                               relative: 0.0 0.0;
+                                               to_x: "pd.right";
+                                       }
+                               }
+                       }
+               }
+       }
+
+       group { "elm/button/base/resizable";
+               styles {
+                       style {
+                               name: "test";
+                               base: "font=Tizen:style=Light color=#FAFAFA font_size=36 wrap=none elipsis=-1";
+                       }
+               }
+               images {
+                       image: "button_bg.png" COMP;
+               }
+               data.item: "texts" "elm.text.date";
+               parts {
+                       image { "bg"; scale;
+                               desc { "default";
+                                       color: 82 199 217 255;
+                                       min: 0 50;
+                                       max: -1 50;
+                                       fixed: 0 1;
+                                       image.normal: "button_bg.png";
+                               }
+                       }
+                       image { "bg_effect"; scale;
+                               repeat;
+                               desc { "default";
+                                       color: 0 0 0 0;
+                                       rel1.to: "bg";
+                                       rel2.to: "bg";
+                                       image.normal: "button_bg.png";
+                               }
+                               desc { "pressed";
+                                       inherit: "default";
+                                       color: 0 0 0 100;
+                               }
+                       }
+                       textblock { "elm.text"; scale;
+                               repeat;
+                               desc { "default";
+                                       align: 0.5 0.5;
+                                       text {
+                                               style: "test";
+                                               align: 0.5 0.5;
+                                               elipsis: -1;
+                                               min: 1 0;
+                                               max: 1 0;
+                                       }
+                                       rel.to: "bg";
+                               }
+                       }
+                       program {
+                               signal: "mouse,clicked,*";
+                               source: "bg";
+                               sequence {
+                                       action: SIGNAL_EMIT "elm,action,click" "";
+                                       action: RUN_PLUGIN "touch_sound_plugin";
+                               }
+
+                       }
+                       program {
+                               signal: "mouse,down,*";
+                               source: "bg";
+                               action: STATE_SET "pressed";
+                               target: "bg_effect";
+                       }
+                       program {
+                               signal: "mouse,up,*";
+                               source: "bg";
+                               action: STATE_SET "default";
+                               target: "bg_effect";
+                               transition: DECEL 0.3;
+                       }
+               }
+       }
 };
index eb100cdc2f8c5931bfe0391e881fa4adea047b8c..a6e6dd5f98f79bc8e8c5441b9115758166f103c5 100644 (file)
@@ -77,16 +77,19 @@ void Alarm::Activate()
                return;
        }
 
-       err = alarm_schedule_with_recurrence_week_flag(
-                       control,
-                       &tmtime,
-                       flags.GetBitMask(),
-                       &alarm_id);
-       if (err == ALARM_ERROR_NONE) {
+       if (flags.Empty())
+               err = alarm_schedule_once_at_date(control, &tmtime, &alarm_id);
+       else
+               err = alarm_schedule_with_recurrence_week_flag(
+                               control,
+                               &tmtime,
+                               flags.GetBitMask(),
+                               &alarm_id);
+
+       if (err == ALARM_ERROR_NONE)
                activated = true;
-       } else {
-               ERR("alarm_schedule_with_recurrence_week_flag failed: %s", get_error_message(err));
-       }
+       else
+               ERR("Alarm schedule failed: %s", get_error_message(err));
 
        app_control_destroy(control);
        ObservableObject::OnChanged();
@@ -143,11 +146,15 @@ void Alarm::Snooze()
 
 void Alarm::Dismiss()
 {
-       if (!IsActivated() || !IsSnoozeEnabled())
+       if (!IsActivated())
                return;
 
        CancelPlatformAlarm(snooze.alarm_id);
        snooze.attempt = 0;
+
+       if (flags.Empty())
+               activated = false;
+
        ObservableObject::OnChanged();
 }
 
index bd57a870bf0ca2e1d7873b98d95101629174051f..c0bd912b3ab2be4c8dc42c72deea2bda14e79395 100644 (file)
@@ -31,6 +31,10 @@ void WeekFlags::RemoveDay(WeekDay day) {
        raw_flags &= ~static_cast<unsigned int>(day);
 };
 
+void WeekFlags::Clear() {
+       raw_flags = 0;
+}
+
 bool WeekFlags::IsOn(WeekDay day) {
        return (raw_flags & static_cast<unsigned int>(day)) == static_cast<unsigned int>(day);
 };
index 6001a80fde010bcf2fa8a8fc785608f8b145f5bf..ce1360ca4e8e42394642b0956739c0de64162b33 100644 (file)
@@ -111,13 +111,19 @@ void AlarmListPresenter::OnItemActiveStatusChanged(int idx)
 
        auto &alarm_it = it->second;
 
-       if (alarm_it->IsSnoozed()) {
+       if (alarm_it->IsSnoozed())
                alarm_it->Dismiss();
-       else {
-               if (alarm_it->IsActivated()) {
+       else {
+               if (alarm_it->IsActivated())
                        alarm_it->Deactivate();
-               else {
+               else {
                        alarm_it->Activate();
+                       if (alarm_it->GetWeekFlags().Empty()) {
+                               alarm_it->SetTime(Time::GetUpcoming(alarm_it->GetTime()));
+
+                               view_->ItemUpdate(it->first, alarm_it->GetTime(), alarm_it->GetName().c_str(),
+                                               alarm_it->GetWeekFlags(), alarm_it->IsActivated(), alarm_it->IsSnoozed());
+                       }
                }
        }
 
index c89c80c0c1801c497df6a75cd16b8cdcbd23c14c..ede7d9af457c1666f9a2c9788386c90a57599a69 100644 (file)
@@ -118,7 +118,12 @@ AlarmList::Iterator EditAlarmPresenter::GetMatchingAlarm(const std::string &name
 void EditAlarmPresenter::UpdateAlarm(AlarmList::Iterator it)
 {
        auto alarm = *it;
+
        SetAlarmProperties(alarm, view_.GetData());
+
+       if (alarm.GetWeekFlags().Empty() && Time::Difftime(alarm.GetTime(), Time::Now()) <= 0)
+               alarm.Deactivate();
+
        model_.Replace(it, alarm);
 }
 
@@ -134,7 +139,9 @@ void EditAlarmPresenter::CreateNewAlarm()
        }
 
        SetAlarmProperties(new_alarm, view_.GetData());
-       new_alarm.Activate();
+
+       if (!new_alarm.GetWeekFlags().Empty() || Time::Difftime(new_alarm.GetTime(), Time::Now()) > 0)
+               new_alarm.Activate();
 
        model_.Add(new_alarm);
 }
index feda1dca6d44b0291ce5259c4cebbe9850e976c0..4b1a4bd48690e370042e5b7e736e08f4e8352f74 100644 (file)
@@ -26,6 +26,11 @@ void PopupManager::CreatePopup(ui::IView &parent, const std::string &text, doubl
        if (popup_)
                DestroyPopup();
 
+       if (!parent.GetEvasObject()) {
+               ERR("Parent's Evas_Object is null");
+               return;
+       }
+
        popup_ = elm_popup_add(parent.GetEvasObject());
        if (!popup_) {
                ERR("Could not create popup");
index 54b80625108709acd8959bf0b011855d5f48bfb0..2d9e18553b39507b3279666be7560f4325225460 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "Utils/Time.h"
 #include "Utils/Log.h"
+#include "Utils/Translate.h"
 
 #include <cstring>
 #include <cmath>
@@ -287,6 +288,46 @@ bool Time::operator==(const Time &a) const
        return a.milliseconds_ == milliseconds_;
 }
 
+static int difftime(std::tm start, std::tm end)
+{
+       time_t endTime = mktime(&end);
+       time_t startTime = mktime(&start);
+
+       if (endTime == (time_t)(-1) || startTime == (time_t)(-1)) {
+               return INT_MAX;
+       }
+
+       return (int)(difftime(endTime, startTime));
+}
+
+int Time::Difftime(const Time &end, const Time &start)
+{
+       return (int)difftime(start.GetTmStruct(), end.GetTmStruct());
+}
+
+int Time::DateCompare(const Time &end, const Time &start)
+{
+       tm endTm = end.GetTmStruct();
+       endTm.tm_sec = 0;
+       endTm.tm_min = 0;
+       endTm.tm_hour = 0;
+
+       tm startTm = start.GetTmStruct();
+       startTm.tm_sec = 0;
+       startTm.tm_min = 0;
+       startTm.tm_hour = 0;
+
+       return (difftime(startTm, endTm) / SECONDS_PER_DAY);
+}
+
+int Time::TimeCompare(const Time &end, const Time &start)
+{
+       tm endTm = end.GetTmStruct();
+       tm startTm = start.GetTmStruct();
+
+       return (difftime(startTm, endTm) % SECONDS_PER_DAY);
+}
+
 Time Time::Now(void)
 {
        i18n_udate handle;
@@ -449,6 +490,44 @@ static int i18n_calendar_month_2_tm_month(int icu_month)
        return -1;
 }
 
+Time::Month Time::Int2Month(int month)
+{
+       if (month < 0 || month > 11) {
+               ERR("Invalid month number");
+               return Time::Month::January;
+       }
+
+       return static_cast<Time::Month>(month);
+}
+
+Time Time::GetUpcoming(const Time &time)
+{
+       Time now = Now();
+       int daysLeft = DateCompare(time, now);
+       int secondsLeft = Time::TimeCompare(time, now);
+
+       int x = 0;
+
+       if (daysLeft == 0 && secondsLeft <= 0)
+               x = 1;
+       else if (daysLeft < 0) {
+               if (secondsLeft > 0)
+                       x = daysLeft*(-1);
+               else
+                       x = daysLeft*(-1) + 1;
+       }
+
+       return Time(
+               time.GetYear(),
+               time.GetMonth(),
+               time.GetDay() + x,
+               time.GetHour(),
+               time.GetMinute(),
+               0,
+               0
+       );
+}
+
 std::tm Time::GetTmStruct() const
 {
        std::tm tmstruct = {0,};
index eab6d1499dabd0735cd202546adfdb1b27671d8c..be129905faf9e194364e8e4cb92e834186398293 100644 (file)
@@ -15,6 +15,7 @@
 */
 
 #include "View/AlarmListView.h"
+#include "View/EditAlarmView.h"
 #include "View/MainView.h"
 #include "Utils/TizenAppUtils.h"
 #include <Elementary.h>
@@ -114,6 +115,14 @@ void AlarmListView::SetItemActiveStatus(Elm_Object_Item *it, bool active)
                elm_object_item_signal_emit(it, "alarm,state,disabled", "clock");
 }
 
+void AlarmListView::SetItemVisibleDateOnly(Elm_Object_Item *it, WeekFlags flags)
+{
+       if (flags.Empty())
+               elm_object_item_signal_emit(it, "alarm,state,date,visible", "clock");
+       else
+               elm_object_item_signal_emit(it, "alarm,state,date,hidden", "clock");
+}
+
 void AlarmListView::UpdateItemData(ItemData *data)
 {
        if (!data) return;
@@ -122,6 +131,7 @@ void AlarmListView::UpdateItemData(ItemData *data)
        SetItemCheckboxStatus(data->it, data->snoozed);
        SetItemActiveStatus(data->it, data->active);
        SetItemRepeatIconVisibility(data->it, (data->flags.OnAny(WeekDay::ALL_WEEK)));
+       SetItemVisibleDateOnly(data->it, data->flags);
 }
 
 void AlarmListView::ItemRealized(void *data, Evas_Object *obj, void *info)
@@ -237,6 +247,11 @@ static char *Ampm2FormattedString(const Time &time)
        return strdup(formatted_time.str().c_str());
 }
 
+static char *Date2FormattedString(const Time &time)
+{
+       return strdup(EditAlarmView::GetRelativeDateFormat(Time::Now(), time).c_str());
+}
+
 char *AlarmListView::TextGet(void *data, Evas_Object *obj, const char *part)
 {
        ItemData *id = static_cast<ItemData*>(data);
@@ -249,6 +264,8 @@ char *AlarmListView::TextGet(void *data, Evas_Object *obj, const char *part)
                return Ampm2FormattedString(id->time);
        if (!strcmp(part, "weekflags"))
                return WeekFlag2FormattedString(id->flags);
+       if (!strcmp(part, "date"))
+               return Date2FormattedString(id->time);
 
        return NULL;
 }
index bb341bf8655da4be4f7ee302655df564a28ade23..7e0be7d6cd9ba2799207ebdd973eb59897b1fa43 100644 (file)
@@ -27,6 +27,7 @@
 #include <efl_extension.h>
 #include <Elementary.h>
 #include <limits>
+#include <sstream>
 
 
 using namespace view;
@@ -39,7 +40,7 @@ using namespace model;
 #define SNOOZE_ICON_PART_NAME "elm.swallow.end"
 
 EditAlarmView::EditAlarmView(view::MainView &main)
-       : PageView(main), discard_popup_(nullptr), week_flags_view_(main, data_.flags), is_muted_(false), main_(main)
+       : PageView(main), content_(nullptr), discard_popup_(nullptr), datepicker_popup_(nullptr), week_flags_view_(main, data_.flags), is_muted_(false), main_(main)
 {
        week_flags_popped_conn_ = week_flags_view_.OnPagePopped.Connect(
                        std::bind(&EditAlarmView::OnWeekFlagsPagePopped, this));
@@ -114,42 +115,9 @@ static std::string GetLabelForWeekFlag(WeekFlags &flag)
        return join(values, " ");
 }
 
-inline static Time::Month ConvertTmMont2TimeMonth(int mon)
-{
-       switch (mon) {
-               case 0:
-                       return Time::Month::January;
-               case 1:
-                       return Time::Month::Febuary;
-               case 2:
-                       return Time::Month::March;
-               case 3:
-                       return Time::Month::April;
-               case 4:
-                       return Time::Month::May;
-               case 5:
-                       return Time::Month::June;
-               case 6:
-                       return Time::Month::July;
-               case 7:
-                       return Time::Month::August;
-               case 8:
-                       return Time::Month::September;
-               case 9:
-                       return Time::Month::October;
-               case 10:
-                       return Time::Month::November;
-               case 11:
-                       return Time::Month::December;
-       }
-       FAT("Invalid struct tm month value");
-       // provide default value;
-       return Time::Month::January;
-}
-
 inline static Time ConvertElmDatetimeTimeToTime(const Elm_Datetime_Time &time)
 {
-       return Time(time.tm_year + 1900, ConvertTmMont2TimeMonth(time.tm_mon), time.tm_mday,
+       return Time(time.tm_year + 1900, Time::Int2Month(time.tm_mon), time.tm_mday,
                        time.tm_hour, time.tm_min, 0, 0);
 }
 
@@ -176,6 +144,7 @@ void EditAlarmView::OnCancelButtonClickedCb(void *data, Evas_Object *obj, void *
 void EditAlarmView::OnConfirmButtonClickedCb(void *data, Evas_Object *obj, void *event_info)
 {
        EditAlarmView *view = static_cast<EditAlarmView*>(data);
+
        view->OnEditDone();
 }
 
@@ -190,6 +159,12 @@ const char *EditAlarmView::GetTitle()
        return NULL;
 }
 
+void EditAlarmView::BackButtonOnDatepickerClicked(void *data, Evas_Object *obj, void *event)
+{
+       EditAlarmView *view = static_cast<EditAlarmView*>(data);
+       view->HideDatePickerPopup();
+}
+
 void EditAlarmView::BackButtonOnMainClicked(void *data, Evas_Object *obj, void *event)
 {
        EditAlarmView *view = static_cast<EditAlarmView*>(data);
@@ -370,6 +345,175 @@ void EditAlarmView::ChooseAlarmToneItemSelectedCallback(void *data, Evas_Object
        elm_genlist_item_selected_set(it, EINA_FALSE);
 }
 
+void EditAlarmView::PopupDatePickerDateChanged(void *data, Evas_Object *obj, void *event_info)
+{
+       EditAlarmView *view = static_cast<EditAlarmView *>(data);
+
+       std::tm calendarTm;
+       elm_calendar_selected_time_get(view->calendar_, &calendarTm);
+
+       Time calendarTime(calendarTm);
+
+       int daysLeft = Time::DateCompare(calendarTime, Time::Now());
+
+       Evas_Object *setButton = elm_object_part_content_get(view->datepicker_popup_, "button2");
+
+       if (daysLeft < 0)
+               elm_object_disabled_set(setButton, EINA_TRUE);
+       else
+               elm_object_disabled_set(setButton, EINA_FALSE);
+}
+
+void EditAlarmView::PopupDatePickerCreateCalendar() {
+
+       if (!datepicker_popup_)
+               return;
+
+       calendar_ = elm_calendar_add(datepicker_popup_);
+       elm_object_content_set(datepicker_popup_, calendar_);
+       evas_object_show(calendar_);
+
+       evas_object_smart_callback_add(calendar_, "changed", PopupDatePickerDateChanged, this);
+
+       tm now = Time::Now().GetTmStruct();
+
+       elm_calendar_selected_time_set(calendar_, &now);
+}
+
+
+void EditAlarmView::PopupDatePickerCancelClicked(void *data, Evas_Object *obj, void *event_info)
+{
+       EditAlarmView *view = static_cast<EditAlarmView*>(data);
+       view->HideDatePickerPopup();
+}
+
+void EditAlarmView::UpdateView()
+{
+       if (repeat_it_)
+               elm_genlist_item_update(repeat_it_);
+       if (date_it_)
+               elm_genlist_item_update(date_it_);
+}
+
+void EditAlarmView::PopupDatePickerSetClicked(void *data, Evas_Object *obj, void *event_info)
+{
+       EditAlarmView *view = static_cast<EditAlarmView*>(data);
+
+       std::tm calendarTm;
+       elm_calendar_selected_time_get(view->calendar_, &calendarTm);
+
+       Time calendarTime(
+                       calendarTm.tm_year + 1900,
+                       Time::Int2Month(calendarTm.tm_mon),
+                       calendarTm.tm_mday,
+                       view->data_.time.GetHour(),
+                       view->data_.time.GetMinute(),
+                       0,
+                       0
+                       );
+
+       view->data_.flags.Clear();
+
+       view->UpdateTime(calendarTime);
+       view->UpdateView();
+
+       view->HideDatePickerPopup();
+}
+
+void EditAlarmView::UpdateTime(Time time)
+{
+       if (data_.flags.Empty()) {
+               data_.time = Time::GetUpcoming(time);
+
+               if (time.GetDay() != data_.time.GetDay())
+                       PopupManager::CreatePopup(*this,
+                                       "Can't set alarms for time in past. Tomorrow's date set.", 3.0);
+       } else {
+               Time now = Time::Now();
+               data_.time = Time(
+                       now.GetYear(),
+                       now.GetMonth(),
+                       now.GetDay(),
+                       data_.time.GetHour(),
+                       data_.time.GetMinute(),
+                       0,
+                       0
+                       );
+       }
+
+}
+
+void EditAlarmView::ShowDatePickerPopup() {
+
+       if (datepicker_popup_)
+               return;
+
+       datepicker_popup_ = elm_popup_add(elm_object_top_widget_get(content_));
+       elm_popup_align_set(datepicker_popup_, ELM_NOTIFY_ALIGN_FILL, 1.0);
+       elm_object_translatable_part_text_set(datepicker_popup_, "title,text", "IDS_CLOCK_HEADER_SET_DATE");
+       eext_object_event_callback_add(datepicker_popup_, EEXT_CALLBACK_BACK,
+                       EditAlarmView::BackButtonOnDatepickerClicked, this);
+
+       Evas_Object *btn = elm_button_add(datepicker_popup_);
+       elm_object_translatable_text_set(btn, "IDS_COM_SK_CANCEL");
+       evas_object_smart_callback_add(btn, "clicked", EditAlarmView::PopupDatePickerCancelClicked, this);
+       elm_object_part_content_set(datepicker_popup_, "button1", btn);
+       evas_object_show(btn);
+
+       btn = elm_button_add(datepicker_popup_);
+       elm_object_translatable_text_set(btn, "IDS_CLD_BUTTON_SET");
+       evas_object_smart_callback_add(btn, "clicked", EditAlarmView::PopupDatePickerSetClicked, this);
+       elm_object_part_content_set(datepicker_popup_, "button2", btn);
+       evas_object_show(btn);
+
+       PopupDatePickerCreateCalendar();
+
+       evas_object_show(datepicker_popup_);
+}
+
+void EditAlarmView::HideDatePickerPopup() {
+
+       if (!datepicker_popup_)
+               return;
+
+       evas_object_del(datepicker_popup_);
+       datepicker_popup_ = nullptr;
+}
+
+void EditAlarmView::DateButtonClicked(void *data, Evas_Object *obj, void *event_info)
+{
+       EditAlarmView *view = static_cast<EditAlarmView *>(data);
+
+       view->ShowDatePickerPopup();
+}
+
+std::string EditAlarmView::GetRelativeDateFormat(const Time &relativeTo, const Time &time)
+{
+       std::stringstream text;
+
+       int daysLeft = Time::DateCompare(time, relativeTo);
+
+       if (daysLeft == 0)
+               text << Translate::Sprintf("IDS_CLOCK_BODY_TODAY") << " - ";
+       else if (daysLeft == 1)
+               text << Translate::Sprintf("IDS_CLOCK_BODY_TOMORROW") << " - ";
+
+       int yearDiff = relativeTo.GetYear() - time.GetYear();
+
+       if (yearDiff != 0)
+               text << time.Format("EEE, d MMM. YYYY");
+       else
+               text << time.Format("EEE, d MMM");
+
+       return text.str();
+}
+
+
+std::string EditAlarmView::GetDate()
+{
+       return GetRelativeDateFormat(Time::Now(), data_.time);
+}
+
 void EditAlarmView::CreateGenlistItems()
 {
        Elm_Genlist_Item_Class *itc;
@@ -377,20 +521,59 @@ void EditAlarmView::CreateGenlistItems()
 
        // time chooser
        itc = elm_genlist_item_class_new();
-       itc->item_style = "full";
+       itc->item_style = "alarm:timepicker";
+       itc->func.text_get = [](void *data, Evas_Object *o, const char *part) -> char * {
+               EditAlarmView *view = static_cast<EditAlarmView*>(data);
+               if (!strcmp(part, "elm.text.date")) {
+                       if (view->data_.flags.Empty())
+                               return strdup(view->GetDate().c_str());
+                       else
+                               return strdup(GetLabelForWeekFlag(view->data_.flags).c_str());
+               }
+
+               return NULL;
+       };
        itc->func.content_get = [](void *data, Evas_Object *o, const char *part) -> Evas_Object* {
                EditAlarmView *view = static_cast<EditAlarmView*>(data);
-               Evas_Object *dt = elm_datetime_add(o);
-               elm_datetime_format_set(dt, SystemSettings::Is24HourFormatPrefered() ? "%k %M" : "%l %M %p");
-               elm_object_style_set(dt, "time_layout"); // from tizen-theme
-               evas_object_smart_callback_add(dt, "changed"
-                               , EditAlarmView::DateTimeChangedCallback, view);
-               auto elm_time = view->data_.time.GetTmStruct();
-               elm_datetime_value_set(dt, &elm_time);
-               evas_object_show(dt);
-               return dt;
+
+               if (!strcmp(part, "elm.swallow.timepicker")) {
+                       EditAlarmView *view = static_cast<EditAlarmView*>(data);
+                       Evas_Object *dt = elm_datetime_add(o);
+                       elm_datetime_format_set(dt, SystemSettings::Is24HourFormatPrefered() ? "%k %M" : "%l %M %p");
+                       elm_object_style_set(dt, "time_layout"); // from tizen-theme
+                       evas_object_smart_callback_add(dt, "changed"
+                                       , EditAlarmView::DateTimeChangedCallback, view);
+                       auto elm_time = view->data_.time.GetTmStruct();
+                       elm_datetime_value_set(dt, &elm_time);
+                       evas_object_show(dt);
+
+                       return dt;
+               } else if (!strcmp(part, "elm.swallow.btn")) {
+
+
+                       ThemeExtension::AddTheme(TizenAppUtils::GetResourcePath(TizenAppUtils::APP_DIR_RESOURCE,
+                                               "edje/edit_alarm.edj"));
+
+                       Evas_Object *btn = elm_button_add(o);
+
+                       if (!elm_object_style_set(btn, "resizable"))
+                               ERR("Button style setting failed");
+                       evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, EVAS_HINT_FILL);
+                       evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+                       elm_object_translatable_text_set(btn, "IDS_CLOCK_BUTTON_DATE_M_SELECT_ABB");
+                       evas_object_smart_callback_add(btn, "clicked", EditAlarmView::DateButtonClicked, view);
+
+                       evas_object_show(btn);
+
+                       return btn;
+               }
+
+               return NULL;
        };
-       elm_genlist_item_append(content_, itc, this, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+
+       date_it_ = elm_genlist_item_append(content_, itc, this, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+       elm_genlist_item_select_mode_set(date_it_, ELM_OBJECT_SELECT_MODE_NONE);
        elm_genlist_item_class_unref(itc);
 
        // repeat flags chooser
@@ -622,13 +805,16 @@ void EditAlarmView::ShowSetTypePopup()
 
 void EditAlarmView::OnWeekFlagsPagePopped(void)
 {
-       elm_genlist_item_update(repeat_it_);
+       UpdateTime(data_.time);
+       UpdateView();
 }
 
 void EditAlarmView::SetData(const AlarmViewInfo &info)
 {
        data_ = info;
        is_muted_ = data_.volume <= 0.0 ? true : false;
+       UpdateTime(data_.time);
+
        elm_genlist_realized_items_update(content_);
 }