matrix_sdk_ffi/
room_member.rs

1use matrix_sdk::room::{RoomMember as SdkRoomMember, RoomMemberRole};
2use ruma::{events::room::power_levels::UserPowerLevel, UserId};
3
4use crate::error::{ClientError, NotYetImplemented};
5
6#[derive(Clone, uniffi::Enum)]
7pub enum MembershipState {
8    /// The user is banned.
9    Ban,
10
11    /// The user has been invited.
12    Invite,
13
14    /// The user has joined.
15    Join,
16
17    /// The user has requested to join.
18    Knock,
19
20    /// The user has left.
21    Leave,
22
23    /// A custom membership state value.
24    Custom { value: String },
25}
26
27impl TryFrom<matrix_sdk::ruma::events::room::member::MembershipState> for MembershipState {
28    type Error = NotYetImplemented;
29
30    fn try_from(
31        m: matrix_sdk::ruma::events::room::member::MembershipState,
32    ) -> Result<Self, Self::Error> {
33        match m {
34            matrix_sdk::ruma::events::room::member::MembershipState::Ban => {
35                Ok(MembershipState::Ban)
36            }
37            matrix_sdk::ruma::events::room::member::MembershipState::Invite => {
38                Ok(MembershipState::Invite)
39            }
40            matrix_sdk::ruma::events::room::member::MembershipState::Join => {
41                Ok(MembershipState::Join)
42            }
43            matrix_sdk::ruma::events::room::member::MembershipState::Knock => {
44                Ok(MembershipState::Knock)
45            }
46            matrix_sdk::ruma::events::room::member::MembershipState::Leave => {
47                Ok(MembershipState::Leave)
48            }
49            matrix_sdk::ruma::events::room::member::MembershipState::_Custom(_) => {
50                Ok(MembershipState::Custom { value: m.to_string() })
51            }
52            _ => {
53                tracing::warn!("Other membership state change not yet implemented");
54                Err(NotYetImplemented)
55            }
56        }
57    }
58}
59
60/// Get the suggested role for the given power level.
61///
62/// Returns an error if the value of the power level is out of range for numbers
63/// accepted in canonical JSON.
64#[matrix_sdk_ffi_macros::export]
65pub fn suggested_role_for_power_level(
66    power_level: PowerLevel,
67) -> Result<RoomMemberRole, ClientError> {
68    // It's not possible to expose the constructor on the Enum through Uniffi ☹️
69    Ok(RoomMemberRole::suggested_role_for_power_level(power_level.try_into()?))
70}
71
72/// Get the suggested power level for the given role.
73///
74/// Returns an error if the value of the power level is unsupported.
75#[matrix_sdk_ffi_macros::export]
76pub fn suggested_power_level_for_role(role: RoomMemberRole) -> Result<PowerLevel, ClientError> {
77    // It's not possible to expose methods on an Enum through Uniffi ☹️
78    Ok(role.suggested_power_level().try_into()?)
79}
80
81/// Generates a `matrix.to` permalink to the given userID.
82#[matrix_sdk_ffi_macros::export]
83pub fn matrix_to_user_permalink(user_id: String) -> Result<String, ClientError> {
84    let user_id = UserId::parse(user_id)?;
85    Ok(user_id.matrix_to_uri().to_string())
86}
87
88#[derive(Clone, uniffi::Record)]
89pub struct RoomMember {
90    pub user_id: String,
91    pub display_name: Option<String>,
92    pub avatar_url: Option<String>,
93    pub membership: MembershipState,
94    pub is_name_ambiguous: bool,
95    pub power_level: PowerLevel,
96    pub is_ignored: bool,
97    pub suggested_role_for_power_level: RoomMemberRole,
98    pub membership_change_reason: Option<String>,
99}
100
101impl TryFrom<SdkRoomMember> for RoomMember {
102    type Error = NotYetImplemented;
103
104    fn try_from(m: SdkRoomMember) -> Result<Self, Self::Error> {
105        Ok(RoomMember {
106            user_id: m.user_id().to_string(),
107            display_name: m.display_name().map(|s| s.to_owned()),
108            avatar_url: m.avatar_url().map(|a| a.to_string()),
109            membership: m.membership().clone().try_into()?,
110            is_name_ambiguous: m.name_ambiguous(),
111            power_level: m.power_level().try_into()?,
112            is_ignored: m.is_ignored(),
113            suggested_role_for_power_level: m.suggested_role_for_power_level(),
114            membership_change_reason: m.event().reason().map(|s| s.to_owned()),
115        })
116    }
117}
118
119/// Contains the current user's room member info and the optional room member
120/// info of the sender of the `m.room.member` event that this info represents.
121#[derive(Clone, uniffi::Record)]
122pub struct RoomMemberWithSenderInfo {
123    /// The room member.
124    room_member: RoomMember,
125    /// The info of the sender of the event `room_member` is based on, if
126    /// available.
127    sender_info: Option<RoomMember>,
128}
129
130impl TryFrom<matrix_sdk::room::RoomMemberWithSenderInfo> for RoomMemberWithSenderInfo {
131    type Error = ClientError;
132
133    fn try_from(value: matrix_sdk::room::RoomMemberWithSenderInfo) -> Result<Self, Self::Error> {
134        Ok(Self {
135            room_member: value.room_member.try_into()?,
136            sender_info: value.sender_info.map(|member| member.try_into()).transpose()?,
137        })
138    }
139}
140
141#[derive(Clone, uniffi::Enum)]
142pub enum PowerLevel {
143    /// The user is a room creator and has infinite power level.
144    ///
145    /// This power level was introduced in room version 12.
146    Infinite,
147
148    /// The user has the given power level.
149    Value { value: i64 },
150}
151
152impl TryFrom<UserPowerLevel> for PowerLevel {
153    type Error = NotYetImplemented;
154
155    fn try_from(value: UserPowerLevel) -> Result<Self, Self::Error> {
156        match value {
157            UserPowerLevel::Infinite => Ok(Self::Infinite),
158            UserPowerLevel::Int(value) => Ok(Self::Value { value: value.into() }),
159            _ => Err(NotYetImplemented),
160        }
161    }
162}
163
164impl TryFrom<PowerLevel> for UserPowerLevel {
165    type Error = ClientError;
166
167    fn try_from(value: PowerLevel) -> Result<Self, Self::Error> {
168        Ok(match value {
169            PowerLevel::Infinite => Self::Infinite,
170            PowerLevel::Value { value } => {
171                Self::Int(value.try_into().map_err(|err| ClientError::Generic {
172                    msg: "Power level is out of range".to_owned(),
173                    details: Some(format!("{err:?}")),
174                })?)
175            }
176        })
177    }
178}