diff --git a/data/resources/icons/scalable/status/devices-symbolic.svg b/data/resources/icons/scalable/status/devices-symbolic.svg
new file mode 100644
index 0000000000000000000000000000000000000000..9699a38f134594e207baadc4fd41b2bb94c53d1f
--- /dev/null
+++ b/data/resources/icons/scalable/status/devices-symbolic.svg
@@ -0,0 +1,151 @@
+
+
diff --git a/data/resources/icons/scalable/status/verified-symbolic.svg b/data/resources/icons/scalable/status/verified-symbolic.svg
new file mode 100644
index 0000000000000000000000000000000000000000..82a6ac86e1b920d0bf06b9ea0bbe431a0291929d
--- /dev/null
+++ b/data/resources/icons/scalable/status/verified-symbolic.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index 088f12e9652b24c57ae771f94162767f7eef16de..182b4cfc097f44ef392163449e4954cba245ede0 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -34,10 +34,17 @@
ui/in-app-notification.ui
ui/components-avatar.ui
ui/avatar-with-selection.ui
+ ui/components-auth-dialog.ui
+ ui/account-settings.ui
+ ui/account-settings-device-row.ui
+ ui/account-settings-devices-page.ui
+ ui/components-loading-listbox-row.ui
style.css
icons/scalable/actions/send-symbolic.svg
icons/scalable/status/welcome.svg
icons/scalable/status/empty-page.svg
icons/scalable/status/explore-symbolic.svg
+ icons/scalable/status/devices-symbolic.svg
+ icons/scalable/status/verified-symbolic.svg
diff --git a/data/resources/ui/account-settings-device-row.ui b/data/resources/ui/account-settings-device-row.ui
new file mode 100644
index 0000000000000000000000000000000000000000..f7646bd46bff69b11645f230af57da8d9c61e3c3
--- /dev/null
+++ b/data/resources/ui/account-settings-device-row.ui
@@ -0,0 +1,70 @@
+
+
+
+ False
+ False
+
+
+
+
+
+
diff --git a/data/resources/ui/account-settings-devices-page.ui b/data/resources/ui/account-settings-devices-page.ui
new file mode 100644
index 0000000000000000000000000000000000000000..453ee78123ae93a67156e92723586c08ceda0fa3
--- /dev/null
+++ b/data/resources/ui/account-settings-devices-page.ui
@@ -0,0 +1,39 @@
+
+
+
+ devices-symbolic
+ Sessions
+ sessions
+
+
+ Current Session
+
+
+
+ Current Session
+
+
+
+
+
+
+
+
+ Other Active Sessions
+
+
+
+ Other Active Sessions
+
+
+
+
+
+
+
+
+
diff --git a/data/resources/ui/account-settings.ui b/data/resources/ui/account-settings.ui
new file mode 100644
index 0000000000000000000000000000000000000000..c4c54c6c33998e223b595d11bffcdaa251d46e8b
--- /dev/null
+++ b/data/resources/ui/account-settings.ui
@@ -0,0 +1,15 @@
+
+
+
+ Account Settings
+ False
+
+
+
+ AccountSettings
+
+
+
+
+
+
diff --git a/data/resources/ui/components-auth-dialog.ui b/data/resources/ui/components-auth-dialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..66cc4226691ee601abc89b6d16f86aa18f1ac43c
--- /dev/null
+++ b/data/resources/ui/components-auth-dialog.ui
@@ -0,0 +1,132 @@
+
+
+
+ true
+ true
+
+ 0
+ button_ok
+
+
+
+ 12
+ vertical
+
+
+ center
+ Authentication
+ 24
+
+
+
+
+
+ False
+ False
+ 12
+ 24
+ 24
+
+
+ m.login.password
+
+
+ vertical
+ 12
+
+
+ Please authenticate the operation with your password
+ True
+ word-char
+ 60
+ center
+ start
+
+
+
+
+ True
+ True
+
+
+
+
+
+
+
+
+ fallback
+
+
+ vertical
+ 12
+
+
+ Please authenticate the operation via the browser and once completed press confirm.
+ True
+ word-char
+ 60
+ center
+ start
+
+
+
+
+ Authenticate via Browser
+ center
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ word-char
+ 60
+ center
+ start
+ 12
+
+
+
+
+ True
+ True
+ fill
+
+
+ Cancel
+
+
+
+
+ Confirm
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/resources/ui/components-loading-listbox-row.ui b/data/resources/ui/components-loading-listbox-row.ui
new file mode 100644
index 0000000000000000000000000000000000000000..bb2d4b3d78a812327ba62597e59d7c994fdf8fda
--- /dev/null
+++ b/data/resources/ui/components-loading-listbox-row.ui
@@ -0,0 +1,41 @@
+
+
+
+ False
+ False
+
+
+ crossfade
+
+
+ True
+ center
+ center
+
+
+
+
+ vertical
+ 12
+ 12
+ 12
+ 12
+ 12
+
+
+ True
+ word-char
+
+
+
+
+ Retry
+ center
+
+
+
+
+
+
+
+
diff --git a/data/resources/ui/user-entry-row.ui b/data/resources/ui/user-entry-row.ui
index 9785ad23f0df1a61cd194c85a1c425803b9fe805..68241553bb386f401fd0e7537ab47d2d0c0e0ede 100644
--- a/data/resources/ui/user-entry-row.ui
+++ b/data/resources/ui/user-entry-row.ui
@@ -49,14 +49,26 @@
+
+
+ applications-system-symbolic
+ user-entry-row.open-account-settings
+ center
+ center
+
+
+
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2086295fc58b479cb9a2873ba660d26694a4c9b4..902998b2d049e813f38e689769f28dd24a074756 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,7 +6,12 @@ data/org.gnome.FractalNext.metainfo.xml.in.in
# UI files
data/resources/ui/add_account.ui
+data/resources/ui/account-settings.ui
+data/resources/ui/account-settings-device-row.ui
+data/resources/ui/account-settings-devices-page.ui
+data/resources/ui/components-auth-dialog.ui
data/resources/ui/components-avatar.ui
+data/resources/ui/components-loading-listbox-row.ui
data/resources/ui/avatar-with-selection.ui
data/resources/ui/content-divider-row.ui
data/resources/ui/content-item-row-menu.ui
@@ -36,10 +41,12 @@ data/resources/ui/window.ui
# Rust files
src/application.rs
+src/components/auth_dialog.rs
src/components/avatar.rs
src/components/context_menu_bin.rs
src/components/custom_entry.rs
src/components/label_with_widgets.rs
+src/components/loading_listbox_row.rs
src/components/in_app_notification.rs
src/components/mod.rs
src/components/spinner_button.rs
@@ -48,6 +55,12 @@ src/error.rs
src/login.rs
src/main.rs
src/secret.rs
+src/session/account_settings/devices_page/device.rs
+src/session/account_settings/devices_page/device_item.rs
+src/session/account_settings/devices_page/device_list.rs
+src/session/account_settings/devices_page/device_row.rs
+src/session/account_settings/devices_page/mod.rs
+src/session/account_settings/mod.rs
src/session/categories/category.rs
src/session/categories/category_type.rs
src/session/categories/mod.rs
diff --git a/src/components/auth_dialog.rs b/src/components/auth_dialog.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4206786282ab3fda73d688f428ab0360ebae029c
--- /dev/null
+++ b/src/components/auth_dialog.rs
@@ -0,0 +1,383 @@
+use adw::subclass::prelude::*;
+use gtk::gdk;
+use gtk::gio::prelude::*;
+use gtk::glib::clone;
+use gtk::prelude::*;
+use gtk::subclass::prelude::*;
+use gtk::{glib, CompositeTemplate};
+use std::cell::Cell;
+use std::future::Future;
+
+use crate::session::Session;
+use crate::session::UserExt;
+use crate::RUNTIME;
+
+use matrix_sdk::{
+ ruma::api::{
+ client::{
+ error::ErrorBody,
+ r0::uiaa::{
+ AuthData as MatrixAuthData,
+ FallbackAcknowledgement as MatrixFallbackAcknowledgement,
+ Password as MatrixPassword, UiaaInfo, UiaaResponse, UserIdentifier,
+ },
+ },
+ error::{FromHttpResponseError, ServerError},
+ OutgoingRequest,
+ },
+ ruma::assign,
+ HttpError,
+ HttpError::UiaaError,
+ HttpResult,
+};
+
+use std::fmt::Debug;
+
+pub struct Password {
+ pub user_id: String,
+ pub password: String,
+ pub session: Option,
+}
+
+pub struct FallbackAcknowledgement {
+ pub session: String,
+}
+
+// FIXME: we can't move the ruma AuthData between threads
+// because it's not owned data and doesn't live long enough.
+// Therefore we have our own AuthData.
+pub enum AuthData {
+ Password(Password),
+ FallbackAcknowledgement(FallbackAcknowledgement),
+}
+
+impl AuthData {
+ pub fn as_matrix_auth_data(&self) -> MatrixAuthData {
+ match self {
+ AuthData::Password(Password {
+ user_id,
+ password,
+ session,
+ }) => MatrixAuthData::Password(assign!(MatrixPassword::new(
+ UserIdentifier::MatrixId(&user_id),
+ &password,
+ ), { session: session.as_deref() })),
+ AuthData::FallbackAcknowledgement(FallbackAcknowledgement { session }) => {
+ MatrixAuthData::FallbackAcknowledgement(MatrixFallbackAcknowledgement::new(
+ &session,
+ ))
+ }
+ }
+ }
+}
+
+mod imp {
+ use super::*;
+ use glib::subclass::{InitializingObject, Signal};
+ use glib::SignalHandlerId;
+ use once_cell::sync::Lazy;
+ use std::cell::RefCell;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/FractalNext/components-auth-dialog.ui")]
+ pub struct AuthDialog {
+ pub session: RefCell