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

Refactor reactions / hand raised to use rxjs and start ordering tiles based on hand raised. #2885

Merged
merged 39 commits into from
Dec 19, 2024

Conversation

Half-Shot
Copy link
Member

@Half-Shot Half-Shot commented Dec 9, 2024

Fixes #2715
Fixes #2843

This change will adjust our code so that consumers of reactions and hand raised state use the CallViewModel as much as possible, which allows us to finally do fun stuff like order tiles by hand raised.

The changes are as follows:

  • useReactions is no more. There is now useReactionsReader which consumes reaction/HR events, and emits them in BehaviourSubjects. The sending code has been refactored into a ReactionsSenderProvider.
  • CallViewModel now consumes these two subjects, and includes a range of observables for our presentation components. The presentation components now contain very little selection logic, and focus on...presenting :)
  • Raising your hand now causes your tile to rank higher than regular video participants, but below speakers and presenters.

And, dear reviewer, I'm very sorry for the diff :(. I hope it's worth it.

@Half-Shot Half-Shot changed the title Refactor redactions / hand raised to use rxjs and start ordering tiles based on hand raised. Refactor reactions / hand raised to use rxjs and start ordering tiles based on hand raised. Dec 9, 2024
src/state/CallViewModel.ts Outdated Show resolved Hide resolved
@@ -92,19 +99,38 @@ export const ReactionsProvider = ({
clientState?.state === "valid" && clientState.supportedFeatures.reactions;
const room = rtcSession.room;
const myUserId = room.client.getUserId();
const myDeviceId = room.client.getDeviceId();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially this hook could be split up, and listening for incoming reactions could be moved somewhere else (maybe even MatrixRTCSession?).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've split the sending and receiving logic pieces into a provider and a producer-style hook, using the call view model for state.

@Half-Shot Half-Shot marked this pull request as ready for review December 16, 2024 15:33
@Half-Shot Half-Shot requested a review from a team as a code owner December 16, 2024 15:33
@Half-Shot Half-Shot requested a review from robintown December 16, 2024 15:33
Copy link
Member

@robintown robintown left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The useReactionsReader refactor looks like a good step forward. It's converted the data sources into observables which can now affect the view model, though while staying within React code.

I'm wondering if you feel up to the extra step of moving that hook's code fully out of React and into the view model. It would be a more suitable environment for creating these observables (as the class body runs once, rather than on every render), and it also gets us closer to a world in which there's a clear stratification between Model (matrix-js-sdk, LiveKit) → View Model (RxJS) → View (React), so that the View Models can become entirely external to React, with a unidirectional flow of data.

(That's something I haven't been very explicit about: that the current approach of letting a React effect create the CallViewModel is a bit of a hack, necessary because the app didn't start out with a view model architecture.)

src/reactions/useReactionsReader.ts Outdated Show resolved Hide resolved
src/reactions/useReactionsReader.ts Outdated Show resolved Hide resolved
src/reactions/useReactionsSender.tsx Outdated Show resolved Hide resolved
src/state/CallViewModel.test.ts Outdated Show resolved Hide resolved
src/state/CallViewModel.ts Outdated Show resolved Hide resolved
src/utils/test-fixtures.ts Outdated Show resolved Hide resolved
src/utils/test-viewmodel.ts Outdated Show resolved Hide resolved
@Half-Shot
Copy link
Member Author

The useReactionsReader refactor looks like a good step forward. It's converted the data sources into observables which can now affect the view model, though while staying within React code.

I'm wondering if you feel up to the extra step of moving that hook's code fully out of React and into the view model. It would be a more suitable environment for creating these observables (as the class body runs once, rather than on every render), and it also gets us closer to a world in which there's a clear stratification between Model (matrix-js-sdk, LiveKit) → View Model (RxJS) → View (React), so that the View Models can become entirely external to React, with a unidirectional flow of data.

(That's something I haven't been very explicit about: that the current approach of letting a React effect create the CallViewModel is a bit of a hack, necessary because the app didn't start out with a view model architecture.)

I've half gone with your suggestion, but I factored the reaction logic into it's own class which exports it's own observables. My rationale is the code for doing reactions handling isn't trivial, and I find it easier to parse when you have an explicit class to handle and test, which then passes it's observables into the call view model. I think we could, if you felt very strongly here, port the code it the CVM but I worry about the size of that class..

Anyway! No more react which is the main thing :)

@Half-Shot Half-Shot requested a review from robintown December 19, 2024 11:16
Copy link
Member

@robintown robintown left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay! Splitting call logic across multiple files is a good call.

Comment on lines 59 to 61
this.reactionsSubject$
.pipe(delay(REACTION_ACTIVE_TIME_MS))
.subscribe((reactions) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This subscription should be bound to some ObservableScope so that it doesn't run forever

@Half-Shot Half-Shot force-pushed the hs/reactions-viewcallmodel branch from 916009d to 20f2ca4 Compare December 19, 2024 15:48
@Half-Shot Half-Shot enabled auto-merge (squash) December 19, 2024 15:53
@Half-Shot Half-Shot merged commit abf2ecd into livekit Dec 19, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants