Skip to content

Commit

Permalink
Prepare to identify locations by position, not name
Browse files Browse the repository at this point in the history
Refs: #56
  • Loading branch information
orontee committed Oct 8, 2023
1 parent 1db558e commit cd5015e
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 190 deletions.
8 changes: 8 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Changed

- Display location country as returned by Geocoding API. Previously
user input was shown.

⚠️ Note that this introduces a breaking change in how the application
used to dump its state, and favorites will be lost with this change.

[#56](https://github.com/orontee/taranis/issues/56)

- URL encode location when requesting Geocoding API
[#55](https://github.com/orontee/taranis/issues/55)

Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ integration](./docs/desktop_integration.md).

## Configuration

The application stores the user preferences (unit system, default
location, etc.) in a configuration file writen under
`system/config/taranis.cfg`.
The application stores the user preferences (unit system, API key,
etc.) in a configuration file writen under `system/config/taranis.cfg`
(path may vary depending on the use of profiles).

Note that the Openweather API key distributed with the application is
rate limited. It's possible to specify a custom key using the
`api_key` keyword in the configuration file (See
rate limited. The `api_key` keyword in the configuration file can be
used to specify a custom key (See
[OpenWeather](https://openweathermap.org) for instructions on how to
register and generate API keys).

Expand Down
4 changes: 2 additions & 2 deletions docs/desktop_integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ To customize the application icon and group:
[taranis_f.bmp](./taranis_f.bmp).

2. Then the `/mnt/ext1/system/config/desktop/view.json` file must be
edited on the e-reader (the file path may vary depending on the
use of profiles):
edited on the e-reader (path may vary depending on the use of
profiles):

```diff
--- "/mnt/ext1/system/profiles/matthias/config/desktop/view.orig.json" 2023-09-30 20:20:34.454795306 +0200
Expand Down
121 changes: 50 additions & 71 deletions src/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include <type_traits>
#include <vector>

#include "boost/log/trivial.hpp"
#include "config.h"
#include "errors.h"
#include "events.h"
Expand Down Expand Up @@ -165,21 +164,6 @@ class App {
this->model->unit_system = unit_system_from_config;
}

const auto town_from_config =
config.read_string("location_town"s, "Paris"s);
const auto country_from_config =
config.read_string("location_country"s, "France"s);

const bool is_town_or_country_obsolete =
(town_from_config != this->model->location.town) or
(country_from_config != this->model->location.country);

if (is_town_or_country_obsolete) {
this->model->location.town = town_from_config;
this->model->location.country = country_from_config;
this->clear_model_weather_conditions();
}

const auto display_daily_forecast_from_config =
config.read_bool("display_daily_forecast"s, false);
const bool is_display_daily_forecast_obsolete =
Expand All @@ -198,8 +182,7 @@ class App {
}

const bool is_data_obsolete =
is_api_key_obsolete or is_unit_system_obsolete or
is_town_or_country_obsolete or is_language_obsolete;
is_api_key_obsolete or is_unit_system_obsolete or is_language_obsolete;
// temperatures, wind speed and weather description are computed
// by the backend thus unit system or language change implies that
// data are obsolete
Expand All @@ -222,11 +205,11 @@ class App {
if (param_one == CustomEvent::change_daily_forecast_display) {
const bool enable = not this->model->display_daily_forecast;
this->update_configured_display_daily_forecast(enable);
} else if (param_one == CustomEvent::change_location) {
} else if (param_one == CustomEvent::search_location) {
auto *const raw_location =
reinterpret_cast<std::array<char, 256> *>(GetCurrentEventExData());
const std::string location{raw_location->data()};
this->update_configured_location(location);
this->search_location(location);
return 1;
} else if (param_one == CustomEvent::change_unit_system) {
this->update_configured_unit_system(static_cast<UnitSystem>(param_two));
Expand All @@ -242,7 +225,7 @@ class App {
const size_t history_index = param_two;
auto location = this->history->get_location(history_index);
if (location) {
this->write_config_location(*location);
this->set_model_location(*location);
} else {
DialogSynchro(ICON_WARNING, "Title", "Location not found!",
GetLangText("Ok"), nullptr, nullptr);
Expand Down Expand Up @@ -299,10 +282,9 @@ class App {
clear_model_weather_conditions();

const auto units = Units{this->model}.to_string();
this->service->set_location(this->model->location);
try {
this->service->fetch_data(this->model->location.town,
this->model->location.country, currentLang(),
units);
this->service->fetch_data(currentLang(), units);

this->model->current_condition = this->service->get_current_condition();

Expand Down Expand Up @@ -359,63 +341,60 @@ class App {
GetLangText("Ok"), nullptr, &handle_about_dialog_button_clicked);
}

static Location parse_location(const std::string &location) {
BOOST_LOG_TRIVIAL(debug) << "Parsing location";

std::stringstream to_parse{location};
std::vector<std::string> tokens;
std::string token;
while (std::getline(to_parse, token, ',')) {
ltrim(token);
rtrim(token);
tokens.push_back(token);
}
if (tokens.size() == 1) {
auto town = tokens[0];
town[0] = std::toupper(town[0]);
return {town, ""};
} else if (tokens.size() > 1) {
auto country = tokens[tokens.size() - 1];
country[0] = std::toupper(country[0]);

auto town = location.substr(0, location.size() - country.size());
ltrim(town);
rtrim(town);
town[0] = std::toupper(town[0]);

return {town, country};
}
BOOST_LOG_TRIVIAL(error) << "Failed to parse location " << location;
throw InvalidLocation{};
}

void update_configured_location(const std::string &text) const {
BOOST_LOG_TRIVIAL(debug) << "Updating configured location";

if (text == format_location(this->model->location)) {
BOOST_LOG_TRIVIAL(debug) << "No need to updated configured location";

return;
}
void search_location(const std::string &location_description) {
try {
auto location = App::parse_location(text);

this->write_config_location(location);
const auto [town, country] =
parse_location_description(location_description);
const auto locations = service->search_location(town, country);

if (locations.size() == 1) {
this->set_model_location(locations[0]);
} else if (locations.size() > 1) {
// TODO display list
}
} catch (const InvalidLocation &error) {
const auto event_handler = GetEventHandler();
SendEvent(event_handler, EVT_CUSTOM, CustomEvent::warning_emitted,
CustomEventParam::invalid_location);
} catch (const ConnectionError &error) {
BOOST_LOG_TRIVIAL(debug)
<< "Connection error while refreshing weather conditions "
<< error.what();
Message(
ICON_WARNING, GetLangText("Network error"),
GetLangText("Failure while fetching weather data. Check your network "
"connection."),
App::error_dialog_delay);
} catch (const RequestError &error) {
BOOST_LOG_TRIVIAL(debug)
<< "Request error while refreshing weather conditions "
<< error.what();
Message(
ICON_WARNING, GetLangText("Network error"),
GetLangText("Failure while fetching weather data. Check your network "
"connection."),
App::error_dialog_delay);
} catch (const ServiceError &error) {
BOOST_LOG_TRIVIAL(debug)
<< "Service error while refreshing weather conditions "
<< error.what();
Message(ICON_WARNING, GetLangText("Service unavailable"), error.what(),
App::error_dialog_delay);
}
}

void write_config_location(const Location &location) const {
BOOST_LOG_TRIVIAL(debug) << "Writing config location";
void set_model_location(const Location &location) const {
BOOST_LOG_TRIVIAL(debug) << "Updating model location";

Config config;
config.write_string("location_town"s, location.town);
config.write_string("location_country"s, location.country);
if (location == this->model->location) {
BOOST_LOG_TRIVIAL(debug) << "No need to update configured location";

Config::config_changed();
return;
}
this->model->location = location;

const auto event_handler = GetEventHandler();
SendEvent(event_handler, EVT_CUSTOM, CustomEvent::refresh_data, 0);
}

void update_configured_unit_system(UnitSystem unit_system) {
Expand Down
1 change: 1 addition & 0 deletions src/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace taranis {
enum CustomEvent {
// Commands
change_daily_forecast_display,
search_location,
change_location,
change_unit_system,
display_alert,
Expand Down
18 changes: 8 additions & 10 deletions src/locationbox.cc
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
#include "locationbox.h"

#include "events.h"
#include "inkview.h"
#include "util.h"

std::array<char, 256> location;
std::array<char, 256> input_text;

void taranis::keyboard_handler(char *text) {
const auto event_handler = GetEventHandler();
SendEventEx(event_handler, EVT_CUSTOM, CustomEvent::change_location, 0,
&location);
SendEventEx(event_handler, EVT_CUSTOM, CustomEvent::search_location, 0,
&input_text);
}

void taranis::LocationBox::edit_location() {
const auto title = GetLangText("Enter location");
std::memset(location.data(), '\0', location.size());
std::memset(input_text.data(), '\0', input_text.size());

const auto current_location = format_location(this->model->location);
std::memcpy(location.data(), current_location.data(),
current_location.size());
OpenKeyboard(title, location.data(), location.size() - 1, KBD_NORMAL,
const auto formatted_location_name = format_location(this->model->location);
std::memcpy(input_text.data(), formatted_location_name.data(),
formatted_location_name.size());
OpenKeyboard(title, input_text.data(), input_text.size() - 1, KBD_NORMAL,
keyboard_handler);
}
76 changes: 44 additions & 32 deletions src/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,27 @@ namespace taranis {
enum UnitSystem { standard = 0, metric = 1, imperial = 2 };

struct Location {
std::string town;

Location() : longitude{NAN}, latitude{NAN} {}

Location(double longitude, double latitude, const std::string &name,
const std::string &country, const std::string &state)
: longitude{longitude}, latitude{latitude}, name{name}, country{country},
state{state} {}

Location(const Location &other)
: longitude{other.longitude}, latitude{other.latitude}, name{other.name},
country{other.country}, state{other.state} {}

double longitude;
double latitude;
std::string name;
std::string country;
std::string state;

bool operator==(const Location &other) const {
return this->country == other.country and this->town == other.town;
return this->longitude == other.longitude and
this->latitude == other.latitude;
}
};

Expand Down Expand Up @@ -101,23 +117,23 @@ struct Condition {
std::time_t date;
std::time_t sunrise;
std::time_t sunset;
long double temperature;
long double felt_temperature;
double temperature;
double felt_temperature;
int pressure;
int humidity;
long double uv_index;
double uv_index;
int clouds;
int visibility;
long double probability_of_precipitation;
long double wind_speed;
double probability_of_precipitation;
double wind_speed;
int wind_degree;
long double wind_gust;
double wind_gust;

Weather weather;
std::string weather_description;
std::string weather_icon_name;
long double rain; // mm/h
long double snow; // mm/h
double rain; // mm/h
double snow; // mm/h
};

// Can contain daily forecast
Expand All @@ -127,32 +143,32 @@ struct DailyCondition {
std::time_t sunset;
std::time_t moonrise;
std::time_t moonset;
long double moon_phase;
double moon_phase;
int pressure;
int humidity;
long double dew_point;
long double wind_speed;
double dew_point;
double wind_speed;
int wind_degree;
long double wind_gust;
double wind_gust;
int clouds;
long double probability_of_precipitation;
long double uv_index;
long double rain; // mm
long double snow; // mm
double probability_of_precipitation;
double uv_index;
double rain; // mm
double snow; // mm

Weather weather{CLEAR_SKY};
std::string weather_description;
std::string weather_icon_name;
long double temperature_day;
long double temperature_min;
long double temperature_max;
long double temperature_night;
long double temperature_evening;
long double temperature_morning;
long double felt_temperature_day;
long double felt_temperature_night;
long double felt_temperature_evening;
long double felt_temperature_morning;
double temperature_day;
double temperature_min;
double temperature_max;
double temperature_night;
double temperature_evening;
double temperature_morning;
double felt_temperature_day;
double felt_temperature_night;
double felt_temperature_evening;
double felt_temperature_morning;
};

struct Alert {
Expand All @@ -167,10 +183,6 @@ struct HistoryItem {
const Location location;
bool favorite;

HistoryItem(const std::string &town, const std::string &country,
bool favorite)
: location{town, country}, favorite{favorite} {}

HistoryItem(const Location &location, bool favorite)
: location{location}, favorite{favorite} {}
};
Expand Down
Loading

0 comments on commit cd5015e

Please sign in to comment.