Skip to content

Commit 4e9ddef

Browse files
committed
concise summary small events messages
1 parent e0d8065 commit 4e9ddef

File tree

1 file changed

+147
-160
lines changed

1 file changed

+147
-160
lines changed

src/home/room_screen.rs

Lines changed: 147 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! A room screen is the UI page that displays a single Room's timeline of events/messages
22
//! along with a message input bar at the bottom.
33
4-
use std::{borrow::Cow, collections::BTreeMap, ops::{DerefMut, Range}, sync::{Arc, Mutex}, time::SystemTime};
4+
use std::{borrow::Cow, collections::{BTreeMap, HashSet}, ops::{DerefMut, Range}, sync::{Arc, Mutex}, time::SystemTime};
55

66
use bytesize::ByteSize;
77
use imbl::Vector;
@@ -15,7 +15,7 @@ use matrix_sdk::{room::RoomMember, ruma::{
1515
sticker::StickerEventContent, Mentions}, matrix_uri::MatrixId, uint, EventId, MatrixToUri, MatrixUri, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomId
1616
}, OwnedServerName};
1717
use matrix_sdk_ui::timeline::{
18-
self, EventTimelineItem, InReplyToDetails, MemberProfileChange, RepliedToInfo, RoomMembershipChange, TimelineDetails, TimelineEventItemId, TimelineItem, TimelineItemContent, TimelineItemKind, VirtualTimelineItem
18+
self, EventTimelineItem, InReplyToDetails, MemberProfileChange, MembershipChange, RepliedToInfo, RoomMembershipChange, TimelineDetails, TimelineEventItemId, TimelineItem, TimelineItemContent, TimelineItemKind, VirtualTimelineItem
1919
};
2020
use robius_location::Coordinates;
2121

@@ -1339,23 +1339,9 @@ impl Widget for RoomScreen {
13391339
};
13401340
let room_id = &tl_state.room_id;
13411341
let tl_items = &tl_state.items;
1342-
13431342
let grouped_items = group_small_state_events(tl_items);
13441343

1345-
// for (_, group) in grouped_items.iter().enumerate() {
1346-
// match group {
1347-
// GroupedTimelineItem::GroupedSmallEvents(events) => {
1348-
// let summary = summarize_small_events(&events);
1349-
// log!("Summary: {:?}", summary);
1350-
// }
1351-
// _ => {}
1352-
// }
1353-
// }
1354-
1355-
// Set the portal list's range based on the number of timeline items.
1356-
// let last_item_id = tl_items.len();
13571344
let last_item_id = grouped_items.len();
1358-
13591345
let list = list_ref.deref_mut();
13601346
list.set_item_range(cx, 0, last_item_id);
13611347

@@ -1380,32 +1366,70 @@ impl Widget for RoomScreen {
13801366
TimelineItemContent::Message(message) => {
13811367
let prev_event = tl_idx.and_then(|i| i.checked_sub(1)).and_then(|i| tl_items.get(i));
13821368
populate_message_view(
1383-
cx, list, item_id, room_id, event_tl_item,
1384-
MessageOrSticker::Message(message), prev_event,
1385-
&mut tl_state.media_cache, &tl_state.user_power,
1386-
item_drawn_status, room_screen_widget_uid,
1369+
cx,
1370+
list,
1371+
item_id,
1372+
room_id,
1373+
event_tl_item,
1374+
MessageOrSticker::Message(message),
1375+
prev_event,
1376+
&mut tl_state.media_cache,
1377+
&tl_state.user_power,
1378+
item_drawn_status,
1379+
room_screen_widget_uid,
13871380
)
13881381
}
13891382
TimelineItemContent::Sticker(sticker) => {
13901383
let prev_event = tl_idx.and_then(|i| i.checked_sub(1)).and_then(|i| tl_items.get(i));
13911384
populate_message_view(
1392-
cx, list, item_id, room_id, event_tl_item,
1393-
MessageOrSticker::Sticker(sticker.content()), prev_event,
1394-
&mut tl_state.media_cache, &tl_state.user_power,
1395-
item_drawn_status, room_screen_widget_uid,
1385+
cx,
1386+
list,
1387+
item_id,
1388+
room_id,
1389+
event_tl_item,
1390+
MessageOrSticker::Sticker(sticker.content()),
1391+
prev_event,
1392+
&mut tl_state.media_cache,
1393+
&tl_state.user_power,
1394+
item_drawn_status,
1395+
room_screen_widget_uid,
13961396
)
13971397
}
13981398
TimelineItemContent::RedactedMessage => populate_small_state_event(
1399-
cx, list, item_id, room_id, event_tl_item, &RedactedMessageEventMarker, item_drawn_status,
1399+
cx,
1400+
list,
1401+
item_id,
1402+
room_id,
1403+
event_tl_item,
1404+
&RedactedMessageEventMarker,
1405+
item_drawn_status,
14001406
),
14011407
TimelineItemContent::MembershipChange(membership_change) => populate_small_state_event(
1402-
cx, list, item_id, room_id, event_tl_item, membership_change, item_drawn_status,
1408+
cx,
1409+
list,
1410+
item_id,
1411+
room_id,
1412+
event_tl_item,
1413+
membership_change,
1414+
item_drawn_status,
14031415
),
14041416
TimelineItemContent::ProfileChange(profile_change) => populate_small_state_event(
1405-
cx, list, item_id, room_id, event_tl_item, profile_change, item_drawn_status,
1417+
cx,
1418+
list,
1419+
item_id,
1420+
room_id,
1421+
event_tl_item,
1422+
profile_change,
1423+
item_drawn_status,
14061424
),
14071425
TimelineItemContent::OtherState(other) => populate_small_state_event(
1408-
cx, list, item_id, room_id, event_tl_item, other, item_drawn_status,
1426+
cx,
1427+
list,
1428+
item_id,
1429+
room_id,
1430+
event_tl_item,
1431+
other,
1432+
item_drawn_status,
14091433
),
14101434
unhandled => {
14111435
let item = list.item(cx, item_id, live_id!(SmallStateEvent));
@@ -1435,7 +1459,6 @@ impl Widget for RoomScreen {
14351459
tl_state.profile_drawn_since_last_update.insert(tl_idx..tl_idx + 1);
14361460
}
14371461
}
1438-
14391462
item.draw_all(cx, &mut Scope::empty());
14401463
}
14411464
GroupedTimelineItem::GroupedSmallEvents(events) => {
@@ -1445,126 +1468,6 @@ impl Widget for RoomScreen {
14451468
item.draw_all(cx, &mut Scope::empty());
14461469
}
14471470
};
1448-
1449-
// let item = {
1450-
// let tl_idx = item_id;
1451-
// let Some(timeline_item) = tl_items.get(tl_idx) else {
1452-
// // This shouldn't happen (unless the timeline gets corrupted or some other weird error),
1453-
// // but we can always safely fill the item with an empty widget that takes up no space.
1454-
// list.item(cx, item_id, live_id!(Empty));
1455-
// continue;
1456-
// };
1457-
1458-
// // Determine whether this item's content and profile have been drawn since the last update.
1459-
// // Pass this state to each of the `populate_*` functions so they can attempt to re-use
1460-
// // an item in the timeline's portallist that was previously populated, if one exists.
1461-
// let item_drawn_status = ItemDrawnStatus {
1462-
// content_drawn: tl_state.content_drawn_since_last_update.contains(&tl_idx),
1463-
// profile_drawn: tl_state.profile_drawn_since_last_update.contains(&tl_idx),
1464-
// };
1465-
// let (item, item_new_draw_status) = match timeline_item.kind() {
1466-
// TimelineItemKind::Event(event_tl_item) => match event_tl_item.content() {
1467-
// TimelineItemContent::Message(message) => {
1468-
// let prev_event = tl_idx.checked_sub(1).and_then(|i| tl_items.get(i));
1469-
// populate_message_view(
1470-
// cx,
1471-
// list,
1472-
// item_id,
1473-
// room_id,
1474-
// event_tl_item,
1475-
// MessageOrSticker::Message(message),
1476-
// prev_event,
1477-
// &mut tl_state.media_cache,
1478-
// &tl_state.user_power,
1479-
// item_drawn_status,
1480-
// room_screen_widget_uid,
1481-
// )
1482-
// }
1483-
// TimelineItemContent::Sticker(sticker) => {
1484-
// let prev_event = tl_idx.checked_sub(1).and_then(|i| tl_items.get(i));
1485-
// populate_message_view(
1486-
// cx,
1487-
// list,
1488-
// item_id,
1489-
// room_id,
1490-
// event_tl_item,
1491-
// MessageOrSticker::Sticker(sticker.content()),
1492-
// prev_event,
1493-
// &mut tl_state.media_cache,
1494-
// &tl_state.user_power,
1495-
// item_drawn_status,
1496-
// room_screen_widget_uid,
1497-
// )
1498-
// }
1499-
// TimelineItemContent::RedactedMessage => populate_small_state_event(
1500-
// cx,
1501-
// list,
1502-
// item_id,
1503-
// room_id,
1504-
// event_tl_item,
1505-
// &RedactedMessageEventMarker,
1506-
// item_drawn_status,
1507-
// ),
1508-
// TimelineItemContent::MembershipChange(membership_change) => {
1509-
// populate_small_state_event(
1510-
// cx,
1511-
// list,
1512-
// item_id,
1513-
// room_id,
1514-
// event_tl_item,
1515-
// membership_change,
1516-
// item_drawn_status,
1517-
// )
1518-
// },
1519-
// TimelineItemContent::ProfileChange(profile_change) => populate_small_state_event(
1520-
// cx,
1521-
// list,
1522-
// item_id,
1523-
// room_id,
1524-
// event_tl_item,
1525-
// profile_change,
1526-
// item_drawn_status,
1527-
// ),
1528-
// TimelineItemContent::OtherState(other) => populate_small_state_event(
1529-
// cx,
1530-
// list,
1531-
// item_id,
1532-
// room_id,
1533-
// event_tl_item,
1534-
// other,
1535-
// item_drawn_status,
1536-
// ),
1537-
// unhandled => {
1538-
// let item = list.item(cx, item_id, live_id!(SmallStateEvent));
1539-
// item.label(id!(content)).set_text(cx, &format!("[Unsupported] {:?}", unhandled));
1540-
// (item, ItemDrawnStatus::both_drawn())
1541-
// }
1542-
// }
1543-
// TimelineItemKind::Virtual(VirtualTimelineItem::DateDivider(millis)) => {
1544-
// let item = list.item(cx, item_id, live_id!(DateDivider));
1545-
// let text = unix_time_millis_to_datetime(millis)
1546-
// // format the time as a shortened date (Sat, Sept 5, 2021)
1547-
// .map(|dt| format!("{}", dt.date_naive().format("%a %b %-d, %Y")))
1548-
// .unwrap_or_else(|| format!("{:?}", millis));
1549-
// item.label(id!(date)).set_text(cx, &text);
1550-
// (item, ItemDrawnStatus::both_drawn())
1551-
// }
1552-
// TimelineItemKind::Virtual(VirtualTimelineItem::ReadMarker) => {
1553-
// let item = list.item(cx, item_id, live_id!(ReadMarker));
1554-
// (item, ItemDrawnStatus::both_drawn())
1555-
// }
1556-
// };
1557-
1558-
// // Now that we've drawn the item, add its index to the set of drawn items.
1559-
// if item_new_draw_status.content_drawn {
1560-
// tl_state.content_drawn_since_last_update.insert(tl_idx .. tl_idx + 1);
1561-
// }
1562-
// if item_new_draw_status.profile_drawn {
1563-
// tl_state.profile_drawn_since_last_update.insert(tl_idx .. tl_idx + 1);
1564-
// }
1565-
// item
1566-
// };
1567-
// item.draw_all(cx, &mut Scope::empty());
15681471
}
15691472
}
15701473
DrawStep::done()
@@ -4256,33 +4159,117 @@ fn group_small_state_events(
42564159
}
42574160

42584161
fn summarize_small_events(events: &[Arc<TimelineItem>]) -> String {
4259-
let mut parts = vec![];
4162+
let mut joined = HashSet::new();
4163+
let mut left = HashSet::new();
4164+
let mut joined_and_left = HashSet::new();
4165+
4166+
let mut profile_displayname_updated = HashSet::new();
4167+
let mut profile_avatar_updated = HashSet::new();
4168+
4169+
let mut redacted = 0;
4170+
let mut state_changed = 0;
4171+
42604172
for item in events {
42614173
if let TimelineItemKind::Event(e) = item.kind() {
42624174
match e.content() {
42634175
TimelineItemContent::MembershipChange(change) => {
42644176
let username = change.display_name().unwrap_or("someone".to_owned());
4265-
let Some(preview) = text_preview_of_room_membership_change(change) else {
4266-
parts.push("membership changed".to_string());
4267-
continue;
4268-
};
4269-
parts.push(format!("{}", &preview.format_with(&username)));
4177+
let joined_flag = matches!(change.change(), Some(MembershipChange::Joined));
4178+
let left_flag = matches!(change.change(), Some(MembershipChange::Left));
4179+
4180+
if joined_flag && left_flag {
4181+
joined_and_left.insert(username);
4182+
} else if joined_flag {
4183+
if left.remove(&username) {
4184+
joined_and_left.insert(username);
4185+
} else {
4186+
joined.insert(username);
4187+
}
4188+
} else if left_flag {
4189+
if joined.remove(&username) {
4190+
joined_and_left.insert(username);
4191+
} else {
4192+
left.insert(username);
4193+
}
4194+
}
42704195
}
4271-
TimelineItemContent::ProfileChange(_change) => {
4272-
// text_preview_of_member_profile_change(change, username).format_with(username);
4273-
parts.push("profile updated".to_string());
4196+
TimelineItemContent::ProfileChange(change) => {
4197+
let username = change.user_id().localpart().to_owned();
4198+
4199+
if change.displayname_change().is_some() {
4200+
profile_displayname_updated.insert(username.clone());
4201+
}
4202+
if change.avatar_url_change().is_some() {
4203+
profile_avatar_updated.insert(username);
4204+
}
42744205
}
42754206
TimelineItemContent::RedactedMessage => {
4276-
parts.push("a message was redacted".to_string());
4207+
redacted += 1;
42774208
}
42784209
TimelineItemContent::OtherState(_) => {
4279-
parts.push("state changed".to_string());
4210+
state_changed += 1;
42804211
}
42814212
_ => {}
42824213
}
42834214
}
42844215
}
42854216

4217+
let mut profile_displayname_only = HashSet::new();
4218+
let mut profile_avatar_only = HashSet::new();
4219+
let mut profile_both = HashSet::new();
4220+
4221+
for user in profile_displayname_updated.union(&profile_avatar_updated) {
4222+
let in_display = profile_displayname_updated.contains(user);
4223+
let in_avatar = profile_avatar_updated.contains(user);
4224+
4225+
match (in_display, in_avatar) {
4226+
(true, true) => { profile_both.insert(user.clone()); }
4227+
(true, false) => { profile_displayname_only.insert(user.clone()); }
4228+
(false, true) => { profile_avatar_only.insert(user.clone()); }
4229+
_ => {}
4230+
}
4231+
}
4232+
4233+
fn summarize_users(action: &str, users: &HashSet<String>) -> Option<String> {
4234+
if users.is_empty() {
4235+
return None;
4236+
}
4237+
let mut names: Vec<_> = users.iter().collect();
4238+
names.sort();
4239+
match names.len() {
4240+
1 => Some(format!("{} {}", names[0], action)),
4241+
2 => Some(format!("{} and {} {}", names[0], names[1], action)),
4242+
n => Some(format!("{} and {} others {}", names[0], n - 1, action)),
4243+
}
4244+
}
4245+
4246+
let mut parts = vec![];
4247+
4248+
if let Some(text) = summarize_users("left", &left) {
4249+
parts.push(text);
4250+
}
4251+
if let Some(text) = summarize_users("joined", &joined) {
4252+
parts.push(text);
4253+
}
4254+
if let Some(text) = summarize_users("joined and left", &joined_and_left) {
4255+
parts.push(text);
4256+
}
4257+
if let Some(text) = summarize_users("updated their display name", &profile_displayname_only) {
4258+
parts.push(text);
4259+
}
4260+
if let Some(text) = summarize_users("updated their avatar", &profile_avatar_only) {
4261+
parts.push(text);
4262+
}
4263+
if let Some(text) = summarize_users("updated their display name and avatar", &profile_both) {
4264+
parts.push(text);
4265+
}
4266+
if redacted > 0 {
4267+
parts.push(format!("{} message(s) were redacted", redacted));
4268+
}
4269+
if state_changed > 0 {
4270+
parts.push(format!("{} state change(s)", state_changed));
4271+
}
4272+
42864273
parts.join(", ")
42874274
}
42884275

0 commit comments

Comments
 (0)