You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
6.6 KiB
219 lines
6.6 KiB
use sourceview::prelude::BufferExt; |
|
|
|
/// FIXME: This should be addressed in ruma directly |
|
#[macro_export] |
|
macro_rules! fn_event { |
|
( $event:ident, $fun:ident ) => { |
|
match &$event { |
|
AnyRoomEvent::Message(event) => event.$fun(), |
|
AnyRoomEvent::State(event) => event.$fun(), |
|
AnyRoomEvent::RedactedMessage(event) => event.$fun(), |
|
AnyRoomEvent::RedactedState(event) => event.$fun(), |
|
} |
|
}; |
|
} |
|
|
|
/// FIXME: This should be addressed in ruma directly |
|
#[macro_export] |
|
macro_rules! event_from_sync_event { |
|
( $event:ident, $room_id:ident) => { |
|
match $event { |
|
AnySyncRoomEvent::Message(event) => { |
|
AnyRoomEvent::Message(event.into_full_event($room_id.clone())) |
|
} |
|
AnySyncRoomEvent::State(event) => { |
|
AnyRoomEvent::State(event.into_full_event($room_id.clone())) |
|
} |
|
AnySyncRoomEvent::RedactedMessage(event) => { |
|
AnyRoomEvent::RedactedMessage(event.into_full_event($room_id.clone())) |
|
} |
|
AnySyncRoomEvent::RedactedState(event) => { |
|
AnyRoomEvent::RedactedState(event.into_full_event($room_id.clone())) |
|
} |
|
} |
|
}; |
|
} |
|
|
|
/// Spawn a future on the default `MainContext` |
|
/// |
|
/// This was taken from `gtk-macors` |
|
/// but allows setting optionally the priority |
|
/// |
|
/// FIXME: this should maybe be upstreamed |
|
#[macro_export] |
|
macro_rules! spawn { |
|
($future:expr) => { |
|
let ctx = glib::MainContext::default(); |
|
ctx.spawn_local($future); |
|
}; |
|
($priority:expr, $future:expr) => { |
|
let ctx = glib::MainContext::default(); |
|
ctx.spawn_local_with_priority($priority, $future); |
|
}; |
|
} |
|
|
|
/// Spawn a future on the tokio runtime |
|
#[macro_export] |
|
macro_rules! spawn_tokio { |
|
($future:expr) => { |
|
crate::RUNTIME.spawn($future) |
|
}; |
|
} |
|
|
|
use std::convert::TryInto; |
|
use std::path::PathBuf; |
|
use std::str::FromStr; |
|
|
|
use gettextrs::gettext; |
|
use gtk::gio::{self, prelude::*}; |
|
use gtk::glib::{self, Object}; |
|
use matrix_sdk::media::MediaType; |
|
use matrix_sdk::ruma::UInt; |
|
use mime::Mime; |
|
|
|
/// Returns an expression looking up the given property on `object`. |
|
pub fn prop_expr<T: IsA<Object>>(object: &T, prop: &str) -> gtk::Expression { |
|
let obj_expr = gtk::ConstantExpression::new(object).upcast(); |
|
gtk::PropertyExpression::new(T::static_type(), Some(&obj_expr), prop).upcast() |
|
} |
|
|
|
// Returns an expression that is the and’ed result of the given boolean expressions. |
|
#[allow(dead_code)] |
|
pub fn and_expr(a_expr: gtk::Expression, b_expr: gtk::Expression) -> gtk::Expression { |
|
gtk::ClosureExpression::new( |
|
move |args| { |
|
let a: bool = args[1].get().unwrap(); |
|
let b: bool = args[2].get().unwrap(); |
|
a && b |
|
}, |
|
&[a_expr, b_expr], |
|
) |
|
.upcast() |
|
} |
|
|
|
// Returns an expression that is the or’ed result of the given boolean expressions. |
|
pub fn or_expr(a_expr: gtk::Expression, b_expr: gtk::Expression) -> gtk::Expression { |
|
gtk::ClosureExpression::new( |
|
move |args| { |
|
let a: bool = args[1].get().unwrap(); |
|
let b: bool = args[2].get().unwrap(); |
|
a || b |
|
}, |
|
&[a_expr, b_expr], |
|
) |
|
.upcast() |
|
} |
|
|
|
// Returns an expression that is the inverted result of the given boolean expressions. |
|
#[allow(dead_code)] |
|
pub fn not_expr(a_expr: gtk::Expression) -> gtk::Expression { |
|
gtk::ClosureExpression::new( |
|
move |args| { |
|
let a: bool = args[1].get().unwrap(); |
|
!a |
|
}, |
|
&[a_expr], |
|
) |
|
.upcast() |
|
} |
|
|
|
pub fn cache_dir() -> PathBuf { |
|
let mut path = glib::user_cache_dir(); |
|
path.push("fractal"); |
|
|
|
if !path.exists() { |
|
let dir = gio::File::for_path(path.clone()); |
|
dir.make_directory_with_parents(gio::NONE_CANCELLABLE) |
|
.unwrap(); |
|
} |
|
|
|
path |
|
} |
|
|
|
/// Converts a `UInt` to `i32`. |
|
/// |
|
/// Returns `-1` if the conversion didn't work. |
|
pub fn uint_to_i32(u: Option<UInt>) -> i32 { |
|
u.and_then(|ui| { |
|
let u: Option<u16> = ui.try_into().ok(); |
|
u |
|
}) |
|
.and_then(|u| { |
|
let i: i32 = u.into(); |
|
Some(i) |
|
}) |
|
.unwrap_or(-1) |
|
} |
|
|
|
pub fn setup_style_scheme(buffer: &sourceview::Buffer) { |
|
let manager = adw::StyleManager::default().unwrap(); |
|
|
|
buffer.set_style_scheme(style_scheme().as_ref()); |
|
|
|
manager.connect_dark_notify(glib::clone!(@weak buffer => move |_| { |
|
buffer.set_style_scheme(style_scheme().as_ref()); |
|
})); |
|
} |
|
|
|
pub fn style_scheme() -> Option<sourceview::StyleScheme> { |
|
let manager = adw::StyleManager::default().unwrap(); |
|
let scheme_name = if manager.is_dark() { |
|
"Adwaita-dark" |
|
} else { |
|
"Adwaita" |
|
}; |
|
|
|
sourceview::StyleSchemeManager::default().and_then(|scm| scm.scheme(scheme_name)) |
|
} |
|
|
|
/// Get the unique id of the given `MediaType`. |
|
/// |
|
/// It is built from the underlying `MxcUri` and can be safely used in a filename. |
|
/// |
|
/// The id is not guaranteed to be unique for malformed `MxcUri`s. |
|
pub fn media_type_uid(media_type: Option<MediaType>) -> String { |
|
if let Some(mxc) = media_type |
|
.map(|media_type| match media_type { |
|
MediaType::Uri(uri) => uri, |
|
MediaType::Encrypted(file) => file.url, |
|
}) |
|
.filter(|mxc| mxc.is_valid()) |
|
{ |
|
format!("{}_{}", mxc.server_name().unwrap(), mxc.media_id().unwrap()) |
|
} else { |
|
"media_uid".to_owned() |
|
} |
|
} |
|
|
|
/// Get a default filename for a mime type. |
|
/// |
|
/// Tries to guess the file extension, but it might not find it. |
|
/// |
|
/// If the mime type is unknown, it uses the name for `fallback`. The fallback |
|
/// mime types that are recognized are `mime::IMAGE`, `mime::VIDEO` |
|
/// and `mime::AUDIO`, other values will behave the same as `None`. |
|
pub fn filename_for_mime(mime_type: Option<&str>, fallback: Option<mime::Name>) -> String { |
|
let (type_, extension) = if let Some(mime) = mime_type.and_then(|m| Mime::from_str(m).ok()) { |
|
let extension = |
|
mime_guess::get_mime_extensions(&mime).map(|extensions| extensions[0].to_owned()); |
|
|
|
(Some(mime.type_().as_str().to_owned()), extension) |
|
} else { |
|
(fallback.map(|type_| type_.as_str().to_owned()), None) |
|
}; |
|
|
|
let name = match type_.as_deref() { |
|
// Translators: Default name for image files. |
|
Some("image") => gettext("image"), |
|
// Translators: Default name for video files. |
|
Some("video") => gettext("video"), |
|
// Translators: Default name for audio files. |
|
Some("audio") => gettext("audio"), |
|
// Translators: Default name for files. |
|
_ => gettext("file"), |
|
}; |
|
|
|
extension |
|
.map(|extension| format!("{}.{}", name, extension)) |
|
.unwrap_or(name) |
|
}
|
|
|