50 auto* content =
dialog_->get_content_area();
51 content->set_margin(0);
52 content->set_spacing(0);
54 auto* mainBox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 8);
55 mainBox->set_margin(16);
59 searchEntry_.set_placeholder_text(
_(
"Filtra per nome, username, URL…"));
65 countLabel_.get_style_context()->add_class(
"dim-label");
74 mainBox->append(*Gtk::make_managed<Gtk::Separator>(Gtk::Orientation::HORIZONTAL));
77 auto* hdr = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 0);
78 hdr->set_margin_start(8);
79 hdr->set_margin_end(8);
80 hdr->set_margin_top(4);
81 hdr->set_margin_bottom(4);
83 auto makeHdr = [](
const std::string& t,
int chars) {
84 auto* l = Gtk::make_managed<Gtk::Label>();
85 l->set_markup(
"<b>" + Glib::Markup::escape_text(t) +
"</b>");
87 l->set_width_chars(chars);
88 l->set_max_width_chars(chars);
89 l->set_ellipsize(Pango::EllipsizeMode::END);
92 hdr->append(*makeHdr(
_(
"Nome / Sito"), 24));
93 hdr->append(*makeHdr(
_(
"Username"), 20));
94 hdr->append(*makeHdr(
_(
"URL"), 26));
95 hdr->append(*makeHdr(
_(
"Aggiornato"), 16));
96 mainBox->append(*hdr);
99 mainBox->append(*Gtk::make_managed<Gtk::Separator>(Gtk::Orientation::HORIZONTAL));
102 list_.set_selection_mode(Gtk::SelectionMode::SINGLE);
107 content->append(*mainBox);
108 dialog_->add_button(
_(
"Chiudi"), Gtk::ResponseType::CANCEL);
110 dialog_->signal_response().connect([
this](
int) {
dialog_->hide(); });
117 exportBtn_.get_style_context()->add_class(
"suggested-action");
118 auto provider = Gtk::CssProvider::create();
119 provider->load_from_data(
120 "button.suggested-action {"
121 " background: linear-gradient(to bottom, #3584e4, #1c71d8);"
123 " font-weight: bold;"
124 " padding: 6px 18px;"
125 " border-radius: 6px;"
126 " border: 1px solid #1558b0;"
129 provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
134 while (
auto* child =
list_.get_first_child())
135 list_.remove(*child);
137 std::string needle = filter;
138 std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower);
141 for (
const auto& entry :
entries_) {
142 std::string hay = entry.name +
" " + entry.username +
" " + entry.url;
143 std::transform(hay.begin(), hay.end(), hay.begin(), ::tolower);
144 if (!needle.empty() && hay.find(needle) == std::string::npos)
continue;
146 auto* row = Gtk::make_managed<Gtk::ListBoxRow>();
147 auto* box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 0);
148 box->set_margin_top(6);
149 box->set_margin_bottom(6);
150 box->set_margin_start(8);
151 box->set_margin_end(8);
153 auto makeCell = [](
const std::string& t,
int chars) {
154 auto* l = Gtk::make_managed<Gtk::Label>(t);
156 l->set_width_chars(chars);
157 l->set_max_width_chars(chars);
158 l->set_ellipsize(Pango::EllipsizeMode::END);
162 box->append(*makeCell(entry.name, 24));
163 box->append(*makeCell(entry.username, 20));
164 box->append(*makeCell(entry.url, 26));
165 box->append(*makeCell(entry.updated_at, 16));
166 auto* pwdBtn = Gtk::make_managed<Gtk::Button>(
_(
"👁"));
167 pwdBtn->set_tooltip_text(
_(
"Mostra password"));
168 pwdBtn->get_style_context()->add_class(
"flat");
169 pwdBtn->signal_clicked().connect([
this, entry]() {
172 box->append(*pwdBtn);
174 row->set_child(*box);
179 countLabel_.set_text(std::to_string(shown) +
" / " +
181 std::string(
_(
" credenziali")));
192 auto* dlg = new Gtk::Dialog(_(
"Dettaglio credenziale"), *dialog_, true);
193 dlg->set_default_size(420, 320);
195 auto* box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 10);
198 auto addRow = [&](const std::string& label, const std::string& value, bool selectable = true) {
199 auto* row = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 8);
200 auto* lbl = Gtk::make_managed<Gtk::Label>();
201 lbl->set_markup(
"<b>" + Glib::Markup::escape_text(label) +
"</b>");
202 lbl->set_xalign(0.0f);
203 lbl->set_size_request(100, -1);
205 auto* val = Gtk::make_managed<Gtk::Label>(value);
206 val->set_xalign(0.0f);
207 val->set_hexpand(true);
208 val->set_selectable(selectable);
209 val->set_ellipsize(Pango::EllipsizeMode::END);
216 addRow(
_(
"Nome:"), entry.
name);
218 addRow(
_(
"URL:"), entry.
url);
219 addRow(
_(
"Password:"), secret,
true);
220 if (!entry.
notes.empty())
221 addRow(
_(
"Note:"), entry.
notes);
225 dlg->get_content_area()->set_margin(0);
226 dlg->get_content_area()->append(*box);
227 dlg->add_button(
_(
"Chiudi"), Gtk::ResponseType::CANCEL);
229 dlg->signal_response().connect([dlg](
int) {
239 auto* fc =
new Gtk::FileChooserDialog(
240 _(
"Salva CSV"), Gtk::FileChooser::Action::SAVE);
241 fc->set_transient_for(*
dialog_);
243 fc->set_current_name(
"passwords_export.csv");
245 auto filter = Gtk::FileFilter::create();
246 filter->set_name(
_(
"File CSV (*.csv)"));
247 filter->add_pattern(
"*.csv");
248 fc->add_filter(filter);
250 fc->add_button(
_(
"Annulla"), Gtk::ResponseType::CANCEL);
251 fc->add_button(
_(
"Salva"), Gtk::ResponseType::OK);
253 fc->signal_response().connect([
this, fc](
int r) {
254 if (r == Gtk::ResponseType::OK) {
255 const auto file = fc->get_file();
257 const std::string path = file->get_path();
266 auto* msg =
new Gtk::MessageDialog(
268 false, Gtk::MessageType::ERROR,
269 Gtk::ButtonsType::CLOSE,
true);
270 msg->set_secondary_text(err);
271 msg->signal_response().connect([msg](
int) { msg->hide();
delete msg; });
276 std::ofstream out(path, std::ios::trunc);
277 if (!out.good())
return;
280 auto* msg =
new Gtk::MessageDialog(
282 false, Gtk::MessageType::INFO,
283 Gtk::ButtonsType::CLOSE,
true);
284 msg->set_secondary_text(
286 std::string(
_(
" credenziali salvate in:\n")) + path);
287 msg->signal_response().connect([msg](
int) { msg->hide();
delete msg; });