diff --git a/Cargo.lock b/Cargo.lock index c108aa76..15bf6bf7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,6 +229,12 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-once-cell" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9338790e78aa95a416786ec8389546c4b6a1dfc3dc36071ed9518a9413a542eb" + [[package]] name = "async-process" version = "1.7.0" @@ -596,6 +602,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg-vis" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a2c3bf5fc10fe2ca157564fbe08a4cb2b0a7d2ff3fe2f9683e65d5e7c7859c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "chacha20" version = "0.8.2" @@ -693,6 +711,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" +[[package]] +name = "const_panic" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -1133,9 +1157,9 @@ dependencies = [ [[package]] name = "eyeball" -version = "0.6.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1015c5225a75e0ab3d325e934456d92fdd57f440e8c81d09018878d4f651cd46" +checksum = "40db066b8b21f8f8e49746cee2bfdcceb8d675cb3e2ff5fd7c7d86aadf69b6f5" dependencies = [ "futures-core", "readlock", @@ -1267,11 +1291,12 @@ dependencies = [ "html-escape", "html2pango", "image 0.24.6", - "indexmap 1.9.3", + "indexmap 2.0.0", "libadwaita", "libshumate", "log", "matrix-sdk", + "matrix-sdk-ui", "mime", "mime_guess", "once_cell", @@ -2466,7 +2491,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde", ] [[package]] @@ -2477,6 +2501,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", "hashbrown 0.14.0", + "serde", ] [[package]] @@ -2527,6 +2552,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.8" @@ -2571,25 +2605,30 @@ dependencies = [ [[package]] name = "konst" -version = "0.2.19" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f0e13e6483b8c34885f7e6c9f19b1a7bd449c673fbb948a51c99d66ef74f4" +checksum = "1d9a8bb6c7c71d151b25936b03e012a4c00daea99e3a3797c6ead66b0a0d55e2" dependencies = [ - "konst_macro_rules", + "const_panic", + "konst_kernel", "konst_proc_macros", + "typewit", ] [[package]] -name = "konst_macro_rules" -version = "0.2.19" +name = "konst_kernel" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" +checksum = "55d2ab266022e7309df89ed712bddc753e3a3c395c3ced1bb2e4470ec2a8146d" +dependencies = [ + "typewit", +] [[package]] name = "konst_proc_macros" -version = "0.2.11" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984e109462d46ad18314f10e392c286c3d47bce203088a09012de1015b45b737" +checksum = "4e28ab1dc35e09d60c2b8c90d12a9a8d9666c876c10a3739a3196db0103b6043" [[package]] name = "kv-log-macro" @@ -2866,7 +2905,7 @@ dependencies = [ [[package]] name = "matrix-sdk" version = "0.6.2" -source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=d6100915dfb233c90dab8d64512c0e6063be70e3#d6100915dfb233c90dab8d64512c0e6063be70e3" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" dependencies = [ "anymap2", "async-stream", @@ -2874,7 +2913,7 @@ dependencies = [ "backoff", "bytes", "bytesize", - "chrono", + "cfg-vis", "dashmap", "event-listener", "eyeball", @@ -2886,15 +2925,12 @@ dependencies = [ "hyper", "image 0.24.6", "imbl", - "indexmap 1.9.3", "matrix-sdk-base", "matrix-sdk-common", "matrix-sdk-indexeddb", "matrix-sdk-sqlite", "mime", "mime2ext", - "once_cell", - "pin-project-lite", "rand 0.8.5", "reqwest", "ruma", @@ -2913,7 +2949,7 @@ dependencies = [ [[package]] name = "matrix-sdk-base" version = "0.6.1" -source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=d6100915dfb233c90dab8d64512c0e6063be70e3#d6100915dfb233c90dab8d64512c0e6063be70e3" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" dependencies = [ "async-trait", "bitflags 2.3.3", @@ -2935,7 +2971,7 @@ dependencies = [ [[package]] name = "matrix-sdk-common" version = "0.6.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=d6100915dfb233c90dab8d64512c0e6063be70e3#d6100915dfb233c90dab8d64512c0e6063be70e3" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" dependencies = [ "futures-core", "futures-util", @@ -2951,7 +2987,7 @@ dependencies = [ [[package]] name = "matrix-sdk-crypto" version = "0.6.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=d6100915dfb233c90dab8d64512c0e6063be70e3#d6100915dfb233c90dab8d64512c0e6063be70e3" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" dependencies = [ "aes", "async-std", @@ -2966,7 +3002,7 @@ dependencies = [ "futures-core", "futures-util", "hmac", - "itertools", + "itertools 0.11.0", "matrix-sdk-common", "matrix-sdk-qrcode", "pbkdf2 0.11.0", @@ -2980,6 +3016,7 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "ulid", "vodozemac", "zeroize", ] @@ -2987,7 +3024,7 @@ dependencies = [ [[package]] name = "matrix-sdk-indexeddb" version = "0.2.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=d6100915dfb233c90dab8d64512c0e6063be70e3#d6100915dfb233c90dab8d64512c0e6063be70e3" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" dependencies = [ "anyhow", "async-trait", @@ -3012,7 +3049,7 @@ dependencies = [ [[package]] name = "matrix-sdk-qrcode" version = "0.4.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=d6100915dfb233c90dab8d64512c0e6063be70e3#d6100915dfb233c90dab8d64512c0e6063be70e3" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" dependencies = [ "byteorder", "qrcode", @@ -3024,10 +3061,11 @@ dependencies = [ [[package]] name = "matrix-sdk-sqlite" version = "0.1.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=d6100915dfb233c90dab8d64512c0e6063be70e3#d6100915dfb233c90dab8d64512c0e6063be70e3" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" dependencies = [ "async-trait", "deadpool-sqlite", + "itertools 0.11.0", "matrix-sdk-base", "matrix-sdk-crypto", "matrix-sdk-store-encryption", @@ -3045,7 +3083,7 @@ dependencies = [ [[package]] name = "matrix-sdk-store-encryption" version = "0.2.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=d6100915dfb233c90dab8d64512c0e6063be70e3#d6100915dfb233c90dab8d64512c0e6063be70e3" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" dependencies = [ "blake3", "chacha20poly1305", @@ -3062,6 +3100,36 @@ dependencies = [ "zeroize", ] +[[package]] +name = "matrix-sdk-ui" +version = "0.6.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk.git?rev=1dea482e4399aaca5e96611e732ed06c3de2d4a6#1dea482e4399aaca5e96611e732ed06c3de2d4a6" +dependencies = [ + "async-once-cell", + "async-std", + "async-trait", + "chrono", + "eyeball", + "eyeball-im", + "futures-core", + "futures-util", + "imbl", + "indexmap 2.0.0", + "itertools 0.11.0", + "matrix-sdk", + "matrix-sdk-base", + "matrix-sdk-crypto", + "mime", + "once_cell", + "pin-project-lite", + "ruma", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "memchr" version = "2.5.0" @@ -3857,7 +3925,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", @@ -4099,10 +4167,12 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-socks", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "winreg", ] @@ -4149,7 +4219,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.8.2" -source = "git+https://github.com/ruma/ruma.git?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" +source = "git+https://github.com/ruma/ruma.git?rev=a641adb4287267ba9c4778ac1ee83b4ecab11e26#a641adb4287267ba9c4778ac1ee83b4ecab11e26" dependencies = [ "assign", "js_int", @@ -4163,7 +4233,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.16.2" -source = "git+https://github.com/ruma/ruma.git?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" +source = "git+https://github.com/ruma/ruma.git?rev=a641adb4287267ba9c4778ac1ee83b4ecab11e26#a641adb4287267ba9c4778ac1ee83b4ecab11e26" dependencies = [ "assign", "bytes", @@ -4180,7 +4250,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.11.3" -source = "git+https://github.com/ruma/ruma.git?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" +source = "git+https://github.com/ruma/ruma.git?rev=a641adb4287267ba9c4778ac1ee83b4ecab11e26#a641adb4287267ba9c4778ac1ee83b4ecab11e26" dependencies = [ "base64 0.21.2", "bytes", @@ -4188,7 +4258,7 @@ dependencies = [ "getrandom 0.2.10", "html5ever", "http", - "indexmap 1.9.3", + "indexmap 2.0.0", "js-sys", "js_int", "js_option", @@ -4213,7 +4283,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma.git?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" +source = "git+https://github.com/ruma/ruma.git?rev=a641adb4287267ba9c4778ac1ee83b4ecab11e26#a641adb4287267ba9c4778ac1ee83b4ecab11e26" dependencies = [ "js_int", "ruma-common", @@ -4224,7 +4294,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.1" -source = "git+https://github.com/ruma/ruma.git?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" +source = "git+https://github.com/ruma/ruma.git?rev=a641adb4287267ba9c4778ac1ee83b4ecab11e26#a641adb4287267ba9c4778ac1ee83b4ecab11e26" dependencies = [ "js_int", "thiserror", @@ -4233,7 +4303,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.11.3" -source = "git+https://github.com/ruma/ruma.git?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" +source = "git+https://github.com/ruma/ruma.git?rev=a641adb4287267ba9c4778ac1ee83b4ecab11e26#a641adb4287267ba9c4778ac1ee83b4ecab11e26" dependencies = [ "once_cell", "proc-macro-crate", @@ -4248,7 +4318,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma.git?rev=54a4223caa1c1052464ecdba0f1e08f126e07bcd#54a4223caa1c1052464ecdba0f1e08f126e07bcd" +source = "git+https://github.com/ruma/ruma.git?rev=a641adb4287267ba9c4778ac1ee83b4ecab11e26#a641adb4287267ba9c4778ac1ee83b4ecab11e26" dependencies = [ "js_int", "ruma-common", @@ -5042,6 +5112,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "typewit" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4061a10d4d8f3081a8ccc025182afd8434302d8d4b4503ec6d8510d09df08c2d" + [[package]] name = "uds_windows" version = "1.0.2" @@ -5052,6 +5128,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ulid" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a3aaa69b04e5b66cc27309710a569ea23593612387d67daaf102e73aa974fd" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "unicase" version = "2.6.0" @@ -5164,8 +5249,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vodozemac" -version = "0.3.0" -source = "git+https://github.com/matrix-org/vodozemac?rev=fb609ca1e4df5a7a818490ae86ac694119e41e71#fb609ca1e4df5a7a818490ae86ac694119e41e71" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d1b4c112e19e1f9361e34c7a40d30bd7f1de0fec43b83f2f8383d6eee9f561" dependencies = [ "aes", "arrayvec", @@ -5286,6 +5372,19 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +[[package]] +name = "wasm-streams" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.64" diff --git a/Cargo.toml b/Cargo.toml index 1fdce84a..960ba68e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ gst_video = { version = "0.20", package = "gstreamer-video" } html-escape = "0.2" html2pango = "0.5" image = "0.24" -indexmap = "1" +indexmap = "2" log = "0.4" mime = "0.3" mime_guess = "2" @@ -78,20 +78,25 @@ features = ["v4_10"] [dependencies.matrix-sdk] git = "https://github.com/matrix-org/matrix-rust-sdk.git" -rev = "d6100915dfb233c90dab8d64512c0e6063be70e3" +rev = "1dea482e4399aaca5e96611e732ed06c3de2d4a6" features = [ "socks", "sso-login", "markdown", "qrcode", - "experimental-timeline", "image-rayon", ] +[dependencies.matrix-sdk-ui] +git = "https://github.com/matrix-org/matrix-rust-sdk.git" +rev = "1dea482e4399aaca5e96611e732ed06c3de2d4a6" +default-features = false +features = ["e2e-encryption", "native-tls"] + [dependencies.ruma] # version = "0.8.2" git = "https://github.com/ruma/ruma.git" -rev = "54a4223caa1c1052464ecdba0f1e08f126e07bcd" +rev = "a641adb4287267ba9c4778ac1ee83b4ecab11e26" features = [ "unstable-unspecified", "client-api-c", diff --git a/src/login/homeserver_page.rs b/src/login/homeserver_page.rs index 79de21b7..f13667e1 100644 --- a/src/login/homeserver_page.rs +++ b/src/login/homeserver_page.rs @@ -258,7 +258,7 @@ impl LoginHomeserverPage { return; }; - let handle = spawn_tokio!(async move { client.get_login_types().await }); + let handle = spawn_tokio!(async move { client.matrix_auth().get_login_types().await }); match handle.await.unwrap() { Ok(res) => { diff --git a/src/login/method_page.rs b/src/login/method_page.rs index f371c6d0..0821e9fa 100644 --- a/src/login/method_page.rs +++ b/src/login/method_page.rs @@ -238,6 +238,7 @@ impl LoginMethodPage { let client = login.client().await.unwrap(); let handle = spawn_tokio!(async move { client + .matrix_auth() .login_username(&username, &password) .initial_device_display_name("Fractal") .send() diff --git a/src/login/mod.rs b/src/login/mod.rs index c4fcfb07..891a61cb 100644 --- a/src/login/mod.rs +++ b/src/login/mod.rs @@ -445,6 +445,7 @@ impl Login { let handle = spawn_tokio!(async move { let mut login = client + .matrix_auth() .login_sso(|sso_url| async move { let ctx = glib::MainContext::default(); ctx.spawn(async move { @@ -490,7 +491,7 @@ impl Login { .await .unwrap(); - match Session::new(homeserver, response.into()).await { + match Session::new(homeserver, (&response).into()).await { Ok(session) => { self.init_session(session).await; } diff --git a/src/secret.rs b/src/secret.rs index 6e364c2f..decf27a6 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -3,10 +3,14 @@ use std::{collections::HashMap, ffi::OsStr, fmt, fs, path::PathBuf, string::From use gettextrs::gettext; use gtk::glib; use log::{debug, error, warn}; -use matrix_sdk::ruma::{DeviceId, OwnedDeviceId, OwnedUserId, UserId}; +use matrix_sdk::{ + matrix_auth::{Session as MatrixSession, SessionTokens}, + SessionMeta, +}; use once_cell::sync::Lazy; use oo7::{Item, Keyring}; use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use ruma::{DeviceId, OwnedDeviceId, OwnedUserId, UserId}; use serde::{Deserialize, Serialize}; use serde_json::error::Error as JsonError; use thiserror::Error; @@ -307,12 +311,10 @@ impl StoredSession { } /// Construct a `StoredSession` from the given login data. - pub fn with_login_data(homeserver: Url, data: matrix_sdk::Session) -> Self { - let matrix_sdk::Session { - access_token, - user_id, - device_id, - .. + pub fn with_login_data(homeserver: Url, data: MatrixSession) -> Self { + let MatrixSession { + meta: SessionMeta { user_id, device_id }, + tokens: SessionTokens { access_token, .. }, } = data; let path = DATA_PATH.join(glib::uuid_string_random().as_str()); @@ -339,7 +341,7 @@ impl StoredSession { } /// Split this `StoredSession` into parts. - pub fn into_parts(self) -> (Url, PathBuf, String, matrix_sdk::Session) { + pub fn into_parts(self) -> (Url, PathBuf, String, MatrixSession) { let Self { homeserver, user_id, @@ -352,11 +354,12 @@ impl StoredSession { .. } = self; - let data = matrix_sdk::Session { - access_token, - user_id, - device_id, - refresh_token: None, + let data = MatrixSession { + meta: SessionMeta { user_id, device_id }, + tokens: SessionTokens { + access_token, + refresh_token: None, + }, }; (homeserver, path, passphrase, data) @@ -426,7 +429,7 @@ impl StoredSession { debug!("Logging out session"); match matrix::client_with_stored_session(self.clone()).await { Ok(client) => { - if let Err(error) = client.logout().await { + if let Err(error) = client.matrix_auth().logout().await { error!("Failed to log out session: {error}"); } } diff --git a/src/session/model/room/event/mod.rs b/src/session/model/room/event/mod.rs index d9b8eeaa..063d877e 100644 --- a/src/session/model/room/event/mod.rs +++ b/src/session/model/room/event/mod.rs @@ -1,17 +1,15 @@ use std::fmt; use gtk::{glib, prelude::*, subclass::prelude::*}; -use matrix_sdk::{ - room::timeline::{ - AnyOtherFullStateEventContent, EventTimelineItem, RepliedToEvent, TimelineDetails, - TimelineItemContent, - }, - ruma::{ - events::room::message::MessageType, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, - }, - Error as MatrixError, +use matrix_sdk_ui::timeline::{ + AnyOtherFullStateEventContent, Error as TimelineError, EventTimelineItem, RepliedToEvent, + TimelineDetails, TimelineItemContent, +}; +use ruma::{ + events::{room::message::MessageType, AnySyncTimelineEvent}, + serde::Raw, + MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId, OwnedUserId, }; -use ruma::{events::AnySyncTimelineEvent, serde::Raw, OwnedTransactionId}; mod reaction_group; mod reaction_list; @@ -465,7 +463,7 @@ impl Event { /// Fetch missing details for this event. /// /// This is a no-op if called for a local event. - pub async fn fetch_missing_details(&self) -> Result<(), MatrixError> { + pub async fn fetch_missing_details(&self) -> Result<(), TimelineError> { let Some(event_id) = self.event_id() else { return Ok(()); }; diff --git a/src/session/model/room/event/reaction_group.rs b/src/session/model/room/event/reaction_group.rs index 452e3e4d..3f53811e 100644 --- a/src/session/model/room/event/reaction_group.rs +++ b/src/session/model/room/event/reaction_group.rs @@ -1,5 +1,5 @@ use gtk::{glib, prelude::*, subclass::prelude::*}; -use matrix_sdk::room::timeline::ReactionGroup as SdkReactionGroup; +use matrix_sdk_ui::timeline::ReactionGroup as SdkReactionGroup; use super::EventKey; use crate::{prelude::*, session::model::User}; @@ -117,15 +117,15 @@ impl ReactionGroup { .borrow() .as_ref() .and_then(|reactions| { - reactions.iter().find_map(|(timeline_key, sender)| { - (*sender == user_id).then(|| match timeline_key { + reactions + .by_sender(&user_id) + .next() + .and_then(|timeline_key| match timeline_key { (Some(txn_id), None) => Some(EventKey::TransactionId(txn_id.clone())), (_, Some(event_id)) => Some(EventKey::EventId(event_id.clone())), _ => None, }) - }) }) - .flatten() } /// Whether this group has a reaction from the logged-in user. @@ -135,7 +135,7 @@ impl ReactionGroup { .reactions .borrow() .as_ref() - .filter(|reactions| reactions.iter().any(|(_, sender)| *sender == user_id)) + .filter(|reactions| reactions.by_sender(&user_id).next().is_some()) .is_some() } diff --git a/src/session/model/room/event/reaction_list.rs b/src/session/model/room/event/reaction_list.rs index 6c61dfa8..1d6da001 100644 --- a/src/session/model/room/event/reaction_list.rs +++ b/src/session/model/room/event/reaction_list.rs @@ -1,5 +1,5 @@ use gtk::{gio, glib, prelude::*, subclass::prelude::*}; -use matrix_sdk::room::timeline::BundledReactions; +use matrix_sdk_ui::timeline::BundledReactions; use super::ReactionGroup; use crate::session::model::User; diff --git a/src/session/model/room/mod.rs b/src/session/model/room/mod.rs index e8c66023..5418b8d1 100644 --- a/src/session/model/room/mod.rs +++ b/src/session/model/room/mod.rs @@ -15,25 +15,23 @@ use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*}; use log::{debug, error, warn}; use matrix_sdk::{ attachment::{generate_image_thumbnail, AttachmentConfig, AttachmentInfo, Thumbnail}, - deserialized_responses::{MemberEvent, SyncTimelineEvent}, + deserialized_responses::{MemberEvent, SyncOrStrippedState, SyncTimelineEvent}, room::Room as MatrixRoom, - ruma::{ - events::{ - reaction::ReactionEventContent, - receipt::{ReceiptEventContent, ReceiptType}, - relation::Annotation, - tag::{TagInfo, TagName}, - AnyRoomAccountDataEvent, AnySyncStateEvent, AnySyncTimelineEvent, StateEventType, - SyncStateEvent, - }, - OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, - }, sync::{JoinedRoom, LeftRoom}, DisplayName, Result as MatrixResult, RoomMemberships, RoomState, }; -use ruma::events::{ - receipt::ReceiptThread, room::power_levels::PowerLevelAction, typing::TypingEventContent, - AnyMessageLikeEventContent, SyncEphemeralRoomEvent, +use ruma::{ + events::{ + reaction::ReactionEventContent, + receipt::{ReceiptEventContent, ReceiptThread, ReceiptType}, + relation::Annotation, + room::power_levels::{PowerLevelAction, RoomPowerLevelsEventContent}, + tag::{TagInfo, TagName}, + typing::TypingEventContent, + AnyMessageLikeEventContent, AnyRoomAccountDataEvent, AnySyncStateEvent, + AnySyncTimelineEvent, SyncEphemeralRoomEvent, SyncStateEvent, + }, + OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, }; pub use self::{ @@ -1215,7 +1213,7 @@ impl Room { let matrix_room = self.matrix_room(); let handle = spawn_tokio!(async move { let state_event = match matrix_room - .get_state_event(StateEventType::RoomPowerLevels, "") + .get_state_event_static::() .await { Ok(state_event) => state_event, @@ -1226,13 +1224,10 @@ impl Room { }; state_event - .and_then(|e| e.deserialize().ok()) - .and_then(|e| { - if let AnySyncStateEvent::RoomPowerLevels(SyncStateEvent::Original(e)) = e { - Some(e) - } else { - None - } + .and_then(|r| r.deserialize().ok()) + .and_then(|ev| match ev { + SyncOrStrippedState::Sync(SyncStateEvent::Original(e)) => Some(e), + _ => None, }) }); diff --git a/src/session/model/room/timeline/mod.rs b/src/session/model/room/timeline/mod.rs index 585e0b0d..9eef88af 100644 --- a/src/session/model/room/timeline/mod.rs +++ b/src/session/model/room/timeline/mod.rs @@ -10,12 +10,12 @@ use eyeball_im::VectorDiff; use futures::StreamExt; use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*}; use log::{error, warn}; -use matrix_sdk::{ - room::timeline::{PaginationOptions, Timeline as SdkTimeline, TimelineItem as SdkTimelineItem}, - ruma::OwnedEventId, - Error as MatrixError, +use matrix_sdk::Error as MatrixError; +use matrix_sdk_ui::timeline::{ + BackPaginationStatus, PaginationOptions, RoomExt, Timeline as SdkTimeline, + TimelineItem as SdkTimelineItem, }; -use ruma::events::AnySyncTimelineEvent; +use ruma::{events::AnySyncTimelineEvent, OwnedEventId}; pub use self::{ timeline_item::{TimelineItem, TimelineItemExt, TimelineItemImpl}, @@ -36,6 +36,13 @@ pub enum TimelineState { Complete, } +impl TimelineState { + /// Whether this state is represented by a virtual item. + pub fn has_virtual_item(&self) -> bool { + matches!(*self, Self::Loading | Self::Complete) + } +} + const MAX_BATCH_SIZE: u16 = 20; mod imp { @@ -109,7 +116,12 @@ mod imp { } fn n_items(&self) -> u32 { - let mut len = self.obj().n_items_in_list(); + let obj = self.obj(); + let mut len = obj.n_items_in_list(); + + if obj.state().has_virtual_item() { + len += 1; + } if self.has_typing.get() { len += 1; @@ -141,8 +153,8 @@ impl Timeline { /// The number of visible items in the list. /// - /// This is like `n_items` without items not in the list (e.g. the typing - /// indicator). + /// This is like `n_items` without items not in the list (e.g. the spinner + /// or the typing indicator). fn n_items_in_list(&self) -> u32 { self.imp() .list @@ -152,9 +164,35 @@ impl Timeline { .count() as u32 } - fn item(&self, position: u32) -> Option { + /// Adjust the position of an item in the list, to reflect its true position + /// in the `GListModel`. + /// + /// It can change according to items that are not in the list (e.g. the + /// spinner or the timeline start). + fn adjust_item_position(&self, pos: &mut u32) { + if self.state().has_virtual_item() { + *pos += 1; + } + } + + fn item(&self, mut position: u32) -> Option { let imp = self.imp(); + let state = self.state(); + if state.has_virtual_item() { + if position == 0 { + let item = match state { + TimelineState::Loading => VirtualItem::spinner(), + TimelineState::Complete => VirtualItem::timeline_start(), + _ => unreachable!(), + }; + + return Some(item.upcast()); + } + + position -= 1; + } + if imp.has_typing.get() && position == self.n_items_in_list() { return Some(VirtualItem::typing().upcast()); } @@ -184,7 +222,9 @@ impl Timeline { match diff { VectorDiff::Append { values } => { - let pos = self.n_items_in_list(); + let mut pos = self.n_items_in_list(); + self.adjust_item_position(&mut pos); + let new_list = values .into_iter() .map(|item| self.create_item(&item)) @@ -216,7 +256,10 @@ impl Timeline { list.borrow_mut().push_front(item); if visible { - self.items_changed(0, 0, 1); + let mut pos = 0; + self.adjust_item_position(&mut pos); + + self.items_changed(pos, 0, 1); } } VectorDiff::PushBack { value } => { @@ -231,7 +274,10 @@ impl Timeline { list.borrow_mut().push_back(item); if visible { - self.items_changed(self.n_items_in_list() - 1, 0, 1); + let mut pos = self.n_items_in_list() - 1; + self.adjust_item_position(&mut pos); + + self.items_changed(pos, 0, 1); } } VectorDiff::PopFront => { @@ -240,7 +286,10 @@ impl Timeline { let visible = item.is_visible(); if visible { - self.items_changed(0, 1, 0); + let mut pos = 0; + self.adjust_item_position(&mut pos); + + self.items_changed(pos, 1, 0); } } VectorDiff::PopBack => { @@ -249,7 +298,10 @@ impl Timeline { let visible = item.is_visible(); if visible { - self.items_changed(self.n_items_in_list(), 1, 0); + let mut pos = self.n_items_in_list(); + self.adjust_item_position(&mut pos); + + self.items_changed(pos, 1, 0); } } VectorDiff::Insert { index, value } => { @@ -330,7 +382,10 @@ impl Timeline { *list.borrow_mut() = new_list; - self.items_changed(0, removed, added as u32); + let mut pos = 0; + self.adjust_item_position(&mut pos); + + self.items_changed(pos, removed, added as u32); } } } @@ -375,10 +430,6 @@ impl Timeline { .event_map .borrow_mut() .insert(event.key(), event.clone()); - } else if let Some(virtual_item) = item.downcast_ref::() { - if virtual_item.kind() == VirtualItemKind::TimelineStart { - self.set_state(TimelineState::Complete); - } } item @@ -388,12 +439,6 @@ impl Timeline { fn remove_item(&self, item: &TimelineItem) { if let Some(event) = item.downcast_ref::() { self.imp().event_map.borrow_mut().remove(&event.key()); - } else if item - .downcast_ref::() - .map_or(false, |item| item.kind() == VirtualItemKind::Spinner) - && self.state() == TimelineState::Loading - { - self.set_state(TimelineState::Ready) } } @@ -451,18 +496,24 @@ impl Timeline { /// Get the position of the given item in this `Timeline`. pub fn find_item_position(&self, item: &TimelineItem) -> Option { - self.imp() + let mut pos = self + .imp() .list .borrow() .iter() .filter(|item| item.is_visible()) .enumerate() - .find_map(|(pos, list_item)| (item == list_item).then_some(pos as u32)) + .find_map(|(pos, list_item)| (item == list_item).then_some(pos as u32))?; + + self.adjust_item_position(&mut pos); + + Some(pos) } /// Get the position of the event with the given key in this `Timeline`. pub fn find_event_position(&self, key: &EventKey) -> Option { - self.imp() + let mut pos = self + .imp() .list .borrow() .iter() @@ -472,7 +523,13 @@ impl Timeline { item.downcast_ref::() .filter(|event| event.key() == *key) .map(|_| pos) - }) + })?; + + if self.state().has_virtual_item() { + pos += 1; + } + + Some(pos) } /// Fetch the event with the given id. @@ -555,11 +612,44 @@ impl Timeline { self.set_state(TimelineState::Ready); + spawn!(clone!(@weak self as obj => async move { + obj.setup_back_pagination_status().await; + })); + while let Some(diff) = receiver.next().await { self.update(diff); } } + /// Setup the back-pagination status. + async fn setup_back_pagination_status(&self) { + let room_id = self.room().room_id().to_owned(); + let matrix_timeline = self.matrix_timeline(); + + let (mut sender, mut receiver) = futures::channel::mpsc::channel(8); + let stream = matrix_timeline.back_pagination_status(); + + let fut = stream.for_each(move |status| { + if let Err(error) = sender.try_send(status) { + error!("Error sending back-pagination status for room {room_id}: {error}"); + panic!(); + } + + async {} + }); + spawn_tokio!(fut); + + while let Some(status) = receiver.next().await { + match status { + BackPaginationStatus::Idle => self.set_state(TimelineState::Ready), + BackPaginationStatus::Paginating => self.set_state(TimelineState::Loading), + BackPaginationStatus::TimelineStartReached => { + self.set_state(TimelineState::Complete) + } + } + } + } + /// The room containing this timeline. pub fn room(&self) -> Room { self.imp().room.upgrade().unwrap() @@ -572,14 +662,22 @@ impl Timeline { fn set_state(&self, state: TimelineState) { let imp = self.imp(); + let prev_state = self.state(); - if state == self.state() { + if state == prev_state { return; } imp.state.set(state); self.notify("state"); + + let removed = if prev_state.has_virtual_item() { 1 } else { 0 }; + let added = if state.has_virtual_item() { 1 } else { 0 }; + + if removed > 0 || added > 0 { + self.items_changed(0, removed, added); + } } /// The state of the timeline. diff --git a/src/session/model/room/timeline/timeline_item.rs b/src/session/model/room/timeline/timeline_item.rs index e5eafe27..6a2a8233 100644 --- a/src/session/model/room/timeline/timeline_item.rs +++ b/src/session/model/room/timeline/timeline_item.rs @@ -1,5 +1,5 @@ use gtk::{glib, prelude::*, subclass::prelude::*}; -use matrix_sdk::room::timeline::TimelineItem as SdkTimelineItem; +use matrix_sdk_ui::timeline::{TimelineItem as SdkTimelineItem, TimelineItemKind}; use super::VirtualItem; use crate::session::model::{Event, Member, Room}; @@ -120,9 +120,9 @@ impl TimelineItem { /// /// Constructs the proper child type. pub fn new(item: &SdkTimelineItem, room: &Room) -> Self { - match item { - SdkTimelineItem::Event(event) => Event::new(event.clone(), room).upcast(), - SdkTimelineItem::Virtual(item) => VirtualItem::new(item).upcast(), + match item.kind() { + TimelineItemKind::Event(event) => Event::new(event.clone(), room).upcast(), + TimelineItemKind::Virtual(item) => VirtualItem::new(item).upcast(), } } @@ -130,13 +130,13 @@ impl TimelineItem { /// /// Returns `true` if the update succeeded. pub fn try_update_with(&self, item: &SdkTimelineItem) -> bool { - match item { - SdkTimelineItem::Event(new_event) => { + match item.kind() { + TimelineItemKind::Event(new_event) => { if let Some(event) = self.downcast_ref::() { return event.try_update_with(new_event); } } - SdkTimelineItem::Virtual(_item) => { + TimelineItemKind::Virtual(_item) => { // Always invalidate. It shouldn't happen often and updating // those should be unexpensive. } diff --git a/src/session/model/room/timeline/virtual_item.rs b/src/session/model/room/timeline/virtual_item.rs index b5b6ba50..387c41d6 100644 --- a/src/session/model/room/timeline/virtual_item.rs +++ b/src/session/model/room/timeline/virtual_item.rs @@ -1,5 +1,5 @@ use gtk::{glib, prelude::*, subclass::prelude::*}; -use matrix_sdk::room::timeline::VirtualTimelineItem; +use matrix_sdk_ui::timeline::VirtualTimelineItem; use ruma::MilliSecondsSinceUnixEpoch; use super::{TimelineItem, TimelineItemImpl}; @@ -98,8 +98,6 @@ impl VirtualItem { match item { VirtualTimelineItem::DayDivider(ts) => Self::day_divider_with_timestamp(*ts), VirtualTimelineItem::ReadMarker => Self::new_messages(), - VirtualTimelineItem::LoadingIndicator => Self::spinner(), - VirtualTimelineItem::TimelineStart => Self::timeline_start(), } } diff --git a/src/session/model/session.rs b/src/session/model/session.rs index e3f4e34f..8026c382 100644 --- a/src/session/model/session.rs +++ b/src/session/model/session.rs @@ -9,22 +9,20 @@ use gtk::{ }; use log::{debug, error}; use matrix_sdk::{ - config::SyncSettings, - room::Room as MatrixRoom, - ruma::{ - api::client::{ - error::ErrorKind, - filter::{FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter}, - session::logout, - }, - assign, - events::{ - direct::DirectEventContent, room::encryption::SyncRoomEncryptionEvent, - GlobalAccountDataEvent, - }, + config::SyncSettings, matrix_auth::Session as MatrixSession, room::Room as MatrixRoom, + sync::SyncResponse, Client, +}; +use ruma::{ + api::client::{ + error::ErrorKind, + filter::{FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter}, + session::logout, + }, + assign, + events::{ + direct::DirectEventContent, room::encryption::SyncRoomEncryptionEvent, + GlobalAccountDataEvent, }, - sync::SyncResponse, - Client, }; use tokio::task::JoinHandle; use url::Url; @@ -177,7 +175,7 @@ glib::wrapper! { impl Session { /// Create a new session. - pub async fn new(homeserver: Url, data: matrix_sdk::Session) -> Result { + pub async fn new(homeserver: Url, data: MatrixSession) -> Result { let stored_session = StoredSession::with_login_data(homeserver, data); Self::restore(stored_session).await diff --git a/src/session/view/content/room_history/event_actions.rs b/src/session/view/content/room_history/event_actions.rs index c4badcec..424621f0 100644 --- a/src/session/view/content/room_history/event_actions.rs +++ b/src/session/view/content/room_history/event_actions.rs @@ -1,9 +1,9 @@ use gettextrs::gettext; use gtk::{gdk, gio, glib, glib::clone, prelude::*}; use log::error; -use matrix_sdk::{room::timeline::TimelineItemContent, ruma::events::room::message::MessageType}; +use matrix_sdk_ui::timeline::TimelineItemContent; use once_cell::sync::Lazy; -use ruma::events::room::power_levels::PowerLevelAction; +use ruma::events::room::{message::MessageType, power_levels::PowerLevelAction}; use crate::{ prelude::*, diff --git a/src/session/view/content/room_history/item_row.rs b/src/session/view/content/room_history/item_row.rs index 8881ef19..f607271c 100644 --- a/src/session/view/content/room_history/item_row.rs +++ b/src/session/view/content/room_history/item_row.rs @@ -1,7 +1,7 @@ use adw::{prelude::*, subclass::prelude::*}; use gettextrs::gettext; use gtk::{gdk, gio, glib, glib::clone}; -use matrix_sdk::room::timeline::TimelineItemContent; +use matrix_sdk_ui::timeline::TimelineItemContent; use super::{DividerRow, EventActions, MessageRow, RoomHistory, StateRow, TypingRow}; use crate::{ diff --git a/src/session/view/content/room_history/message_row/content.rs b/src/session/view/content/room_history/message_row/content.rs index 7887cf4e..2445cb4a 100644 --- a/src/session/view/content/room_history/message_row/content.rs +++ b/src/session/view/content/room_history/message_row/content.rs @@ -2,10 +2,8 @@ use adw::{prelude::*, subclass::prelude::*}; use gettextrs::gettext; use gtk::{gdk, glib, glib::clone}; use log::{error, warn}; -use matrix_sdk::{ - room::timeline::{TimelineDetails, TimelineItemContent}, - ruma::events::room::message::MessageType, -}; +use matrix_sdk_ui::timeline::{TimelineDetails, TimelineItemContent}; +use ruma::events::room::message::MessageType; use super::{ audio::MessageAudio, file::MessageFile, location::MessageLocation, media::MessageMedia, diff --git a/src/session/view/content/room_history/state_row/mod.rs b/src/session/view/content/room_history/state_row/mod.rs index 07365ff6..958ba700 100644 --- a/src/session/view/content/room_history/state_row/mod.rs +++ b/src/session/view/content/room_history/state_row/mod.rs @@ -5,14 +5,14 @@ use adw::{prelude::*, subclass::prelude::*}; use gettextrs::gettext; use gtk::{glib, CompositeTemplate}; use log::warn; -use matrix_sdk::{ - room::timeline::{ - AnyOtherFullStateEventContent, MemberProfileChange, MembershipChange, OtherState, - RoomMembershipChange, TimelineItemContent, - }, - ruma::events::room::member::MembershipState, +use matrix_sdk_ui::timeline::{ + AnyOtherFullStateEventContent, MemberProfileChange, MembershipChange, OtherState, + RoomMembershipChange, TimelineItemContent, +}; +use ruma::{ + events::{room::member::MembershipState, FullStateEventContent}, + UserId, }; -use ruma::{events::FullStateEventContent, UserId}; use self::{creation::StateCreation, tombstone::StateTombstone}; use super::ReadReceiptsList;