Refactor Clock: generalize multi timezones and single timezone cases

After this refactoring:
1. Timezones parses only once on start and the we refer to saved values. All time_zone.isString() checks gone to the constructor.
2. Single timezone case handling as case of multi timezoned logic.
3. Scroll event seems more clear now.
4. Tooltip template parses on start to check if there calendar placeholder or not. To do not calculate calendar_text() if not necessary.
This commit is contained in:
Sergey Mishin 2021-10-03 16:48:21 +00:00
parent 6eb9606f23
commit 110c66dd32
No known key found for this signature in database
GPG Key ID: BFFA09D74430117B
2 changed files with 75 additions and 44 deletions

View File

@ -17,6 +17,8 @@ struct waybar_time {
date::zoned_seconds ztime; date::zoned_seconds ztime;
}; };
const std::string kCalendarPlaceholder = "calendar";
class Clock : public ALabel { class Clock : public ALabel {
public: public:
Clock(const std::string&, const Json::Value&); Clock(const std::string&, const Json::Value&);
@ -26,18 +28,19 @@ class Clock : public ALabel {
private: private:
util::SleeperThread thread_; util::SleeperThread thread_;
std::locale locale_; std::locale locale_;
const date::time_zone* time_zone_; std::vector<const date::time_zone*> time_zones_;
bool fixed_time_zone_; int current_time_zone_idx_;
int time_zone_idx_;
date::year_month_day cached_calendar_ymd_ = date::January/1/0; date::year_month_day cached_calendar_ymd_ = date::January/1/0;
std::string cached_calendar_text_; std::string cached_calendar_text_;
bool is_calendar_in_tooltip_;
bool handleScroll(GdkEventScroll* e); bool handleScroll(GdkEventScroll* e);
auto calendar_text(const waybar_time& wtime) -> std::string; auto calendar_text(const waybar_time& wtime) -> std::string;
auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void; auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void;
auto first_day_of_week() -> date::weekday; auto first_day_of_week() -> date::weekday;
bool setTimeZone(Json::Value zone_name); const date::time_zone* current_timezone();
bool is_timezone_fixed();
}; };
} // namespace waybar::modules } // namespace waybar::modules

View File

@ -14,17 +14,51 @@
using waybar::modules::waybar_time; using waybar::modules::waybar_time;
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), fixed_time_zone_(false) { : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true),
current_time_zone_idx_(0),
is_calendar_in_tooltip_(false)
{
if (config_["timezones"].isArray() && !config_["timezones"].empty()) { if (config_["timezones"].isArray() && !config_["timezones"].empty()) {
time_zone_idx_ = 0; for (const auto& zone_name: config_["timezones"]) {
setTimeZone(config_["timezones"][time_zone_idx_]); if (!zone_name.isString() || zone_name.asString().empty()) {
} else { time_zones_.push_back(nullptr);
setTimeZone(config_["timezone"]); continue;
} }
if (fixed_time_zone_) { time_zones_.push_back(
date::locate_zone(
zone_name.asString()
)
);
}
// If we parse all timezones and no one is good, add nullptr to the tmezones vector, to mark that we need to show localtime
if (!time_zones_.size()) {
time_zones_.push_back(nullptr);
}
} else {
time_zones_.push_back(
date::locate_zone(
config_["timezone"].asString()
)
);
}
if (!is_timezone_fixed()) {
spdlog::warn("As using a timezone, some format args may be missing as the date library haven't got a release since 2018."); spdlog::warn("As using a timezone, some format args may be missing as the date library haven't got a release since 2018.");
} }
// Check if we have to particular placeholder in tooltip format, to know what to calculate on update
if (config_["tooltip-format"].isString()) {
std::string trimmedFormat = config_["tooltip-format"].asString();
trimmedFormat.erase(std::remove_if(trimmedFormat.begin(),
trimmedFormat.end(),
[](unsigned char x){return std::isspace(x);}),
trimmedFormat.end());
if (trimmedFormat.find("{" + kCalendarPlaceholder + "}") != std::string::npos) {
is_calendar_in_tooltip_ = true;
}
}
if (config_["locale"].isString()) { if (config_["locale"].isString()) {
locale_ = std::locale(config_["locale"].asString()); locale_ = std::locale(config_["locale"].asString());
} else { } else {
@ -40,53 +74,46 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
}; };
} }
auto waybar::modules::Clock::update() -> void { const date::time_zone* waybar::modules::Clock::current_timezone() {
if (!fixed_time_zone_) { return time_zones_[current_time_zone_idx_] ? time_zones_[current_time_zone_idx_] : date::current_zone();
// Time zone can change. Be sure to pick that.
time_zone_ = date::current_zone();
} }
bool waybar::modules::Clock::is_timezone_fixed() {
return time_zones_[current_time_zone_idx_] != nullptr;
}
auto waybar::modules::Clock::update() -> void {
auto time_zone = current_timezone();
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
waybar_time wtime = {locale_, waybar_time wtime = {locale_,
date::make_zoned(time_zone_, date::floor<std::chrono::seconds>(now))}; date::make_zoned(time_zone, date::floor<std::chrono::seconds>(now))};
std::string text = "";
std::string text; if (!is_timezone_fixed()) {
if (!fixed_time_zone_) {
// As date dep is not fully compatible, prefer fmt // As date dep is not fully compatible, prefer fmt
tzset(); tzset();
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now)); auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
text = fmt::format(format_, localtime); text = fmt::format(format_, localtime);
label_.set_markup(text);
} else { } else {
text = fmt::format(format_, wtime); text = fmt::format(format_, wtime);
label_.set_markup(text);
} }
label_.set_markup(text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
const auto calendar = calendar_text(wtime); std::string calendarText = "";
if (is_calendar_in_tooltip_) {
calendarText = calendar_text(wtime);
}
auto tooltip_format = config_["tooltip-format"].asString(); auto tooltip_format = config_["tooltip-format"].asString();
auto tooltip_text = fmt::format(tooltip_format, wtime, fmt::arg("calendar", calendar)); text = fmt::format(tooltip_format, wtime, fmt::arg("calendar", calendarText));
label_.set_tooltip_markup(tooltip_text); }
} else { }
label_.set_tooltip_markup(text); label_.set_tooltip_markup(text);
}
}
// Call parent update // Call parent update
ALabel::update(); ALabel::update();
} }
bool waybar::modules::Clock::setTimeZone(Json::Value zone_name) {
if (!zone_name.isString() || zone_name.asString().empty()) {
fixed_time_zone_ = false;
return false;
}
time_zone_ = date::locate_zone(zone_name.asString());
fixed_time_zone_ = true;
return true;
}
bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) { bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) {
// defer to user commands if set // defer to user commands if set
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) { if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) {
@ -97,17 +124,18 @@ bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) {
if (dir != SCROLL_DIR::UP && dir != SCROLL_DIR::DOWN) { if (dir != SCROLL_DIR::UP && dir != SCROLL_DIR::DOWN) {
return true; return true;
} }
if (!config_["timezones"].isArray() || config_["timezones"].empty()) { if (time_zones_.size() == 1) {
return true; return true;
} }
auto nr_zones = config_["timezones"].size();
auto nr_zones = time_zones_.size();
if (dir == SCROLL_DIR::UP) { if (dir == SCROLL_DIR::UP) {
size_t new_idx = time_zone_idx_ + 1; size_t new_idx = current_time_zone_idx_ + 1;
time_zone_idx_ = new_idx == nr_zones ? 0 : new_idx; current_time_zone_idx_ = new_idx == nr_zones ? 0 : new_idx;
} else { } else {
time_zone_idx_ = time_zone_idx_ == 0 ? nr_zones - 1 : time_zone_idx_ - 1; current_time_zone_idx_ = current_time_zone_idx_ == 0 ? nr_zones - 1 : current_time_zone_idx_ - 1;
} }
setTimeZone(config_["timezones"][time_zone_idx_]);
update(); update();
return true; return true;
} }