diff options
Diffstat (limited to 'ui')
| -rw-r--r-- | ui/include/turns/ui/windows/tracker.hpp | 16 | ||||
| -rw-r--r-- | ui/res/ui.cmb | 40 | ||||
| -rw-r--r-- | ui/src/windows/tracker.cpp | 64 |
3 files changed, 98 insertions, 22 deletions
diff --git a/ui/include/turns/ui/windows/tracker.hpp b/ui/include/turns/ui/windows/tracker.hpp index b1af178..a5fe833 100644 --- a/ui/include/turns/ui/windows/tracker.hpp +++ b/ui/include/turns/ui/windows/tracker.hpp @@ -1,22 +1,28 @@ #ifndef TURNS_UI_WINDOWS_TRACKER_HPP #define TURNS_UI_WINDOWS_TRACKER_HPP -#include "turns/ui/widgets/turn_order_view.hpp" #include "turns/core/turn_order.hpp" +#include "turns/ui/widgets/turn_order_view.hpp" #include <glibmm/refptr.h> #include <glibmm/ustring.h> #include <glibmm/variant.h> +#include <giomm/asyncresult.h> + #include <gtkmm/applicationwindow.h> #include <gtkmm/builder.h> #include <gtkmm/button.h> +#include <gtkmm/filedialog.h> #include <gtkmm/revealer.h> #include <gtkmm/stack.h> #include <gtkmm/widget.h> #include <adwaita.h> +#include <string> +#include <optional> + namespace turns::ui::windows { @@ -28,6 +34,8 @@ namespace turns::ui::windows auto handle_add_participant() -> void; auto handle_delete_participant(Glib::VariantBase param) -> void; auto handle_edit_participant(Glib::VariantBase param) -> void; + auto handle_save() -> void; + auto handle_save_finish(Glib::RefPtr<Gio::AsyncResult> result, Glib::RefPtr<Gtk::FileDialog> dialog) -> void; auto handle_stop() -> void; auto setup_actions() -> void; @@ -37,14 +45,18 @@ namespace turns::ui::windows AdwApplicationWindow * m_adw; Gtk::Revealer * m_controls; Gtk::Widget * m_empty; + AdwToastOverlay * m_overlay; Gtk::Stack * m_stack; Gtk::Button * m_start; AdwWindowTitle * m_title; Glib::RefPtr<core::turn_order> m_turn_order; widgets::turn_order_view * m_turn_order_view; Glib::PropertyProxy<Glib::ustring> m_subtitle; + + std::string m_file_tag{}; + std::optional<std::string> m_file_name{}; }; -} // namespace turns::app::windows +} // namespace turns::ui::windows #endif
\ No newline at end of file diff --git a/ui/res/ui.cmb b/ui/res/ui.cmb index acf1687..58005a6 100644 --- a/ui/res/ui.cmb +++ b/ui/res/ui.cmb @@ -24,10 +24,7 @@ (1,7,"GtkMenuButton","open_main_menu",3,None,"end",None,None,None,None), (1,8,"GtkButton","add_participant",3,None,"start",None,1,None,None), (1,9,"(menu)","main_menu",None,None,None,None,-1,None,None), - (1,10,"(item)",None,9,None,None,None,1,None,None), - (1,11,"GtkStack","stack",2,None,None,None,-1,None,None), - (1,16,"AdwStatusPage","empty",11,None,None,None,-1,None,None), - (1,17,"GtkButton",None,16,None,None,None,-1,None,None), + (1,10,"(item)",None,9,None,None,None,2,None,None), (1,18,"GtkButton","start",3,None,"start",None,2,None,None), (1,19,"(item)",None,9,None,None,None,None,None,None), (1,20,"GtkRevealer","controls",2,None,"bottom",None,-1,None,None), @@ -35,6 +32,11 @@ (1,22,"GtkButton",None,21,None,"start",None,-1,None,None), (1,23,"GtkButton",None,21,None,"center",None,-1,None,None), (1,24,"GtkButton",None,21,None,"end",None,-1,None,None), + (1,25,"(item)",None,9,None,None,None,1,None,None), + (1,26,"AdwToastOverlay","overlay",2,None,None,None,-1,None,None), + (1,30,"GtkStack","stack",26,None,None,None,-1,None,None), + (1,31,"AdwStatusPage","empty",30,None,None,None,None,None,None), + (1,32,"GtkButton",None,31,None,None,None,None,None,None), (2,1,"AdwDialog","participant_editor",None,None,None,None,-1,None,None), (2,2,"AdwToolbarView",None,1,None,None,None,-1,None,None), (2,3,"AdwHeaderBar",None,2,None,"top",None,-1,None,None), @@ -68,7 +70,7 @@ (1,1,"GtkWidget","width-request","360",None,None,None,None,None,None,None,None,None), (1,1,"GtkWindow","default-height","720",None,None,None,None,None,None,None,None,None), (1,1,"GtkWindow","default-width","360",None,None,None,None,None,None,None,None,None), - (1,2,"AdwToolbarView","content",None,None,None,None,None,11,None,None,None,None), + (1,2,"AdwToolbarView","content",None,None,None,None,None,26,None,None,None,None), (1,3,"AdwHeaderBar","title-widget",None,None,None,None,None,6,None,None,None,None), (1,6,"AdwWindowTitle","subtitle","No active turn order",1,None,None,None,None,None,None,None,None), (1,6,"AdwWindowTitle","title","Turns",1,None,None,None,None,None,None,None,None), @@ -80,12 +82,6 @@ (1,8,"GtkWidget","tooltip-text","Add participant",1,None,None,None,None,None,None,None,None), (1,10,"(item)","action","app.quit",None,None,None,None,None,None,None,None,None), (1,10,"(item)","label","_Quit",1,None,None,None,None,None,None,None,None), - (1,11,"GtkStack","transition-type","crossfade",None,None,None,None,None,None,None,None,None), - (1,16,"AdwStatusPage","child",None,None,None,None,None,17,None,None,None,None), - (1,16,"AdwStatusPage","icon-name","contact-new-symbolic",None,None,None,None,None,None,None,None,None), - (1,17,"GtkActionable","action-name","win.add_participant",None,None,None,None,None,None,None,None,None), - (1,17,"GtkButton","label","Add participant",1,None,None,None,None,None,None,None,None), - (1,17,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None), (1,18,"GtkActionable","action-name","win.start",None,None,None,None,None,None,None,None,None), (1,18,"GtkButton","icon-name","media-playback-start-symbolic",None,None,None,None,None,None,None,None,None), (1,18,"GtkWidget","tooltip-text","Start turn order",1,None,None,None,None,None,None,None,None), @@ -102,6 +98,14 @@ (1,24,"GtkActionable","action-name","win.next",None,None,None,None,None,None,None,None,None), (1,24,"GtkButton","icon-name","media-skip-forward-symbolic",None,None,None,None,None,None,None,None,None), (1,24,"GtkWidget","tooltip-markup","Next participant",1,None,None,None,None,None,None,None,None), + (1,25,"(item)","action","win.save",None,None,None,None,None,None,None,None,None), + (1,25,"(item)","label","_Save",1,None,None,None,None,None,None,None,None), + (1,26,"AdwToastOverlay","child",None,None,None,None,None,30,None,None,None,None), + (1,31,"AdwStatusPage","child",None,None,None,None,None,32,None,None,None,None), + (1,31,"AdwStatusPage","icon-name","contact-new-symbolic",None,None,None,None,None,None,None,None,None), + (1,32,"GtkActionable","action-name","win.add_participant",None,None,None,None,None,None,None,None,None), + (1,32,"GtkButton","label","Add participant",1,None,None,None,None,None,None,None,None), + (1,32,"GtkWidget","halign","center",None,None,None,None,None,None,None,None,None), (2,1,"AdwDialog","child",None,None,None,None,None,2,None,None,None,None), (2,1,"AdwDialog","default-widget",None,None,None,None,None,None,None,None,None,None), (2,1,"GtkWidget","hexpand","True",None,None,None,None,None,None,None,None,None), @@ -165,9 +169,6 @@ (2,9,"GtkWidget",1,1,None,None,None,None,None,None), (2,9,"GtkWidget",2,2,None,1,None,None,None,None), (2,9,"GtkWidget",2,3,None,1,None,None,None,None), - (1,17,"GtkWidget",1,1,None,None,None,None,None,None), - (1,17,"GtkWidget",2,2,None,1,None,None,None,None), - (1,17,"GtkWidget",2,3,None,1,None,None,None,None), (3,6,"GtkWidget",1,1,None,None,None,None,None,None), (3,6,"GtkWidget",2,2,None,1,None,None,None,None), (3,2,"GtkWidget",1,1,None,None,None,None,None,None), @@ -200,15 +201,16 @@ (4,2,"GtkWidget",1,1,None,None,None,None,None,None), (4,2,"GtkWidget",2,2,None,1,None,None,None,None), (4,5,"GtkWidget",1,1,None,None,None,None,None,None), - (4,5,"GtkWidget",2,2,None,1,None,None,None,None) + (4,5,"GtkWidget",2,2,None,1,None,None,None,None), + (1,32,"GtkWidget",1,1,None,None,None,None,None,None), + (1,32,"GtkWidget",2,2,None,1,None,None,None,None), + (1,32,"GtkWidget",2,3,None,1,None,None,None,None) </object_data> <object_data_arg> (1,1,"GtkWidget",2,2,"name","background"), (2,6,"GtkWidget",2,2,"name","boxed-list"), (2,9,"GtkWidget",2,2,"name","pill"), (2,9,"GtkWidget",2,3,"name","suggested-action"), - (1,17,"GtkWidget",2,2,"name","pill"), - (1,17,"GtkWidget",2,3,"name","suggested-action"), (3,6,"GtkWidget",2,2,"name","circular"), (3,2,"GtkWidget",2,2,"name","header"), (3,7,"GtkWidget",2,2,"name","title"), @@ -227,6 +229,8 @@ (1,24,"GtkWidget",2,3,"name","suggested-action"), (1,21,"GtkWidget",2,2,"name","toolbar"), (4,2,"GtkWidget",2,2,"name","osd"), - (4,5,"GtkWidget",2,2,"name","boxed-list") + (4,5,"GtkWidget",2,2,"name","boxed-list"), + (1,32,"GtkWidget",2,2,"name","pill"), + (1,32,"GtkWidget",2,3,"name","suggested-action") </object_data_arg> </cambalache-project> diff --git a/ui/src/windows/tracker.cpp b/ui/src/windows/tracker.cpp index 8add81f..5571aca 100644 --- a/ui/src/windows/tracker.cpp +++ b/ui/src/windows/tracker.cpp @@ -5,12 +5,19 @@ #include "turns/lang/messages.hpp" #include "turns/ui/windows/participant_editor.hpp" +#include <sigc++/bind.h> #include <sigc++/functors/mem_fun.h> #include <glibmm/binding.h> #include <glibmm/i18n.h> +#include <giomm/liststore.h> + +#include <gtkmm/error.h> +#include <gtkmm/filedialog.h> + #include <adwaita.h> +#include <nlohmann/json.hpp> #include <format> #include <utility> @@ -43,6 +50,7 @@ namespace turns::ui::windows , m_adw{ADW_APPLICATION_WINDOW(gobj())} , m_controls{builder->get_widget<Gtk::Revealer>("controls")} , m_empty(builder->get_widget<Gtk::Widget>("empty")) + , m_overlay{ADW_TOAST_OVERLAY(builder->get_widget<Gtk::Widget>("overlay")->gobj())} , m_stack{builder->get_widget<Gtk::Stack>("stack")} , m_start{builder->get_widget<Gtk::Button>("start")} , m_title(ADW_WINDOW_TITLE(builder->get_widget<Gtk::Widget>("title")->gobj())) @@ -92,6 +100,48 @@ namespace turns::ui::windows dialog->present(this); } + auto tracker::handle_save() -> void + { + auto filters = Gio::ListStore<Gtk::FileFilter>::create(); + auto filter = Gtk::FileFilter::create(); + filter->set_name(_("Turns Files")); + filter->add_pattern("*.trns"); + filters->append(filter); + + auto dialog = Gtk::FileDialog::create(); + dialog->set_initial_name(m_file_name.value_or(_(lang::new_turn_order_file_name))); + dialog->set_filters(filters); + dialog->save(*this, sigc::bind(sigc::mem_fun(*this, &tracker::handle_save_finish), dialog)); + } + + auto tracker::handle_save_finish(Glib::RefPtr<Gio::AsyncResult> result, Glib::RefPtr<Gtk::FileDialog> dialog) -> void + try + { + auto file = dialog->save_finish(result); + file->replace_contents(m_turn_order->serialize().dump(2), m_file_tag, m_file_tag); + auto name = file->get_basename(); + auto message = std::vformat(_(lang::successfully_saved_format), std::make_format_args(name)); + auto toast = adw_toast_new(message.c_str()); + adw_toast_overlay_add_toast(m_overlay, toast); + } + catch (Gtk::DialogError const & e) + { + if (e.code() == Gtk::DialogError::FAILED) + { + auto error = e.what(); + auto message = std::vformat(_(lang::saving_failed_format), std::make_format_args(error)); + auto toast = adw_toast_new(message.c_str()); + adw_toast_overlay_add_toast(m_overlay, toast); + } + } + catch (Gio::Error const & e) + { + auto error = e.what(); + auto message = std::vformat(_(lang::saving_failed_format), std::make_format_args(error)); + auto toast = adw_toast_new(message.c_str()); + adw_toast_overlay_add_toast(m_overlay, toast); + } + auto tracker::handle_stop() -> void { auto dialog = ADW_ALERT_DIALOG(adw_alert_dialog_new("Stop turn order", "Do you want to clear the turn order?")); @@ -174,6 +224,16 @@ namespace turns::ui::windows add_action_with_parameter("delete", Glib::VARIANT_TYPE_INT32, sigc::mem_fun(*this, &tracker::handle_delete_participant)); add_action_with_parameter("edit", Glib::VARIANT_TYPE_INT32, sigc::mem_fun(*this, &tracker::handle_edit_participant)); } + + // win.save + // depends-on: turn_order:is_empty == false + { + auto action = add_action("save", sigc::mem_fun(*this, &tracker::handle_save)); + + Glib::Binding::bind_property(m_turn_order->is_empty(), + action->property_enabled(), + Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN); + } } auto tracker::update_subtitle() -> void @@ -185,8 +245,8 @@ namespace turns::ui::windows else { auto round_number = m_turn_order->round_number() + 1; - m_subtitle = round_number == 0 ? "" : std::vformat(_("Round {}"), std::make_format_args(round_number)); + m_subtitle = round_number == 0 ? "" : std::vformat(_(lang::round_number), std::make_format_args(round_number)); } } -} // namespace turns::app::windows +} // namespace turns::ui::windows |
