Skip to content

Commit

Permalink
GNOME - CurrencyConverterDialog
Browse files Browse the repository at this point in the history
  • Loading branch information
nlogozzo committed Mar 12, 2024
1 parent 1c2e6a4 commit 1a20c9a
Show file tree
Hide file tree
Showing 37 changed files with 2,659 additions and 852 deletions.
2 changes: 1 addition & 1 deletion docs/po/denaro.pot
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-03-01 22:21-0500\n"
"POT-Creation-Date: 2024-03-12 19:14-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down
1 change: 1 addition & 0 deletions org.nickvision.money.gnome/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
if(LINUX)
add_executable(org.nickvision.money.gnome
"src/controls/currencyconverterdialog.cpp"
"src/helpers/builder.cpp"
"src/views/mainwindow.cpp"
"src/views/preferencesdialog.cpp"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using Gtk 4.0;
using Adw 1;

Adw.Window root {
width-request: 360;
default-width: 440;
modal: true;
resizable: true;

content: Adw.ToastOverlay toastOverlay {
Adw.ToolbarView {
[top]
Adw.HeaderBar header {
title-widget: Adw.WindowTitle {
title: _("Currency Converter");
};
}

Gtk.WindowHandle {
Gtk.Box {
orientation: vertical;
spacing: 24;
margin-start: 24;
margin-end: 24;
margin-bottom: 24;

Adw.PreferencesGroup {
title: _("Currency");

header-suffix: Gtk.Box {
orientation: horizontal;
spacing: 6;

Gtk.Button switchButton {
valign: center;
tooltip-text: _("Switch Currencies");

Adw.ButtonContent {
label: _("Switch");
icon-name: "update-symbolic";
}

styles ["flat"]
}
};

Adw.ComboRow sourceCurrencyRow {
title: _("Source");
}

Adw.ComboRow resultCurrencyRow {
title: _("Result");
}
}

Adw.PreferencesGroup {
title: _("Amount");

Adw.EntryRow sourceAmountRow { }

Adw.EntryRow resultAmountRow {
editable: false;

[suffix]
Gtk.Button copyResultButton {
valign: center;
tooltip-text: _("Copy Result Amount");
icon-name: "edit-copy-symbolic";

styles ["flat"]
}
}
}
}
}
}
};

Gtk.ShortcutController {
Gtk.Shortcut {
trigger: "Escape";
action: "action(window.close)";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef CURRENCYCONVERTERDIALOG_H
#define CURRENCYCONVERTERDIALOG_H

#include <string>
#include <adwaita.h>

namespace Nickvision::Money::GNOME::Controls
{
/**
* @brief A dialog for converting currencies.
*/
class CurrencyConverterDialog
{
public:
/**
* @brief Constructs a CurrencyConverterDialog.
* @param parent The GtkWindow object of the parent window
* @param iconName The name of the icon to use for the window
*/
CurrencyConverterDialog(GtkWindow* parent, const std::string& iconName);
/**
* @brief Destructs a CurrencyConverterDialog.
*/
~CurrencyConverterDialog();
/**
* @brief Shows the CurrencyConverterDialog and waits for it to close.
*/
void run();

private:
void switchCurrencies();
void onSourceCurrencyChanged();
void onResultCurrencyChanged();
void onSourceAmountChanged();
void copyResult();
void onCurrencyChange();
GtkBuilder* m_builder;
GtkWindow* m_parent;
AdwWindow* m_window;
GtkStringList* m_currencyList;
};
}

#endif //CURRENCYCONVERTERDIALOG_H
8 changes: 8 additions & 0 deletions org.nickvision.money.gnome/include/views/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ namespace Nickvision::Money::GNOME::Views
* @param app The GtkApplication object of the running app
*/
MainWindow(const std::shared_ptr<Shared::Controllers::MainWindowController>& controller, GtkApplication* app);
/**
* @brief Destructs a MainWindow.
*/
~MainWindow();
/**
* @brief Gets the GObject object for the main window.
* @return The GObject for the main window
Expand All @@ -48,6 +52,10 @@ namespace Nickvision::Money::GNOME::Views
* @param args Nickvision::Notifications::ShellNotificationSentEventArgs
*/
void onShellNotificationSent(const Nickvision::Notifications::ShellNotificationSentEventArgs& args);
/**
* @brief Displays the currency converter dialog.
*/
void currencyConverter();
/**
* @brief Quits the application.
*/
Expand Down
150 changes: 150 additions & 0 deletions org.nickvision.money.gnome/src/controls/currencyconverterdialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#include "controls/currencyconverterdialog.h"
#include <libnick/localization/gettext.h>
#include "helpers/builder.h"
#include "helpers/currencyhelpers.h"
#include "models/currencyconversionservice.h"

using namespace Nickvision::Money::Shared;
using namespace Nickvision::Money::Shared::Models;

namespace Nickvision::Money::GNOME::Controls
{
CurrencyConverterDialog::CurrencyConverterDialog(GtkWindow* parent, const std::string& iconName)
: m_builder{ BuilderHelpers::fromBlueprint("currency_converter_dialog") },
m_parent{ parent },
m_window{ ADW_WINDOW(gtk_builder_get_object(m_builder, "root")) },
m_currencyList{ gtk_string_list_new(nullptr) }
{
gtk_window_set_transient_for(GTK_WINDOW(m_window), m_parent);
gtk_window_set_icon_name(GTK_WINDOW(m_window), iconName.c_str());
//Signals
g_signal_connect(gtk_builder_get_object(m_builder, "switchButton"), "clicked", G_CALLBACK(+[](GtkButton*, gpointer data){ reinterpret_cast<CurrencyConverterDialog*>(data)->switchCurrencies(); }), this);
g_signal_connect(gtk_builder_get_object(m_builder, "sourceCurrencyRow"), "notify::selected-item", G_CALLBACK(+[](GObject*, GParamSpec*, gpointer data){ reinterpret_cast<CurrencyConverterDialog*>(data)->onSourceCurrencyChanged(); }), this);
g_signal_connect(gtk_builder_get_object(m_builder, "resultCurrencyRow"), "notify::selected-item", G_CALLBACK(+[](GObject*, GParamSpec*, gpointer data){ reinterpret_cast<CurrencyConverterDialog*>(data)->onResultCurrencyChanged(); }), this);
g_signal_connect(gtk_builder_get_object(m_builder, "sourceAmountRow"), "changed", G_CALLBACK(+[](GtkEditable*, gpointer data){ reinterpret_cast<CurrencyConverterDialog*>(data)->onSourceAmountChanged(); }), this);
g_signal_connect(gtk_builder_get_object(m_builder, "copyResultButton"), "clicked", G_CALLBACK(+[](GtkButton*, gpointer data){ reinterpret_cast<CurrencyConverterDialog*>(data)->copyResult(); }), this);
}

CurrencyConverterDialog::~CurrencyConverterDialog()
{
g_object_unref(m_currencyList);
gtk_window_destroy(GTK_WINDOW(m_window));
g_object_unref(m_builder);
}

void CurrencyConverterDialog::run()
{
const std::map<std::string, double>& conversionRates{ CurrencyConversionService::getConversionRates("USD") };
if(conversionRates.empty())
{
AdwMessageDialog* messageDialog{ ADW_MESSAGE_DIALOG(adw_message_dialog_new(m_parent, _("Error"), _("Unable to load currency data. Please try again. If the error still persists, report a bug."))) };
adw_message_dialog_add_response(messageDialog, "close", _("Close"));
adw_message_dialog_set_default_response(messageDialog, "close");
adw_message_dialog_set_close_response(messageDialog, "close");
g_signal_connect(messageDialog, "response", G_CALLBACK(+[](AdwMessageDialog* self, const char*, gpointer){ gtk_window_destroy(GTK_WINDOW(self)); }), nullptr);
gtk_window_present(GTK_WINDOW(messageDialog));
}
else
{
unsigned int usdIndex{ 0 };
unsigned int eurIndex{ 0 };
unsigned int i{ 0 };
for(const std::pair<const std::string, double>& pair : conversionRates)
{
gtk_string_list_append(m_currencyList, pair.first.c_str());
if(pair.first == "USD")
{
usdIndex = i;
}
else if(pair.first == "EUR")
{
eurIndex = i;
}
i++;
}
adw_combo_row_set_model(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "sourceCurrencyRow")), G_LIST_MODEL(m_currencyList));
adw_combo_row_set_model(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "resultCurrencyRow")), G_LIST_MODEL(m_currencyList));
adw_combo_row_set_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "sourceCurrencyRow")), usdIndex);
adw_combo_row_set_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "resultCurrencyRow")), eurIndex);
gtk_window_present(GTK_WINDOW(m_window));
while(gtk_widget_is_visible(GTK_WIDGET(m_window)))
{
g_main_context_iteration(g_main_context_default(), false);
}
}
}

void CurrencyConverterDialog::switchCurrencies()
{
unsigned int sourceIndex{ adw_combo_row_get_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "sourceCurrencyRow"))) };
unsigned int resultIndex{ adw_combo_row_get_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "resultCurrencyRow"))) };
adw_combo_row_set_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "resultCurrencyRow")), sourceIndex);
adw_combo_row_set_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "sourceCurrencyRow")), resultIndex);
}

void CurrencyConverterDialog::onSourceCurrencyChanged()
{
adw_preferences_row_set_title(ADW_PREFERENCES_ROW(gtk_builder_get_object(m_builder, "sourceAmountRow")), gtk_string_list_get_string(m_currencyList, adw_combo_row_get_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "sourceCurrencyRow")))));
onCurrencyChange();
}

void CurrencyConverterDialog::onResultCurrencyChanged()
{
adw_preferences_row_set_title(ADW_PREFERENCES_ROW(gtk_builder_get_object(m_builder, "resultAmountRow")), gtk_string_list_get_string(m_currencyList, adw_combo_row_get_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "resultCurrencyRow")))));
onCurrencyChange();
}

void CurrencyConverterDialog::onSourceAmountChanged()
{
onCurrencyChange();
}

void CurrencyConverterDialog::copyResult()
{
std::string resultText{ gtk_editable_get_text(GTK_EDITABLE(gtk_builder_get_object(m_builder, "resultAmountRow"))) };
if(!resultText.empty())
{
GdkClipboard* clipboard{ gtk_widget_get_clipboard(GTK_WIDGET(gtk_builder_get_object(m_builder, "resultAmountRow"))) };
gdk_clipboard_set_text(clipboard, resultText.c_str());
adw_toast_overlay_add_toast(ADW_TOAST_OVERLAY(gtk_builder_get_object(m_builder, "toastOverlay")), adw_toast_new(_("Result was copied to clipboard.")));
}
}

void CurrencyConverterDialog::onCurrencyChange()
{
std::string sourceText{ gtk_editable_get_text(GTK_EDITABLE(gtk_builder_get_object(m_builder, "sourceAmountRow"))) };
std::string resultText{ gtk_editable_get_text(GTK_EDITABLE(gtk_builder_get_object(m_builder, "resultAmountRow"))) };
gtk_widget_remove_css_class(GTK_WIDGET(gtk_builder_get_object(m_builder, "sourceAmountRow")), "error");
gtk_widget_remove_css_class(GTK_WIDGET(gtk_builder_get_object(m_builder, "resultAmountRow")), "error");
if(sourceText.empty())
{
gtk_editable_set_text(GTK_EDITABLE(gtk_builder_get_object(m_builder, "resultAmountRow")), "");
}
else
{
double sourceAmount{ 0 };
try
{
sourceAmount = std::stod(sourceText);
}
catch(const std::exception&)
{
gtk_widget_add_css_class(GTK_WIDGET(gtk_builder_get_object(m_builder, "sourceAmountRow")), "error");
gtk_editable_set_text(GTK_EDITABLE(gtk_builder_get_object(m_builder, "resultAmountRow")), "");
return;
}
std::string sourceCurrency{ gtk_string_list_get_string(m_currencyList, adw_combo_row_get_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "sourceCurrencyRow")))) };
std::string resultCurrency{ gtk_string_list_get_string(m_currencyList, adw_combo_row_get_selected(ADW_COMBO_ROW(gtk_builder_get_object(m_builder, "resultCurrencyRow")))) };
std::optional<CurrencyConversion> conversion{ CurrencyConversionService::convert(sourceCurrency, sourceAmount, resultCurrency) };
if (conversion.has_value())
{
std::string resultAmountString{ CurrencyHelpers::toAmountString(conversion->getResultAmount(), CurrencyHelpers::getSystemCurrency(), false, true) };
gtk_editable_set_text(GTK_EDITABLE(gtk_builder_get_object(m_builder, "resultAmountRow")), resultAmountString.c_str());
}
else
{
gtk_widget_add_css_class(GTK_WIDGET(gtk_builder_get_object(m_builder, "resultAmountRow")), "error");
}
}
}
}
18 changes: 18 additions & 0 deletions org.nickvision.money.gnome/src/views/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
#include <libnick/app/appinfo.h>
#include <libnick/notifications/shellnotification.h>
#include <libnick/localization/gettext.h>
#include "controls/currencyconverterdialog.h"
#include "helpers/builder.h"
#include "views/preferencesdialog.h"

using namespace Nickvision::Money::GNOME::Controls;
using namespace Nickvision::Money::Shared::Controllers;
using namespace Nickvision::App;
using namespace Nickvision::Events;
Expand Down Expand Up @@ -37,6 +39,10 @@ namespace Nickvision::Money::GNOME::Views
g_signal_connect(actQuit, "activate", G_CALLBACK(+[](GSimpleAction*, GVariant*, gpointer data){ reinterpret_cast<MainWindow*>(data)->quit(); }), this);
g_action_map_add_action(G_ACTION_MAP(m_window), G_ACTION(actQuit));
SET_ACCEL_FOR_ACTION(m_app, "win.quit", "<Ctrl>Q");
//Currency Converter Action
GSimpleAction* actCurrencyConverter{ g_simple_action_new("currencyConverter", nullptr) };
g_signal_connect(actCurrencyConverter, "activate", G_CALLBACK(+[](GSimpleAction*, GVariant*, gpointer data){ reinterpret_cast<MainWindow*>(data)->currencyConverter(); }), this);
g_action_map_add_action(G_ACTION_MAP(m_window), G_ACTION(actCurrencyConverter));
//Preferences Action
GSimpleAction* actPreferences{ g_simple_action_new("preferences", nullptr) };
g_signal_connect(actPreferences, "activate", G_CALLBACK(+[](GSimpleAction*, GVariant*, gpointer data){ reinterpret_cast<MainWindow*>(data)->preferences(); }), this);
Expand All @@ -54,6 +60,12 @@ namespace Nickvision::Money::GNOME::Views
SET_ACCEL_FOR_ACTION(m_app, "win.about", "F1");
}

MainWindow::~MainWindow()
{
gtk_window_destroy(GTK_WINDOW(m_window));
g_object_unref(m_builder);
}

GObject* MainWindow::gobj() const
{
return G_OBJECT(m_window);
Expand Down Expand Up @@ -90,6 +102,12 @@ namespace Nickvision::Money::GNOME::Views
}
}

void MainWindow::currencyConverter()
{
CurrencyConverterDialog currencyConverter{ GTK_WINDOW(m_window), m_controller->getAppInfo().getId() };
currencyConverter.run();
}

void MainWindow::preferences()
{
PreferencesDialog preferences{ m_controller->createPreferencesViewController(), GTK_WINDOW(m_window) };
Expand Down
Loading

0 comments on commit 1a20c9a

Please sign in to comment.