Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide message text input bar if the user cannot send messages in a room #253

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,4 @@ collapsible_else_if = "allow"
too_many_arguments = "allow"
blocks_in_conditions = "allow"
used_underscore_binding = "allow"
module_name_repetitions = "allow"
module_name_repetitions = "allow"
41 changes: 40 additions & 1 deletion src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ live_design! {
COLOR_PROFILE_CIRCLE = #xfff8ee
TYPING_NOTICE_ANIMATION_DURATION = 0.3

CAN_NOT_SEND_NOTICE = "You don't have permission to post to this room."

FillerY = <View> {width: Fill}

FillerX = <View> {height: Fill}
Expand Down Expand Up @@ -810,7 +812,7 @@ live_design! {
location_preview = <LocationPreview> { }

// Below that, display a view that holds the message input bar and send button.
<View> {
input_bar = <View> {
width: Fill, height: Fit
flow: Right,
align: {y: 0.5},
Expand Down Expand Up @@ -917,6 +919,24 @@ live_design! {
icon_walk: {width: 18.0, height: Fit},
}
}
can_not_send_message_notice = <View> {
visible: false
show_bg: true
draw_bg: {
color: (COLOR_SECONDARY)
}
padding: {left: 75}
align: {y: 0.3}
width: Fill, height: 37.5

text = <Label> {
draw_text: {
color: (COLOR_TEXT)
text_style: <THEME_FONT_ITALIC>{font_size: 12.2}
}
text: (CAN_NOT_SEND_NOTICE)
}
}
}

// The top space should be displayed on top of the timeline
Expand Down Expand Up @@ -1714,6 +1734,15 @@ impl RoomScreen {
// if the list of typing users gets updated many times in a row.
typing_users = users;
}

TimelineUpdate::CanUserSendMessage(can_user_send_message) => {
let input_bar = self.view.view(id!(input_bar));
let can_not_send_message_notice = self.view.view(id!(can_not_send_message_notice));

//Set the visibility of the corresponding component for both cases.
input_bar.set_visible(can_user_send_message);
can_not_send_message_notice.set_visible(!can_user_send_message);
}
aaravlu marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -1837,6 +1866,8 @@ impl RoomScreen {
/// Invoke this when this timeline is being shown,
/// e.g., when the user navigates to this timeline.
fn show_timeline(&mut self, cx: &mut Cx) {
self.check_can_user_send_message();

let room_id = self.room_id.clone()
.expect("BUG: Timeline::show_timeline(): no room_id was set.");
// just an optional sanity check
Expand Down Expand Up @@ -2101,6 +2132,13 @@ impl RoomScreen {
}
tl.last_scrolled_index = first_index;
}

/// Send request as `MatrixRequest` to check post permission.
fn check_can_user_send_message(&self) {
if let Some(room_id) = self.room_id.clone() {
submit_async_request(MatrixRequest::CheckCanUserSendMessage { room_id })
aaravlu marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

impl RoomScreenRef {
Expand Down Expand Up @@ -2181,6 +2219,7 @@ pub enum TimelineUpdate {
/// The list of users (their displayable name) who are currently typing in this room.
users: Vec<String>,
},
CanUserSendMessage (bool)
}

/// The global set of all timeline states, one entry per room.
Expand Down
69 changes: 51 additions & 18 deletions src/sliding_sync.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::{Result, bail};
use anyhow::{bail, Result};
use clap::Parser;
aaravlu marked this conversation as resolved.
Show resolved Hide resolved
use eyeball::Subscriber;
use eyeball_im::VectorDiff;
Expand Down Expand Up @@ -102,7 +102,7 @@ async fn build_client(
let homeserver_url = cli.homeserver.as_deref()
.unwrap_or("https://matrix-client.matrix.org/");
// .unwrap_or("https://matrix.org/");

let mut builder = Client::builder()
.server_name_or_homeserver_url(homeserver_url)
// Use a sqlite database to persist the client's encryption setup.
Expand Down Expand Up @@ -180,7 +180,7 @@ async fn login(
bail!("Failed to login as {}: {login_result:?}", cli.username);
}
}

LoginRequest::LoginBySSOSuccess(client, client_session) => {
if let Err(e) = persistent_state::save_session(&client, client_session).await {
error!("Failed to save session state to storage: {e:?}");
Expand Down Expand Up @@ -226,7 +226,7 @@ async fn populate_login_types(
}

/// Which direction to paginate in.
///
///
/// * `Forwards` will retrieve later events (towards the end of the timeline),
/// which only works if the timeline is *focused* on a specific event.
/// * `Backwards`: the more typical choice, in which earlier events are retrieved
Expand Down Expand Up @@ -357,6 +357,10 @@ pub enum MatrixRequest {
FullyReadReceipt{
room_id: OwnedRoomId,
event_id: OwnedEventId,
},
/// Sends user permission's checking once user entered room.
CheckCanUserSendMessage{
aaravlu marked this conversation as resolved.
Show resolved Hide resolved
room_id: OwnedRoomId,
}
}

Expand All @@ -374,7 +378,7 @@ pub enum LoginRequest{
LoginBySSOSuccess(Client, ClientSessionPersisted),
LoginByCli,
HomeserverLoginTypesQuery(String),

}
/// Information needed to log in to a Matrix homeserver.
pub struct LoginByPassword {
Expand Down Expand Up @@ -774,7 +778,32 @@ async fn async_worker(
Err(_e) => error!("Failed to send fully read receipt to room {room_id}, event {event_id}; error: {_e:?}"),
}
});
}
},

MatrixRequest::CheckCanUserSendMessage { room_id } => {
let (timeline, sender) = {
let all_room_info = ALL_ROOM_INFO.lock().unwrap();
let Some(room_info) = all_room_info.get(&room_id) else {
log!("BUG: room info not found for fetch members request {room_id}");
continue;
};

(room_info.timeline.clone(), room_info.timeline_update_sender.clone())
};

let Some(client) = CLIENT.get() else { continue };
let Some(user_id) = client.user_id() else { continue };

aaravlu marked this conversation as resolved.
Show resolved Hide resolved
let _check_can_user_send_message_task = Handle::current().spawn(async move {
let room = timeline.room();

let can_user_send_message = room.can_user_send_message(user_id, matrix_sdk::ruma::events::MessageLikeEventType::Message).await.unwrap_or(false);

aaravlu marked this conversation as resolved.
Show resolved Hide resolved
if let Err(e) = sender.send(TimelineUpdate::CanUserSendMessage(can_user_send_message)) {
error!("Failed to send the result of if user can send message: {e}")
}
});
}
}
}

Expand All @@ -798,7 +827,7 @@ pub fn start_matrix_tokio() -> Result<()> {
// Create a channel to be used between UI thread(s) and the async worker thread.
let (sender, receiver) = tokio::sync::mpsc::unbounded_channel::<MatrixRequest>();
REQUEST_SENDER.set(sender).expect("BUG: REQUEST_SENDER already set!");

let (login_sender, login_receiver) = tokio::sync::mpsc::channel(1);
// Start a high-level async task that will start and monitor all other tasks.
let _monitor = rt.spawn(async move {
Expand Down Expand Up @@ -949,7 +978,7 @@ pub fn is_user_ignored(user_id: &UserId) -> bool {


/// Returns three channel endpoints related to the timeline for the given room.
///
///
/// 1. A timeline update sender.
/// 2. The timeline update receiver, which is a singleton, and can only be taken once.
/// 3. A `tokio::watch` sender that can be used to send requests to the timeline subscriber handler.
Expand Down Expand Up @@ -1706,7 +1735,7 @@ async fn timeline_subscriber_handler(
} else {
found_target_event_id = find_target_event(&mut target_event_id, std::iter::once(&value));
}

clear_cache = true;
timeline_items.push_front(value);
reobtain_latest_event |= latest_event.is_none();
Expand Down Expand Up @@ -1779,7 +1808,7 @@ async fn timeline_subscriber_handler(
if index <= *i {
*i = i.saturating_sub(1);
}
}
}
timeline_items.remove(index);
if LOG_TIMELINE_DIFFS { log!("timeline_subscriber: room {room_id} diff Remove at {index}. Changes: {index_of_first_change}..{index_of_last_change}"); }
reobtain_latest_event = true;
Expand All @@ -1803,16 +1832,16 @@ async fn timeline_subscriber_handler(
}
}
}

if num_updates > 0 {
let new_latest_event = if reobtain_latest_event {
timeline.latest_event().await
} else {
None
};

let changed_indices = index_of_first_change..index_of_last_change;

if LOG_TIMELINE_DIFFS {
log!("timeline_subscriber: applied {num_updates} updates for room {room_id}, timeline now has {} items. is_append? {is_append}, clear_cache? {clear_cache}. Changes: {changed_indices:?}.", timeline_items.len());
}
Expand All @@ -1839,7 +1868,7 @@ async fn timeline_subscriber_handler(

// Send a Makepad-level signal to update this room's timeline UI view.
SignalToUI::set_ui_signal();

// Update the latest event for this room.
if let Some(new_latest) = new_latest_event {
if latest_event.as_ref().map_or(true, |ev| ev.timestamp() < new_latest.timestamp()) {
Expand Down Expand Up @@ -1893,6 +1922,10 @@ fn update_latest_event(
AnyOtherFullStateEventContent::RoomAvatar(_avatar_event) => {
room_avatar_changed = true;
}
AnyOtherFullStateEventContent::RoomPowerLevels(_power_level_event) => {
let id = room_id.clone();
submit_async_request(MatrixRequest::CheckCanUserSendMessage { room_id: id })
}
aaravlu marked this conversation as resolved.
Show resolved Hide resolved
_ => { }
}
}
Expand Down Expand Up @@ -1959,10 +1992,10 @@ async fn spawn_sso_server(
..Default::default()
};
Handle::current().spawn(async move {
let Ok((client, client_session)) = build_client(&cli, app_data_dir()).await else {
Cx::post_action(LoginAction::LoginFailure("Failed to establish client".to_string()));
return;
};
let Ok((client, client_session)) = build_client(&cli, app_data_dir()).await else {
Cx::post_action(LoginAction::LoginFailure("Failed to establish client".to_string()));
return;
};
let mut is_logged_in = false;
match client
.matrix_auth()
Expand Down
Loading