Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 80 additions & 13 deletions reflection-app/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
use adw::prelude::*;
use adw::subclass::prelude::*;
use gettextrs::gettext;
use gtk::{gio, glib, glib::Properties, glib::clone};
use gtk::{gdk, gio, glib, glib::Properties, glib::clone};
use reflection_doc::{document::DocumentId, identity::PrivateKey, service::Service};
use std::{cell::RefCell, fs};
use thiserror::Error;
Expand Down Expand Up @@ -156,7 +156,9 @@ impl ReflectionApplication {
.activate(move |app: &Self, _, _| app.show_about())
.build();
let new_window_action = gio::ActionEntry::builder("new-window")
.activate(move |app: &Self, _, _| app.new_window())
.activate(move |app: &Self, _, _| {
app.new_window();
})
.build();
let new_document_action = gio::ActionEntry::builder("new-document")
.activate(move |app: &Self, _, _| app.new_document())
Expand All @@ -169,11 +171,11 @@ impl ReflectionApplication {
let parameter = parameter.unwrap();

if parameter.n_children() == 0 {
app.open_join_document_dialog();
app.open_join_document_dialog(false);
} else {
for i in 0..parameter.n_children() {
if let Some(document_id) = parameter.child_value(i).get() {
app.join_document(&document_id);
app.join_document(&document_id, false);
// FIXME: open all documents with it's own window
break;
} else {
Expand All @@ -183,6 +185,31 @@ impl ReflectionApplication {
}
})
.build();

let join_document_in_new_window_action =
gio::ActionEntry::builder("join-document-in-new-window")
.parameter_type(Some(&glib::VariantType::new_array(
&DocumentId::static_variant_type(),
)))
.activate(move |app: &Self, _, parameter| {
let parameter = parameter.unwrap();

if parameter.n_children() == 0 {
app.open_join_document_dialog(true);
} else {
for i in 0..parameter.n_children() {
if let Some(document_id) = parameter.child_value(i).get() {
app.join_document(&document_id, true);
// FIXME: open all documents with it's own window
break;
} else {
error!("Failed to join document: Invalid document id specified");
}
}
}
})
.build();

let delete_document_action = gio::ActionEntry::builder("delete-document")
.parameter_type(Some(&glib::VariantType::new_array(
&DocumentId::static_variant_type(),
Expand All @@ -200,6 +227,25 @@ impl ReflectionApplication {
}
})
.build();

let copy_document_id_action = gio::ActionEntry::builder("copy-document-id")
.parameter_type(Some(&glib::VariantType::new_array(
&DocumentId::static_variant_type(),
)))
.activate(move |app: &Self, _, parameter| {
let parameter = parameter.unwrap();

for i in 0..parameter.n_children() {
if let Some(document_id) = parameter.child_value(i).get() {
app.copy_document_id(&document_id);
break;
} else {
error!("Failed to copy document id: Invalid document id specified");
}
}
})
.build();

let temporary_identity_action = gio::ActionEntry::builder("new-temporary-identity")
.activate(move |app: &Self, _, _| {
glib::spawn_future_local(clone!(
Expand All @@ -218,43 +264,57 @@ impl ReflectionApplication {
new_window_action,
new_document_action,
join_document_action,
join_document_in_new_window_action,
delete_document_action,
copy_document_id_action,
temporary_identity_action,
]);
}

fn new_window(&self) {
fn new_window(&self) -> Window {
let window = Window::new(self);
window.set_service(self.service());
if let Some(error) = self.imp().startup_error.borrow().as_ref() {
window.display_startup_error(error);
}
window.present();
window
}

fn new_document(&self) {
self.join_document(&DocumentId::new());
self.join_document(&DocumentId::new(), false);
}

fn open_join_document_dialog(&self) {
let active = self.active_window();
fn open_join_document_dialog(&self, new_window: bool) {
let window = if new_window {
self.new_window()
} else if let Some(active) = self.active_window().and_downcast::<Window>() {
active
} else {
self.new_window()
};

let dialog = OpenDialog::new();
adw::prelude::AdwDialogExt::present(&dialog, active.as_ref());
adw::prelude::AdwDialogExt::present(&dialog, Some(&window));
}

fn join_document(&self, document_id: &DocumentId) {
fn join_document(&self, document_id: &DocumentId, new_window: bool) {
if let Some(window) = self.window_for_document_id(document_id) {
window.present();
} else {
let Some(service) = self.service() else {
return;
};
let Some(active) = self.active_window().and_downcast::<Window>() else {
return;

let window = if new_window {
self.new_window()
} else if let Some(active) = self.active_window().and_downcast::<Window>() {
active
} else {
self.new_window()
};
let document = service.join_document(document_id);
active.set_document(Some(&document));
window.set_document(Some(&document));
let hold_guard = self.hold();
glib::spawn_future_local(clone!(
#[weak]
Expand Down Expand Up @@ -300,6 +360,13 @@ impl ReflectionApplication {
}
}

fn copy_document_id(&self, document_id: &DocumentId) {
let Some(display) = gdk::Display::default() else {
return;
};
display.clipboard().set_text(&document_id.to_string());
}

async fn new_temporary_identity(&self) {
let private_key = PrivateKey::new();
let service = Service::new(&private_key, None);
Expand Down
12 changes: 9 additions & 3 deletions reflection-app/src/document_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
components::{MultilineEntry, ZoomLevelSelector},
};

const BASE_TEXT_FONT_SIZE: f64 = 24.0;
const BASE_TEXT_FONT_SIZE: f64 = 11.0;

mod imp {
use super::*;
Expand Down Expand Up @@ -134,7 +134,13 @@ mod imp {
let buffer = ReflectionTextBuffer::new();
self.text_view.set_buffer(Some(&buffer));

self.font_size.set(BASE_TEXT_FONT_SIZE);
let size = ReflectionApplication::default()
.system_settings()
.monospace_font_name()
.map_or(BASE_TEXT_FONT_SIZE, |font| {
font.size() as f64 / gtk::pango::SCALE as f64
});
self.font_size.set(size);
self.obj().set_font_scale(0.0);
gtk::style_context_add_provider_for_display(
&gtk::Widget::display(self.obj().upcast_ref()),
Expand Down Expand Up @@ -215,7 +221,7 @@ mod imp {
self.zoom_level.set(size / font_size);
self.obj().notify_zoom_level();
self.css_provider
.load_from_string(&format!(".sourceview {{ font-size: {size}px; }}"));
.load_from_string(&format!(".sourceview {{ font-size: {size}pt; }}"));
self.obj().action_set_enabled("window.zoom-out", size > 1.0);
}

Expand Down
13 changes: 5 additions & 8 deletions reflection-app/src/landing_view/document_row.blp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ template $ReflectionDocumentRow: Adw.ActionRow {
action-target: bind $transform_action_target(template.document as <$Document>.id) as <$GVariant>;

title: bind $transform_name(template.document as <$Document>.name) as <string>;
title-lines: 2;
subtitle: bind $transform_last_accessed(template.document as <$Document>.last_accessed, template.document as <$Document>.subscribed) as <string>;

$ReflectionAuthorsStack {
Expand All @@ -30,16 +31,14 @@ template $ReflectionDocumentRow: Adw.ActionRow {
menu menu_model {
section {
item {
label: _("_Open in new Window");
action: "app.open-document-in-window";
label: _("_Open in New Window");
action: "app.join-document-in-new-window";
hidden-when: "action-missing";
}
}

section {
item {
label: _("_Share Document...");
action: "app.share-document";
label: _("_Copy Invite Code");
action: "app.copy-document-id";
hidden-when: "action-missing";
}

Expand All @@ -48,9 +47,7 @@ menu menu_model {
action: "app.export-to-file";
hidden-when: "action-missing";
}
}

section {
item {
label: _("_Delete Document...");
action: "app.delete-document";
Expand Down
8 changes: 5 additions & 3 deletions reflection-app/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ pub fn format_datetime(last_string: &str, datetime: &glib::DateTime) -> String {

// This was ported from Nautilus and simplified for our use case.
// See: https://gitlab.gnome.org/GNOME/nautilus/-/blob/1c5bd3614a35cfbb49de087bc10381cdef5a218f/src/nautilus-file.c#L5001
let now = glib::DateTime::now_local().unwrap();
let now = glib::DateTime::now_utc().unwrap();
let format;
let days_ago = {
let today_midnight =
glib::DateTime::from_local(now.year(), now.month(), now.day_of_month(), 0, 0, 0f64)
glib::DateTime::from_utc(now.year(), now.month(), now.day_of_month(), 0, 0, 0f64)
.expect("constructing GDateTime works");

let date = glib::DateTime::from_local(
let date = glib::DateTime::from_utc(
datetime.year(),
datetime.month(),
datetime.day_of_month(),
Expand Down Expand Up @@ -159,6 +159,8 @@ pub fn format_datetime(last_string: &str, datetime: &glib::DateTime) -> String {
}

datetime
.to_local()
.expect("constructing local GDateTime works")
.format(&format)
.expect("formatting GDateTime works")
.into()
Expand Down
2 changes: 1 addition & 1 deletion reflection-doc/src/author.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl Author {
let was_online = self.imp().is_online.get();
self.imp().is_online.set(is_online);
if !is_online && was_online {
*self.imp().last_seen.lock().unwrap() = glib::DateTime::now_local().ok();
*self.imp().last_seen.lock().unwrap() = glib::DateTime::now_utc().ok();
self.notify_last_seen();
}
self.notify_is_online();
Expand Down
2 changes: 1 addition & 1 deletion reflection-doc/src/authors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl Authors {

pub(crate) fn add_this_device(&self, author_key: PublicKey) {
let mut list = self.imp().list.write().unwrap();
let now = glib::DateTime::now_local().ok();
let now = glib::DateTime::now_utc().ok();

assert!(list.is_empty());

Expand Down
6 changes: 3 additions & 3 deletions reflection-doc/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ mod imp {
/// Loro documents can contain multiple different CRDT types in one document.
static TEXT_CONTAINER_ID: LazyLock<loro::ContainerID> =
LazyLock::new(|| loro::ContainerID::new_root("document", loro::ContainerType::Text));
const DOCUMENT_NAME_LENGTH: usize = 32;
const DOCUMENT_NAME_LENGTH: usize = 124;
const SNAPSHOT_TIMEOUT: Duration = Duration::from_secs(5);

#[derive(Properties, Default)]
Expand Down Expand Up @@ -155,10 +155,10 @@ mod imp {
let mut name = String::with_capacity(DOCUMENT_NAME_LENGTH);
crdt_text.iter(|slice| {
for char in slice.chars() {
if char == '\n' {
if char == '\n' || name.len() > DOCUMENT_NAME_LENGTH {
// Only use the first line as name for the document
return false;
} else if char.is_whitespace() || char.is_alphanumeric() {
} else if (!name.is_empty() && char.is_whitespace()) || char.is_alphanumeric() {
name.push(char);
}
}
Expand Down
Loading