mirror of
https://gitlab.com/schmiddi-on-mobile/flare.git
synced 2026-10-24 20:57:46 -04:00
ui(): Port to new adwaita dialogs
This commit is contained in:
1 parent
10a05fa20f
commit
028ffc92de
20 files changed
+242
-177
No files matched your search
+1
-1
@@ -19,7 +19,7 @@ opt-level = 3
|
||||
[dependencies]
|
||||
gtk = { version = "0.8.0", package = "gtk4", features = ["v4_12"]}
|
||||
gdk = { version = "0.8.0", package = "gdk4" }
|
||||
adw = { version = "0.6.0", package = "libadwaita", features = ["v1_4"]}
|
||||
adw = { version = "0.6.0", package = "libadwaita", features = ["v1_5"]}
|
||||
ashpd = { version = "0.8.0", default-features = false, features = [ "gtk4", "tokio" ]}
|
||||
zbus = { version = "4.1.2", default-features = false, features = [ "tokio" ]}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
Adw.AboutWindow about {
|
||||
Adw.AboutDialog about {
|
||||
application-icon: "icon";
|
||||
application-name: "Flare";
|
||||
version: "@VERSION@";
|
||||
|
||||
@@ -1,56 +1,69 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $FlChannelInfoDialog: Adw.MessageDialog {
|
||||
heading: bind template.channel as <$FlChannel>.title;
|
||||
template $FlChannelInfoDialog: Adw.Dialog {
|
||||
can-focus: true;
|
||||
content-height: 600;
|
||||
content-width: 450;
|
||||
|
||||
extra-child: Box {
|
||||
spacing: 5;
|
||||
|
||||
orientation: vertical;
|
||||
|
||||
Adw.PreferencesGroup {
|
||||
title: _("Channel Information");
|
||||
header-suffix:
|
||||
Adw.Avatar avatar {
|
||||
icon-name: "user-bookmarks-symbolic";
|
||||
size: 30;
|
||||
};
|
||||
|
||||
Adw.ActionRow row_phone {
|
||||
styles ["property"]
|
||||
|
||||
title: _("Phone Number");
|
||||
icon-name: "call-start-symbolic";
|
||||
}
|
||||
|
||||
Adw.ActionRow row_disappearing {
|
||||
styles ["property"]
|
||||
|
||||
title: _("Disappearing Messages");
|
||||
icon-name: "appointment-missed-symbolic";
|
||||
}
|
||||
|
||||
Adw.ActionRow row_description {
|
||||
styles ["property"]
|
||||
|
||||
title: _("Description");
|
||||
subtitle-lines: 2;
|
||||
}
|
||||
Adw.ToolbarView {
|
||||
[top]
|
||||
Adw.HeaderBar {
|
||||
title-widget: Adw.WindowTitle {
|
||||
title: bind template.channel as <$FlChannel>.title;
|
||||
};
|
||||
}
|
||||
|
||||
// Session Reset
|
||||
Button button_reset_session {
|
||||
accessibility {
|
||||
label: C_("accessibility", "Reset Session");
|
||||
Adw.Clamp {
|
||||
orientation: horizontal;
|
||||
tightening-threshold: 300;
|
||||
maximum-size: 600;
|
||||
|
||||
Box {
|
||||
spacing: 5;
|
||||
|
||||
orientation: vertical;
|
||||
|
||||
Adw.PreferencesGroup {
|
||||
title: _("Channel Information");
|
||||
header-suffix:
|
||||
Adw.Avatar avatar {
|
||||
icon-name: "user-bookmarks-symbolic";
|
||||
size: 30;
|
||||
};
|
||||
|
||||
Adw.ActionRow row_phone {
|
||||
styles ["property"]
|
||||
|
||||
title: _("Phone Number");
|
||||
icon-name: "call-start-symbolic";
|
||||
}
|
||||
|
||||
Adw.ActionRow row_disappearing {
|
||||
styles ["property"]
|
||||
|
||||
title: _("Disappearing Messages");
|
||||
icon-name: "appointment-missed-symbolic";
|
||||
}
|
||||
|
||||
Adw.ActionRow row_description {
|
||||
styles ["property"]
|
||||
|
||||
title: _("Description");
|
||||
subtitle-lines: 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Session Reset
|
||||
Button button_reset_session {
|
||||
accessibility {
|
||||
label: C_("accessibility", "Reset Session");
|
||||
}
|
||||
|
||||
label: _("Reset Session");
|
||||
clicked => $reset_session() swapped;
|
||||
}
|
||||
}
|
||||
|
||||
label: _("Reset Session");
|
||||
clicked => $reset_session() swapped;
|
||||
}
|
||||
};
|
||||
|
||||
responses [
|
||||
close: _("Close"),
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
Adw.MessageDialog dialog {
|
||||
Adw.AlertDialog dialog {
|
||||
heading: _("Clear messages");
|
||||
body: _("This will clear all locally stored messages. This will also close the application.");
|
||||
default-response: "cancel";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
Adw.MessageDialog dialog {
|
||||
Adw.AlertDialog dialog {
|
||||
heading: _("Unlink");
|
||||
body: _("This will unlink this device and remove all locally saved data. This will also close the application such that it can be relinked when opening it again.");
|
||||
default-response: "cancel";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $FlErrorDialog: Adw.MessageDialog {
|
||||
template $FlErrorDialog: Adw.AlertDialog {
|
||||
heading: _("Error");
|
||||
response => $handle_response();
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $FlLinkedDevicesWindow: Adw.Window {
|
||||
template $FlLinkedDevicesWindow: Adw.Dialog {
|
||||
can-focus: true;
|
||||
default-height: 600;
|
||||
default-width: 450;
|
||||
destroy-with-parent: true;
|
||||
modal: true;
|
||||
content-height: 600;
|
||||
content-width: 450;
|
||||
|
||||
content: Adw.ToolbarView {
|
||||
Adw.ToolbarView {
|
||||
[top]
|
||||
Adw.HeaderBar {
|
||||
title-widget: Adw.WindowTitle {
|
||||
@@ -26,10 +24,10 @@ template $FlLinkedDevicesWindow: Adw.Window {
|
||||
|
||||
Gtk.ListView list_devices {}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Adw.MessageDialog add_device_dialog {
|
||||
Adw.AlertDialog add_device_dialog {
|
||||
heading: _("Add Linked Device");
|
||||
body: _("Please insert the URL of the device to link.");
|
||||
default-response: "cancel";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $FlPreferencesWindow: Adw.PreferencesWindow {
|
||||
template $FlPreferencesWindow: Adw.PreferencesDialog {
|
||||
Adw.PreferencesPage {
|
||||
title: _("General");
|
||||
icon-name: "preferences-system-symbolic";
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $FlSetupWindow: Adw.Window {
|
||||
template $FlSetupWindow: Adw.Dialog {
|
||||
can-focus: true;
|
||||
default-height: 600;
|
||||
default-width: 450;
|
||||
destroy-with-parent: true;
|
||||
modal: true;
|
||||
deletable: false;
|
||||
content-height: 600;
|
||||
content-width: 450;
|
||||
|
||||
content: Adw.ToastOverlay toast_overlay {
|
||||
Adw.ToastOverlay toast_overlay {
|
||||
child: Box {
|
||||
orientation: vertical;
|
||||
|
||||
@@ -532,5 +529,5 @@ template $FlSetupWindow: Adw.Window {
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
Adw.MessageDialog dialog {
|
||||
Adw.AlertDialog dialog {
|
||||
heading: _("Submit Captcha");
|
||||
// Translators: Do not translate tags around "on this website".
|
||||
body: _("Submit a Captcha challenge. The token can be obtained from the error message that was displayed from Flare. The captcha must be filled out <a href=\"https://signalcaptchas.org/challenge/generate.html\">on this website</a> and the link to open Signal must be pasted to the corresponding entry. Note that the captcha is only valid for about one minute.");
|
||||
|
||||
@@ -11,6 +11,29 @@
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
|
||||
libadwaita_1_5 = pkgs.libadwaita.overrideAttrs (finalAttrs: prevAttrs: {
|
||||
version = "1.5.beta";
|
||||
src = with pkgs; fetchFromGitLab {
|
||||
domain = "gitlab.gnome.org";
|
||||
owner = "GNOME";
|
||||
repo = "libadwaita";
|
||||
rev = "66edcd31c1acfb5a569db02870d1f7e471946fcf";
|
||||
hash = "sha256-ipyifdRwZCO8H7qQOcEHOXW9PT9w+Ix+k374qHRfSjg=";
|
||||
};
|
||||
});
|
||||
|
||||
blueprint-compiler-git = pkgs.blueprint-compiler.overrideAttrs (finalAttrs: prevAttrs: {
|
||||
version = "0.10.1.git";
|
||||
src = with pkgs; fetchFromGitLab {
|
||||
domain = "gitlab.gnome.org";
|
||||
owner = "jwestman";
|
||||
repo = "blueprint-compiler";
|
||||
rev = "d47955c5a20b2f7cf85ff25a00b02160883aa0b1";
|
||||
hash = "sha256-yNFgJpCGu2CrT6J004N4G+Nlt+3/DbEkSGOWkvSn4J8=";
|
||||
};
|
||||
});
|
||||
|
||||
name = "flare";
|
||||
in
|
||||
rec {
|
||||
@@ -38,8 +61,8 @@
|
||||
./flake.lock
|
||||
]);
|
||||
};
|
||||
buildInputs = with pkgs; [ pkgs.libadwaita pkgs.protobuf pkgs.libsecret pkgs.gst_all_1.gstreamer pkgs.gst_all_1.gst-plugins-base pkgs.gst_all_1.gst-plugins-good pkgs.gst_all_1.gst-plugins-bad pkgs.gtksourceview5 pkgs.gtk4 ];
|
||||
nativeBuildInputs = with pkgs; [ pkgs.appstream-glib pkgs.blueprint-compiler pkgs.desktop-file-utils pkgs.meson pkgs.ninja pkgs.pkg-config pkgs.wrapGAppsHook4 pkgs.rustPlatform.cargoSetupHook cargo rustc pkgs.glib ];
|
||||
buildInputs = with pkgs; [ libadwaita_1_5 pkgs.protobuf pkgs.libsecret pkgs.gst_all_1.gstreamer pkgs.gst_all_1.gst-plugins-base pkgs.gst_all_1.gst-plugins-good pkgs.gst_all_1.gst-plugins-bad pkgs.gtksourceview5 pkgs.gtk4 ];
|
||||
nativeBuildInputs = with pkgs; [ pkgs.appstream-glib blueprint-compiler-git pkgs.desktop-file-utils pkgs.meson pkgs.ninja pkgs.pkg-config pkgs.wrapGAppsHook4 pkgs.rustPlatform.cargoSetupHook cargo rustc pkgs.glib ];
|
||||
|
||||
PROTOC = "${pkgs.protobuf}/bin/protoc";
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ pub fn backend_to_gui(attachment: &crate::backend::Attachment) -> Attachment {
|
||||
pub mod imp {
|
||||
use std::{cell::RefCell, os::fd::AsFd};
|
||||
|
||||
use adw::prelude::*;
|
||||
use ashpd::{desktop::open_uri::OpenFileRequest, WindowIdentifier};
|
||||
use gdk::{
|
||||
gio::File,
|
||||
@@ -43,7 +44,7 @@ pub mod imp {
|
||||
ParamSpec, ParamSpecObject, Value,
|
||||
};
|
||||
use gtk::{gio, glib, FileDialog};
|
||||
use gtk::{prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
use gtk::{subclass::prelude::*, CompositeTemplate};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{
|
||||
@@ -139,7 +140,7 @@ pub mod imp {
|
||||
if let Err(e) = attachment.save_to_file(&file).await {
|
||||
let root = obj.imp().window();
|
||||
let dialog = ErrorDialog::new(e.into(), &root);
|
||||
dialog.present();
|
||||
dialog.present(&root);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use gdk::{
|
||||
glib::subclass::types::ObjectSubclassIsExt,
|
||||
prelude::{IsA, ObjectExt},
|
||||
};
|
||||
use gdk::{glib::subclass::types::ObjectSubclassIsExt, prelude::ObjectExt};
|
||||
use glib::Object;
|
||||
use gtk::glib;
|
||||
|
||||
@@ -9,18 +6,17 @@ use crate::backend::{Channel, Manager};
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ChannelInfoDialog(ObjectSubclass<imp::ChannelInfoDialog>)
|
||||
@extends adw::MessageDialog, gtk::Window, gtk::Widget,
|
||||
@extends adw::Dialog, gtk::Widget,
|
||||
@implements gtk::gio::ActionGroup, gtk::gio::ActionMap, gtk::Accessible, gtk::Buildable,
|
||||
gtk::ConstraintTarget;
|
||||
}
|
||||
|
||||
impl ChannelInfoDialog {
|
||||
pub fn new(channel: &Channel, manager: &Manager, parent: &impl IsA<gtk::Window>) -> Self {
|
||||
pub fn new(channel: &Channel, manager: &Manager) -> Self {
|
||||
log::trace!("Initializing `ChannelInfoDialog`");
|
||||
let s = Object::builder::<Self>()
|
||||
.property("channel", channel)
|
||||
.property("manager", manager)
|
||||
.property("transient-for", parent)
|
||||
.build();
|
||||
s.imp().setup();
|
||||
s
|
||||
@@ -33,7 +29,7 @@ impl ChannelInfoDialog {
|
||||
|
||||
pub mod imp {
|
||||
use adw::prelude::ActionRowExt;
|
||||
use adw::subclass::prelude::MessageDialogImpl;
|
||||
use adw::subclass::dialog::AdwDialogImpl;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use glib::{subclass::InitializingObject, ParamSpec, ParamSpecObject, Value};
|
||||
@@ -172,7 +168,7 @@ pub mod imp {
|
||||
impl ObjectSubclass for ChannelInfoDialog {
|
||||
const NAME: &'static str = "FlChannelInfoDialog";
|
||||
type Type = super::ChannelInfoDialog;
|
||||
type ParentType = adw::MessageDialog;
|
||||
type ParentType = adw::Dialog;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
Self::bind_template(klass);
|
||||
@@ -229,8 +225,6 @@ pub mod imp {
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowImpl for ChannelInfoDialog {}
|
||||
impl MessageDialogImpl for ChannelInfoDialog {}
|
||||
impl AdwDialogImpl for ChannelInfoDialog {}
|
||||
impl WidgetImpl for ChannelInfoDialog {}
|
||||
impl BoxImpl for ChannelInfoDialog {}
|
||||
}
|
||||
@@ -138,11 +138,12 @@ impl ChannelMessages {
|
||||
pub mod imp {
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use adw::prelude::*;
|
||||
use glib::{
|
||||
clone, subclass::InitializingObject, ParamSpec, ParamSpecBoolean, ParamSpecObject, Value,
|
||||
};
|
||||
use gtk::{gio, glib, FileDialog, PositionType, SignalListItemFactory};
|
||||
use gtk::{prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
use gtk::{subclass::prelude::*, CompositeTemplate};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::backend::timeline::Timeline;
|
||||
@@ -350,7 +351,7 @@ pub mod imp {
|
||||
.dynamic_cast::<crate::gui::Window>()
|
||||
.expect("Root of `ChannelMessages` to be a `Window`.");
|
||||
let dialog = ErrorDialog::new(e, &root);
|
||||
dialog.present();
|
||||
dialog.present(&root);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -362,7 +363,7 @@ pub mod imp {
|
||||
.dynamic_cast::<crate::gui::Window>()
|
||||
.expect("Root of `ChannelMessages` to be a `Window`.");
|
||||
let dialog = ErrorDialog::new(e, &root);
|
||||
dialog.present();
|
||||
dialog.present(&root);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
+33
-13
@@ -1,16 +1,18 @@
|
||||
use adw::prelude::MessageDialogExt;
|
||||
use adw::prelude::AlertDialogExt;
|
||||
use gdk::glib::object::ObjectExt;
|
||||
use glib::{prelude::IsA, Object};
|
||||
use gtk::glib;
|
||||
|
||||
use crate::ApplicationError;
|
||||
|
||||
use super::Window;
|
||||
|
||||
const REPORT: &str = "report";
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ErrorDialog(ObjectSubclass<imp::ErrorDialog>)
|
||||
@extends adw::MessageDialog, gtk::Window, gtk::Widget,
|
||||
@implements gtk::gio::ActionGroup, gtk::gio::ActionMap, gtk::Accessible, gtk::Buildable,
|
||||
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
|
||||
@extends adw::AlertDialog, adw::Dialog, gtk::Widget,
|
||||
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
|
||||
}
|
||||
|
||||
impl ErrorDialog {
|
||||
@@ -22,29 +24,39 @@ impl ErrorDialog {
|
||||
.property("body", &error.to_string())
|
||||
.property("secondary-error", &error.more_information())
|
||||
.property("should-report", error.should_report())
|
||||
.property("transient-for", parent)
|
||||
.property("window", parent)
|
||||
.build();
|
||||
s.set_response_enabled(REPORT, error.should_report());
|
||||
s
|
||||
}
|
||||
|
||||
fn window(&self) -> Window {
|
||||
self.property("window")
|
||||
}
|
||||
}
|
||||
|
||||
pub mod imp {
|
||||
pub(crate) use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use adw::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use gdk::gio;
|
||||
use gdk::glib::ParamSpecObject;
|
||||
use glib::{subclass::InitializingObject, ParamSpec, ParamSpecBoolean, ParamSpecString, Value};
|
||||
use gtk::CompositeTemplate;
|
||||
use gtk::{glib, UriLauncher};
|
||||
use gtk::{prelude::*, CompositeTemplate};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::gui::Window;
|
||||
|
||||
#[derive(CompositeTemplate, Default)]
|
||||
#[template(resource = "/ui/error_dialog.ui")]
|
||||
pub struct ErrorDialog {
|
||||
secondary_error: RefCell<Option<String>>,
|
||||
should_report: Cell<bool>,
|
||||
|
||||
window: RefCell<Option<Window>>,
|
||||
}
|
||||
|
||||
#[gtk::template_callbacks]
|
||||
@@ -56,7 +68,7 @@ pub mod imp {
|
||||
let launcher =
|
||||
UriLauncher::new("https://gitlab.com/schmiddi-on-mobile/flare/-/issues");
|
||||
launcher.launch(
|
||||
self.obj().transient_for().as_ref(),
|
||||
Some(&self.obj().window()),
|
||||
None::<&gio::Cancellable>,
|
||||
|_| {},
|
||||
);
|
||||
@@ -68,7 +80,7 @@ pub mod imp {
|
||||
impl ObjectSubclass for ErrorDialog {
|
||||
const NAME: &'static str = "FlErrorDialog";
|
||||
type Type = super::ErrorDialog;
|
||||
type ParentType = adw::MessageDialog;
|
||||
type ParentType = adw::AlertDialog;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
Self::bind_template(klass);
|
||||
@@ -95,6 +107,9 @@ pub mod imp {
|
||||
ParamSpecBoolean::builder("should-report")
|
||||
.construct_only()
|
||||
.build(),
|
||||
ParamSpecObject::builder::<Window>("window")
|
||||
.construct_only()
|
||||
.build(),
|
||||
]
|
||||
});
|
||||
PROPERTIES.as_ref()
|
||||
@@ -104,6 +119,7 @@ pub mod imp {
|
||||
match pspec.name() {
|
||||
"secondary-error" => self.secondary_error.borrow().as_ref().to_value(),
|
||||
"should-report" => self.should_report.get().to_value(),
|
||||
"window" => self.window.borrow().as_ref().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
@@ -122,15 +138,19 @@ pub mod imp {
|
||||
);
|
||||
self.should_report.replace(r);
|
||||
}
|
||||
"window" => {
|
||||
let win = value
|
||||
.get::<Option<Window>>()
|
||||
.expect("Property `window` of `ErrorDialog` has to be of type `Window`");
|
||||
|
||||
self.window.replace(win);
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageDialogImpl for ErrorDialog {}
|
||||
impl AdwAlertDialogImpl for ErrorDialog {}
|
||||
impl WidgetImpl for ErrorDialog {}
|
||||
impl WindowImpl for ErrorDialog {}
|
||||
impl ApplicationWindowImpl for ErrorDialog {}
|
||||
impl AdwWindowImpl for ErrorDialog {}
|
||||
impl AdwApplicationWindowImpl for ErrorDialog {}
|
||||
impl AdwDialogImpl for ErrorDialog {}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
use crate::backend::Manager;
|
||||
use adw::prelude::GtkWindowExt;
|
||||
use gdk::prelude::CastNone;
|
||||
use glib::{prelude::ObjectExt, Object};
|
||||
use gtk::glib;
|
||||
|
||||
@@ -8,9 +6,8 @@ use super::Window;
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct LinkedDevicesWindow(ObjectSubclass<imp::LinkedDevicesWindow>)
|
||||
@extends adw::Window, gtk::Window, gtk::Widget,
|
||||
@implements gtk::gio::ActionGroup, gtk::gio::ActionMap, gtk::Accessible, gtk::Buildable,
|
||||
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
|
||||
@extends adw::Dialog, gtk::Widget,
|
||||
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
|
||||
}
|
||||
|
||||
impl LinkedDevicesWindow {
|
||||
@@ -18,7 +15,7 @@ impl LinkedDevicesWindow {
|
||||
log::trace!("Initializing link window");
|
||||
Object::builder::<Self>()
|
||||
.property("manager", &manager)
|
||||
.property("transient-for", parent)
|
||||
.property("window", parent)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -27,16 +24,13 @@ impl LinkedDevicesWindow {
|
||||
}
|
||||
|
||||
fn window(&self) -> Window {
|
||||
self.transient_for()
|
||||
.and_dynamic_cast()
|
||||
.expect("LinkedDevicesWindow to have a Window parent")
|
||||
self.property("window")
|
||||
}
|
||||
}
|
||||
|
||||
pub mod imp {
|
||||
use adw::prelude::EditableExt;
|
||||
use adw::prelude::GtkWindowExt;
|
||||
use adw::prelude::{MessageDialogExt, WidgetExt};
|
||||
use adw::prelude::WidgetExt;
|
||||
use adw::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use gdk::glib::clone;
|
||||
use gdk::prelude::ParamSpecBuilderExt;
|
||||
@@ -52,16 +46,19 @@ pub mod imp {
|
||||
use crate::gspawn;
|
||||
use crate::gui::error_dialog::ErrorDialog;
|
||||
use crate::gui::utility::Utility;
|
||||
use crate::gui::Window;
|
||||
|
||||
#[derive(CompositeTemplate, Default)]
|
||||
#[template(resource = "/ui/linked_devices_window.ui")]
|
||||
pub struct LinkedDevicesWindow {
|
||||
// TODO: Port to AlertDialog
|
||||
#[template_child]
|
||||
add_device_dialog: TemplateChild<adw::MessageDialog>,
|
||||
add_device_dialog: TemplateChild<adw::AlertDialog>,
|
||||
#[template_child]
|
||||
entry_device_url: TemplateChild<adw::EntryRow>,
|
||||
|
||||
manager: RefCell<Option<Manager>>,
|
||||
window: RefCell<Option<Window>>,
|
||||
}
|
||||
|
||||
#[gtk::template_callbacks]
|
||||
@@ -70,9 +67,7 @@ pub mod imp {
|
||||
fn handle_add_linked_device(&self) {
|
||||
log::trace!("User asked to add device link. Presenting dialog.");
|
||||
self.entry_device_url.set_text("");
|
||||
self.add_device_dialog
|
||||
.set_transient_for(Some(&self.obj().window()));
|
||||
self.add_device_dialog.present();
|
||||
self.add_device_dialog.present(&self.obj().window());
|
||||
}
|
||||
|
||||
#[template_callback]
|
||||
@@ -88,8 +83,9 @@ pub mod imp {
|
||||
let manager = self.obj().manager();
|
||||
gspawn!(clone!(@weak obj => async move {
|
||||
if let Err(e) = manager.link_secondary(url).await {
|
||||
let dialog = ErrorDialog::new(e.into(), &obj.window());
|
||||
dialog.present();
|
||||
let root = obj.window();
|
||||
let dialog = ErrorDialog::new(e.into(), &root);
|
||||
dialog.present(&root);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -109,7 +105,7 @@ pub mod imp {
|
||||
impl ObjectSubclass for LinkedDevicesWindow {
|
||||
const NAME: &'static str = "FlLinkedDevicesWindow";
|
||||
type Type = super::LinkedDevicesWindow;
|
||||
type ParentType = adw::Window;
|
||||
type ParentType = adw::Dialog;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
Self::bind_template(klass);
|
||||
@@ -130,9 +126,14 @@ pub mod imp {
|
||||
|
||||
fn properties() -> &'static [ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<ParamSpec>> = Lazy::new(|| {
|
||||
vec![ParamSpecObject::builder::<Manager>("manager")
|
||||
.construct_only()
|
||||
.build()]
|
||||
vec![
|
||||
ParamSpecObject::builder::<Manager>("manager")
|
||||
.construct_only()
|
||||
.build(),
|
||||
ParamSpecObject::builder::<Window>("window")
|
||||
.construct_only()
|
||||
.build(),
|
||||
]
|
||||
});
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
@@ -140,6 +141,7 @@ pub mod imp {
|
||||
fn property(&self, _id: usize, pspec: &ParamSpec) -> Value {
|
||||
match pspec.name() {
|
||||
"manager" => self.manager.borrow().as_ref().to_value(),
|
||||
"window" => self.window.borrow().as_ref().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
@@ -153,12 +155,18 @@ pub mod imp {
|
||||
|
||||
self.manager.replace(man);
|
||||
}
|
||||
"window" => {
|
||||
let win = value.get::<Option<Window>>().expect(
|
||||
"Property `window` of `LinkedDevicesWindow` has to be of type `Window`",
|
||||
);
|
||||
|
||||
self.window.replace(win);
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for LinkedDevicesWindow {}
|
||||
impl WindowImpl for LinkedDevicesWindow {}
|
||||
impl AdwWindowImpl for LinkedDevicesWindow {}
|
||||
impl AdwDialogImpl for LinkedDevicesWindow {}
|
||||
}
|
||||
@@ -221,13 +221,14 @@ pub mod imp {
|
||||
use regex::Regex;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use adw::prelude::*;
|
||||
use glib::{
|
||||
clone,
|
||||
subclass::{InitializingObject, Signal},
|
||||
ParamSpec, ParamSpecBoolean, ParamSpecObject, Value,
|
||||
};
|
||||
use gtk::{glib, EmojiChooser};
|
||||
use gtk::{prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
use gtk::{subclass::prelude::*, CompositeTemplate};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{
|
||||
@@ -392,7 +393,7 @@ pub mod imp {
|
||||
.dynamic_cast::<crate::gui::Window>()
|
||||
.expect("Root of `ChannelMessages` to be a `Window`.");
|
||||
let dialog = ErrorDialog::new(e, &root);
|
||||
dialog.present();
|
||||
dialog.present(&root);
|
||||
}
|
||||
obj.notify("has-reaction");
|
||||
}));
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{gspawn, tspawn};
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct PreferencesWindow(ObjectSubclass<imp::PreferencesWindow>)
|
||||
@extends adw::PreferencesWindow, adw::Window, gtk::Window, gtk::Widget,
|
||||
@extends adw::PreferencesDialog, adw::Dialog, gtk::Widget,
|
||||
@implements gtk::gio::ActionGroup, gtk::gio::ActionMap, gtk::Accessible, gtk::Buildable,
|
||||
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
|
||||
}
|
||||
@@ -177,7 +177,7 @@ pub mod imp {
|
||||
impl ObjectSubclass for PreferencesWindow {
|
||||
const NAME: &'static str = "FlPreferencesWindow";
|
||||
type Type = super::PreferencesWindow;
|
||||
type ParentType = adw::PreferencesWindow;
|
||||
type ParentType = adw::PreferencesDialog;
|
||||
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
@@ -211,7 +211,6 @@ pub mod imp {
|
||||
}
|
||||
}
|
||||
impl WidgetImpl for PreferencesWindow {}
|
||||
impl WindowImpl for PreferencesWindow {}
|
||||
impl PreferencesWindowImpl for PreferencesWindow {}
|
||||
impl AdwWindowImpl for PreferencesWindow {}
|
||||
impl PreferencesDialogImpl for PreferencesWindow {}
|
||||
impl AdwDialogImpl for PreferencesWindow {}
|
||||
}
|
||||
+30
-17
@@ -1,6 +1,5 @@
|
||||
use crate::backend::{Manager, Server, SetupResult};
|
||||
use adw::prelude::GtkWindowExt;
|
||||
use gdk::{glib::subclass::types::ObjectSubclassIsExt, prelude::CastNone};
|
||||
use gdk::glib::subclass::types::ObjectSubclassIsExt;
|
||||
use glib::{prelude::ObjectExt, Object};
|
||||
use gtk::glib;
|
||||
use libsignal_service::configuration::SignalServers;
|
||||
@@ -9,7 +8,7 @@ use super::Window;
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct SetupWindow(ObjectSubclass<imp::SetupWindow>)
|
||||
@extends adw::Window, gtk::Window, gtk::Widget,
|
||||
@extends adw::Dialog, gtk::Widget,
|
||||
@implements gtk::gio::ActionGroup, gtk::gio::ActionMap, gtk::Accessible, gtk::Buildable,
|
||||
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
|
||||
}
|
||||
@@ -19,7 +18,7 @@ impl SetupWindow {
|
||||
log::trace!("Initializing setup window");
|
||||
Object::builder::<Self>()
|
||||
.property("manager", &manager)
|
||||
.property("transient-for", parent)
|
||||
.property("window", parent)
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -32,9 +31,7 @@ impl SetupWindow {
|
||||
}
|
||||
|
||||
pub fn window(&self) -> Window {
|
||||
self.transient_for()
|
||||
.and_dynamic_cast()
|
||||
.expect("SetupWindow to have a Window parent")
|
||||
self.property("window")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +49,14 @@ fn servers() -> Vec<Server> {
|
||||
}
|
||||
|
||||
pub mod imp {
|
||||
use adw::prelude::AdwDialogExt;
|
||||
use adw::prelude::ComboRowExt;
|
||||
use adw::subclass::dialog::AdwDialogImplExt;
|
||||
use adw::subclass::prelude::*;
|
||||
use adw::Toast;
|
||||
use futures::channel::oneshot::Sender;
|
||||
use gdk::gdk_pixbuf::Pixbuf;
|
||||
use gdk::gio::ListStore;
|
||||
use gdk::glib::Propagation;
|
||||
use gettextrs::gettext;
|
||||
use gio::MemoryInputStream;
|
||||
use glib::{subclass::InitializingObject, Bytes, ParamSpec, ParamSpecObject, Value};
|
||||
@@ -72,6 +70,7 @@ pub mod imp {
|
||||
|
||||
use crate::backend::{Manager, Server, SetupDecision, SetupResult};
|
||||
use crate::gui::utility::Utility;
|
||||
use crate::gui::Window;
|
||||
|
||||
#[derive(CompositeTemplate, Default)]
|
||||
#[template(resource = "/ui/setup_window.ui")]
|
||||
@@ -117,6 +116,8 @@ pub mod imp {
|
||||
|
||||
manager: RefCell<Option<Manager>>,
|
||||
|
||||
window: RefCell<Option<Window>>,
|
||||
|
||||
decision_callback: RefCell<Option<Sender<SetupDecision>>>,
|
||||
confirm_callback: RefCell<Option<Sender<String>>>,
|
||||
|
||||
@@ -237,7 +238,7 @@ pub mod imp {
|
||||
let obj = self.obj();
|
||||
match result {
|
||||
SetupResult::Pending(callback) => {
|
||||
obj.present();
|
||||
obj.present(&obj.window());
|
||||
self.decision_callback.replace(callback.take());
|
||||
|
||||
let win = obj.window();
|
||||
@@ -295,7 +296,7 @@ pub mod imp {
|
||||
impl ObjectSubclass for SetupWindow {
|
||||
const NAME: &'static str = "FlSetupWindow";
|
||||
type Type = super::SetupWindow;
|
||||
type ParentType = adw::Window;
|
||||
type ParentType = adw::Dialog;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
Self::bind_template(klass);
|
||||
@@ -317,9 +318,14 @@ pub mod imp {
|
||||
|
||||
fn properties() -> &'static [ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<ParamSpec>> = Lazy::new(|| {
|
||||
vec![ParamSpecObject::builder::<Manager>("manager")
|
||||
.construct_only()
|
||||
.build()]
|
||||
vec![
|
||||
ParamSpecObject::builder::<Manager>("manager")
|
||||
.construct_only()
|
||||
.build(),
|
||||
ParamSpecObject::builder::<Window>("window")
|
||||
.construct_only()
|
||||
.build(),
|
||||
]
|
||||
});
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
@@ -327,6 +333,7 @@ pub mod imp {
|
||||
fn property(&self, _id: usize, pspec: &ParamSpec) -> Value {
|
||||
match pspec.name() {
|
||||
"manager" => self.manager.borrow().as_ref().to_value(),
|
||||
"window" => self.window.borrow().as_ref().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
@@ -340,21 +347,27 @@ pub mod imp {
|
||||
|
||||
self.manager.replace(man);
|
||||
}
|
||||
"window" => {
|
||||
let win = value
|
||||
.get::<Option<Window>>()
|
||||
.expect("Property `window` of `SetupWindow` has to be of type `Window`");
|
||||
|
||||
self.window.replace(win);
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for SetupWindow {}
|
||||
impl WindowImpl for SetupWindow {
|
||||
fn close_request(&self) -> Propagation {
|
||||
impl AdwDialogImpl for SetupWindow {
|
||||
fn closed(&self) {
|
||||
// If it is closed while not being finished, close the parent window
|
||||
if self.content.visible_page() != Some(self.page_finished.get()) {
|
||||
self.obj().window().destroy();
|
||||
}
|
||||
|
||||
self.parent_close_request()
|
||||
self.parent_closed()
|
||||
}
|
||||
}
|
||||
impl AdwWindowImpl for SetupWindow {}
|
||||
}
|
||||
+24
-27
@@ -86,9 +86,8 @@ impl Window {
|
||||
pub mod imp {
|
||||
use std::{cell::RefCell, env, path::PathBuf};
|
||||
|
||||
use adw::prelude::MessageDialogExtManual;
|
||||
use adw::{prelude::*, subclass::prelude::*, AboutWindow, MessageDialog};
|
||||
use adw::{EntryRow, ResponseAppearance};
|
||||
use adw::{prelude::*, subclass::prelude::*, AboutDialog};
|
||||
use adw::{AlertDialog, EntryRow, ResponseAppearance};
|
||||
use gdk::gio::Cancellable;
|
||||
use gdk::glib::{BindingFlags, BoxedAnyObject, Propagation};
|
||||
use gio::{Settings, SimpleAction, SimpleActionGroup};
|
||||
@@ -148,19 +147,18 @@ pub mod imp {
|
||||
log::trace!("Setting up preferences-window action");
|
||||
let obj = self.obj();
|
||||
let action_settings = SimpleAction::new("settings", None);
|
||||
action_settings.connect_activate(|_, _| {
|
||||
action_settings.connect_activate(clone!(@weak obj => move |_, _| {
|
||||
let settings = PreferencesWindow::new();
|
||||
settings.present();
|
||||
});
|
||||
settings.present(&obj);
|
||||
}));
|
||||
|
||||
let action_clear_messages = SimpleAction::new("clear-messages", None);
|
||||
action_clear_messages.connect_activate(clone!(@weak obj => move |_, _| {
|
||||
log::trace!("User requested to clear messages");
|
||||
let builder = Builder::from_resource("/ui/dialog_clear_messages.ui");
|
||||
let dialog: MessageDialog = builder
|
||||
let dialog: AlertDialog = builder
|
||||
.object("dialog")
|
||||
.expect("dialog_clear_messages.ui to have at least one object dialog");
|
||||
dialog.set_transient_for(Some(&obj));
|
||||
dialog.connect_response(None, clone!(@weak obj => move |_dialog, response| {
|
||||
if response == "clear" {
|
||||
log::info!("Clear messages device");
|
||||
@@ -173,17 +171,16 @@ pub mod imp {
|
||||
obj.kill();
|
||||
}
|
||||
}));
|
||||
dialog.present();
|
||||
dialog.present(&obj);
|
||||
}));
|
||||
log::trace!("Setting up unlink action");
|
||||
let action_unlink = SimpleAction::new("unlink", None);
|
||||
action_unlink.connect_activate(clone!(@weak obj => move |_, _| {
|
||||
log::trace!("User requested to unlink the device");
|
||||
let builder = Builder::from_resource("/ui/dialog_unlink.ui");
|
||||
let dialog: MessageDialog = builder
|
||||
let dialog: AlertDialog = builder
|
||||
.object("dialog")
|
||||
.expect("dialog_unlink.ui to have at least one object dialog");
|
||||
dialog.set_transient_for(Some(&obj));
|
||||
dialog.connect_response(None, clone!(@weak obj => move |_dialog, response| {
|
||||
if response == "unlink-keep" {
|
||||
log::info!("Unlinking device");
|
||||
@@ -214,7 +211,7 @@ pub mod imp {
|
||||
obj.kill();
|
||||
}
|
||||
}));
|
||||
dialog.present();
|
||||
dialog.present(&obj);
|
||||
}));
|
||||
|
||||
log::trace!("Setting up submit-captcha action");
|
||||
@@ -222,7 +219,7 @@ pub mod imp {
|
||||
action_submit_captcha.connect_activate(clone!(@weak obj => move |_, _| {
|
||||
log::trace!("User requested to submit a captcha the device");
|
||||
let builder = Builder::from_resource("/ui/submit_captcha_dialog.ui");
|
||||
let dialog: MessageDialog = builder
|
||||
let dialog: AlertDialog = builder
|
||||
.object("dialog")
|
||||
.expect("submit_captcha_dialog.ui to have at least one object dialog");
|
||||
let entry_token: EntryRow = builder
|
||||
@@ -231,7 +228,6 @@ pub mod imp {
|
||||
let entry_captcha: EntryRow = builder
|
||||
.object("entry_captcha")
|
||||
.expect("submit_captcha_dialog.ui to have at least one object entry_captcha");
|
||||
dialog.set_transient_for(Some(&obj));
|
||||
dialog.connect_response(None, clone!(@weak obj, @weak entry_token, @weak entry_captcha => move |_dialog, response| {
|
||||
if response == "submit" {
|
||||
log::info!("Unlinking device");
|
||||
@@ -247,7 +243,7 @@ pub mod imp {
|
||||
}
|
||||
}
|
||||
}));
|
||||
dialog.present();
|
||||
dialog.present(&obj);
|
||||
}));
|
||||
log::trace!("Setting up sync-contacts action");
|
||||
let action_sync_contacts = SimpleAction::new("sync-contacts", None);
|
||||
@@ -274,16 +270,16 @@ pub mod imp {
|
||||
|
||||
log::trace!("Setting up about-page action");
|
||||
let action_about = SimpleAction::new("about", None);
|
||||
action_about.connect_activate(|_, _| {
|
||||
action_about.connect_activate(clone!(@weak obj => move |_, _| {
|
||||
let builder = Builder::from_resource("/ui/about.ui");
|
||||
let about: AboutWindow = builder
|
||||
let about: AboutDialog = builder
|
||||
.object("about")
|
||||
.expect("about.ui to have at least one object about");
|
||||
// TODO: Replace this in Blueprint when string[] is supported
|
||||
about.set_artists(&["David Lapshin <[email protected]>"]);
|
||||
about.add_link("GitLab", "https://gitlab.com/schmiddi-on-mobile/flare");
|
||||
about.present();
|
||||
});
|
||||
about.present(&obj);
|
||||
}));
|
||||
|
||||
log::trace!("Setting up kill action");
|
||||
let action_kill = SimpleAction::new("kill", None);
|
||||
@@ -296,16 +292,17 @@ pub mod imp {
|
||||
action_channel_information.connect_activate(clone!(@weak obj => move |_, _| {
|
||||
log::trace!("Requested channel info");
|
||||
let Some(channel) = obj.imp().channel_messages.active_channel() else {return};
|
||||
let channel_info = ChannelInfoDialog::new(&channel, &obj.manager(), &obj);
|
||||
channel_info.present();
|
||||
// TODO: To AlertDialog
|
||||
let channel_info = ChannelInfoDialog::new(&channel, &obj.manager());
|
||||
channel_info.present(&obj);
|
||||
}));
|
||||
|
||||
log::trace!("Setting up channel clear messages action");
|
||||
let action_channel_clear_messages = SimpleAction::new("channel-clear-messages", None);
|
||||
action_channel_clear_messages.connect_activate(clone!(@weak obj => move |_, _| {
|
||||
log::trace!("Requested clearing messages of channels");
|
||||
let confirmation_dialog = MessageDialog::builder()
|
||||
.transient_for(&obj)
|
||||
// TODO: To AlertDialog
|
||||
let confirmation_dialog = AlertDialog::builder()
|
||||
.heading(gettextrs::gettext("Remove Messages"))
|
||||
.body(gettextrs::gettext("This will remove all locally stored messages from this channel"))
|
||||
.close_response("cancel")
|
||||
@@ -314,11 +311,11 @@ pub mod imp {
|
||||
confirmation_dialog.add_response("cancel", &gettextrs::gettext("Cancel"));
|
||||
confirmation_dialog.add_response("remove", &gettextrs::gettext("Remove Messages"));
|
||||
confirmation_dialog.set_response_appearance("remove", ResponseAppearance::Destructive);
|
||||
confirmation_dialog.choose(None::<&Cancellable>, clone!(@weak obj => move |response| {
|
||||
confirmation_dialog.choose(&obj, None::<&Cancellable>, clone!(@weak obj => move |response| {
|
||||
if response == "remove" {
|
||||
if let Err(e) = obj.imp().channel_messages.clear_messages() {
|
||||
let dialog = ErrorDialog::new(e, &obj);
|
||||
dialog.present();
|
||||
dialog.present(&obj);
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -399,7 +396,7 @@ pub mod imp {
|
||||
action_linked_devices.connect_activate(clone!(@weak obj => move |_, _| {
|
||||
log::trace!("User requested to view linked devices");
|
||||
let win = LinkedDevicesWindow::new(obj.manager(), &obj);
|
||||
win.present();
|
||||
win.present(&obj);
|
||||
}));
|
||||
|
||||
self.obj()
|
||||
@@ -520,7 +517,7 @@ pub mod imp {
|
||||
|
||||
if let Err(e) = manager.init(&path).await {
|
||||
let dialog = ErrorDialog::new(e, &obj);
|
||||
dialog.present();
|
||||
dialog.present(&obj);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user