-
Notifications
You must be signed in to change notification settings - Fork 269
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
refactor(timeline): fuse edit_by_id
(resp redact_by_id
) into their ID-less counterparts
#4100
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4100 +/- ##
==========================================
- Coverage 84.76% 84.73% -0.03%
==========================================
Files 269 269
Lines 28848 28813 -35
==========================================
- Hits 24453 24415 -38
- Misses 4395 4398 +3 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the work on this! I have a few questions, especially about how we return this unique id.
I'll also try to build a version and test it against Android to see how it works.
/// represented by the item. | ||
#[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
#[cfg_attr(feature = "uniffi", derive(uniffi::Object))] | ||
pub struct TimelineUniqueId(pub(crate) String); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is created as an Object
instead of Record
so it can't be instantiated from the clients? I'd rather have a plain type instead of passing a pointer as it would be better for debugging purposes though 🫤 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose Record
means the inner string would be available to all, and the intent here is that the identifier is an opaque thingy. Would you like a "gimme a debug string" helper for debugging purposes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that would be enough, yes. Without an event id or transaction id it could be a bit difficult to keep track of an item if it changed while debugging, with the event id back this should be better and having a way to manually check the unique id would be perfect. Thanks!
match event.handle() { | ||
let items = &self.controller.items().await; | ||
let Some((_item_pos, item)) = rfind_event_by_uid(&items, unique_id) else { | ||
warn!("couldn't find timeline item identified with id"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having a bool
indicating whether the event was redacted or not seemed weird when I was looking at this code, same as when editing: if I ask theSDK to do an operation and it can't, I'd expect the issue to be raised as an error instead of a false
value, but maybe that's because I'm used to the java way of catching exceptions for unexpected behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not closed to changing the API here; I'd rather have it be a different PR though, ideally with an issue explaining the motivation.
Self { | ||
is_local: value.is_local_echo(), | ||
is_remote: !value.is_local_echo(), | ||
event_or_transaction_id: value.identifier().into(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we get a unique id without this? Did I miss where we return it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see, it's here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But to create a ComposerDraftType
we'll still need a way to get the related event id, at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added it back in a fixup commit autosquashed.
812e128
to
5f59ead
Compare
Some things I found while trying to integrate the changes:
I'm still trying to adapt our current code to the new APIs, I'll post any other issues I run into. |
@jmartinesp Thanks for the feedback. Latest commits should address most of your comments, please let me know if anything's missing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took me 2 hours to get the app building again but I finally did it. You can see what it took here: element-hq/element-x-ios@develop...stefan/TimelineUniqueId
I found problems in:
- methods for retring using txnids (room.tryResend, room.ignoreDeviceTrustAndResend, room.withdrawVerificationAndResend)
- message drafts
- voice message audio players: we need to keep their states in between timeline resets/updates. The IDs need to be stable.
- sending read receipts
- editing polls
- ending polls
- selecting poll options
- copying permalinks (tell if it's been sent, use its event id)
- replying
- pinning, unpinning message and viewing them in the timeline. Checking if a particular timeline item is pinned.
- reporting content
- composer states (editing, replying)
- focusing a timeline on a particular event id
- fetching event details through
fetchDetailsForEvent(eventId)
While some of them can probably be rewritten some other way even now I don't think this PR considers all of them.
I'm all up for improving APIs but introducing so many changes at the same time is a sure recipe for regressions.
@stefanceriu Thanks for trying it out. I'm not sure how I'm supposed to guess what you need based on skimming the list of "problems", since they don't mention any particular APIs or precise issues, except for the voice message item? (The first bullet item should've been addressed, considering I've added back event_id/transaction_id in the EventTimelineItem.) |
event_id: Option<String>, | ||
/// A transaction id, for events waiting in the send queue. | ||
/// | ||
/// Note: not set for remote-echoes. | ||
transaction_id: Option<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds a lot like EventOrTransactionId
to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're already losing much static typing safety by using Strings everywhere, maybe we can afford two types to help distinguish one from the other 🥲 Also, one can't use an EventOrTransactionId
in any API, it's either an event id OR a transaction id, so using any of those APIs would require passing the event|transaction id and pray your best luck/favorite god that it doesn't fail because it wasn't the expected type.
7ba240c
to
cceea94
Compare
Can we perhaps split this PR out into smaller chunks, that would perhaps make it easier to see what introduces certain regressions. |
@bnjbvr Oh I'm sorry, I just assumed you know how these things are used. I would suggest you introduce that |
We've discussed about it offline, and we think using the
So the plan is:
|
cceea94
to
998ddcf
Compare
TimelineUniqueId
for both edit
and redact
edit_by_id
(resp redact_by_id
) into their ID-less counterparts
ac9b551
to
0490df2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the other 2 PRs now in place this is looking very nice! 👏 (bar those inline comment of mine).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love it! 👏
Changelog: `Timeline::redact_by_id` has been fused into `Timeline::redact`, which now takes a `TimelineEventItemId` as an identifier of the item (local or remote) to redact.
In particular, this means that trying to edit an event that's not present anymore in a timeline (e.g. after a timeline reset) will fail, while it worked before. Changelog: `Timeline::edit_by_id` has been fused into `Timeline::edit`, which now takes a `TimelineEventItemId` as the identifier for the local or remote item to edit. This also means that editing an event that's not in the timeline anymore will now fail. Callers should manually create the edit event's content, and then send it via the send queue; which the FFI function `Room::edit` does.
…ouldn't be found in the timeline This maintains functionality we had prior to the previous commit: if an event's missing from the timeline (e.g. timeline's been cleared after a gappy sync response), then still allow editing it.
…al echo disappeared I think this can't happen, but the send queue can return an error if a local echo identified by a transaction id doesn't exist anymore in the database. The only reason the latter could happen is because the local echo has been sent, in which case an update to the timeline would be dispatched, and the timeline item would have morphed into a remote echo in the meantime. So it's really rare that this would happen, and the `Timeline::redact()` method doesn't have to return a boolean to indicate success in general. Changelog: `Timeline::redact()` doesn't return a boolean; previously, it would only return false if the internal state was invalid, so a new error `RedactError::InvalidLocalEchoState` has been introduced to represent that.
See previous commit for explanations. This makes for a simpler API anyways. Changelog: `Timeline::edit` doesn't return a bool anymore to indicate it couldn't manage the edit in some cases, but will return errors indicating what the cause of the error is.
1ded097
to
5646e1c
Compare
This PR sits on top of #4111 and #4127, and allows us to get rid of the
edit_by_id
/redact_by_id
variants.I've added changelog entries \o/
Fixes #4093.