diff --git a/Cargo.toml b/Cargo.toml index bd7cd4b..ed374b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" ]} diff --git a/data/resources/ui/about.blp.in b/data/resources/ui/about.blp.in index 1ddd23d..c607586 100644 --- a/data/resources/ui/about.blp.in +++ b/data/resources/ui/about.blp.in @@ -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@"; diff --git a/data/resources/ui/channel_info_dialog.blp b/data/resources/ui/channel_info_dialog.blp index 01275a5..a68b608 100644 --- a/data/resources/ui/channel_info_dialog.blp +++ b/data/resources/ui/channel_info_dialog.blp @@ -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"), - ] + } } diff --git a/data/resources/ui/dialog_clear_messages.blp b/data/resources/ui/dialog_clear_messages.blp index d7566dd..eae81f2 100644 --- a/data/resources/ui/dialog_clear_messages.blp +++ b/data/resources/ui/dialog_clear_messages.blp @@ -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"; diff --git a/data/resources/ui/dialog_unlink.blp b/data/resources/ui/dialog_unlink.blp index 82f62ed..b9765f7 100644 --- a/data/resources/ui/dialog_unlink.blp +++ b/data/resources/ui/dialog_unlink.blp @@ -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"; diff --git a/data/resources/ui/error_dialog.blp b/data/resources/ui/error_dialog.blp index 2a83b68..e8f9b96 100644 --- a/data/resources/ui/error_dialog.blp +++ b/data/resources/ui/error_dialog.blp @@ -1,7 +1,7 @@ using Gtk 4.0; using Adw 1; -template $FlErrorDialog: Adw.MessageDialog { +template $FlErrorDialog: Adw.AlertDialog { heading: _("Error"); response => $handle_response(); diff --git a/data/resources/ui/linked_devices_window.blp b/data/resources/ui/linked_devices_window.blp index 3c0db0d..9d08f83 100644 --- a/data/resources/ui/linked_devices_window.blp +++ b/data/resources/ui/linked_devices_window.blp @@ -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"; diff --git a/data/resources/ui/preferences_window.blp b/data/resources/ui/preferences_window.blp index 95b9ce0..9a54514 100644 --- a/data/resources/ui/preferences_window.blp +++ b/data/resources/ui/preferences_window.blp @@ -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"; diff --git a/data/resources/ui/setup_window.blp b/data/resources/ui/setup_window.blp index 7d5a817..919cb97 100644 --- a/data/resources/ui/setup_window.blp +++ b/data/resources/ui/setup_window.blp @@ -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 { } } }; - }; + } } diff --git a/data/resources/ui/submit_captcha_dialog.blp b/data/resources/ui/submit_captcha_dialog.blp index 5294557..dbda5a6 100644 --- a/data/resources/ui/submit_captcha_dialog.blp +++ b/data/resources/ui/submit_captcha_dialog.blp @@ -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 on this website and the link to open Signal must be pasted to the corresponding entry. Note that the captcha is only valid for about one minute."); diff --git a/flake.nix b/flake.nix index 8cec553..0ebc570 100644 --- a/flake.nix +++ b/flake.nix @@ -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"; diff --git a/src/gui/attachment.rs b/src/gui/attachment.rs index 0852407..1eca381 100644 --- a/src/gui/attachment.rs +++ b/src/gui/attachment.rs @@ -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 { diff --git a/src/gui/channel_info_dialog.rs b/src/gui/channel_info_dialog.rs index f400956..886a4ce 100644 --- a/src/gui/channel_info_dialog.rs +++ b/src/gui/channel_info_dialog.rs @@ -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) - @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) -> Self { + pub fn new(channel: &Channel, manager: &Manager) -> Self { log::trace!("Initializing `ChannelInfoDialog`"); let s = Object::builder::() .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 {} } diff --git a/src/gui/channel_messages.rs b/src/gui/channel_messages.rs index 00dc3fd..f2d5a35 100644 --- a/src/gui/channel_messages.rs +++ b/src/gui/channel_messages.rs @@ -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::() .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::() .expect("Root of `ChannelMessages` to be a `Window`."); let dialog = ErrorDialog::new(e, &root); - dialog.present(); + dialog.present(&root); } }) ); diff --git a/src/gui/error_dialog.rs b/src/gui/error_dialog.rs index 1c30d41..876c0cb 100644 --- a/src/gui/error_dialog.rs +++ b/src/gui/error_dialog.rs @@ -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) - @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>, should_report: Cell, + + window: RefCell>, } #[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") + .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::>() + .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 {} } diff --git a/src/gui/linked_devices_window.rs b/src/gui/linked_devices_window.rs index 74fe761..1663ab9 100644 --- a/src/gui/linked_devices_window.rs +++ b/src/gui/linked_devices_window.rs @@ -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) - @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::() .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, + add_device_dialog: TemplateChild, #[template_child] entry_device_url: TemplateChild, manager: RefCell>, + window: RefCell>, } #[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> = Lazy::new(|| { - vec![ParamSpecObject::builder::("manager") - .construct_only() - .build()] + vec![ + ParamSpecObject::builder::("manager") + .construct_only() + .build(), + ParamSpecObject::builder::("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::>().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 {} } diff --git a/src/gui/message_item.rs b/src/gui/message_item.rs index 458a286..408cbe8 100644 --- a/src/gui/message_item.rs +++ b/src/gui/message_item.rs @@ -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::() .expect("Root of `ChannelMessages` to be a `Window`."); let dialog = ErrorDialog::new(e, &root); - dialog.present(); + dialog.present(&root); } obj.notify("has-reaction"); })); diff --git a/src/gui/preferences_window.rs b/src/gui/preferences_window.rs index b68c357..5a8bf03 100644 --- a/src/gui/preferences_window.rs +++ b/src/gui/preferences_window.rs @@ -11,7 +11,7 @@ use crate::{gspawn, tspawn}; glib::wrapper! { pub struct PreferencesWindow(ObjectSubclass) - @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 {} } diff --git a/src/gui/setup_window.rs b/src/gui/setup_window.rs index 9fa1c6b..d6622ee 100644 --- a/src/gui/setup_window.rs +++ b/src/gui/setup_window.rs @@ -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) - @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::() .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 { } 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>, + window: RefCell>, + decision_callback: RefCell>>, confirm_callback: RefCell>>, @@ -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> = Lazy::new(|| { - vec![ParamSpecObject::builder::("manager") - .construct_only() - .build()] + vec![ + ParamSpecObject::builder::("manager") + .construct_only() + .build(), + ParamSpecObject::builder::("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::>() + .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 {} } diff --git a/src/gui/window.rs b/src/gui/window.rs index 5ae4da8..2bf4d75 100644 --- a/src/gui/window.rs +++ b/src/gui/window.rs @@ -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 "]); 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); } })); }