Refactor EventTile using the MVVM pattern - #7b (#33668)

* Normalize Leaf Adapter Pattern

* Extract simple EventTile adapters

* Move simple EventTile adapter VM ownership to EventTileViewModel

* Release listener-owning EventTile child VMs on adapter unmount

* Extract stateful EventTile adapters

* Move action bar VM ownership to EventTileViewModel

* Move reactions row VM ownership into EventTileViewModel

* Extract EventTile receipt rendering

* Extract EventTile sender identity rendering

* Add missing TSDoc on adapters
This commit is contained in:
rbondesson
2026-06-01 13:36:37 +00:00
committed by GitHub
parent ffd524d8c2
commit 531fc76726
13 changed files with 1146 additions and 684 deletions
@@ -33,6 +33,14 @@ export class E2eMessageSharedIconViewModel
this.disposables.track(() => this.teardownRoomStateListener());
}
public setClient(client: MatrixClient): void {
if (this.props.client === client) return;
this.props = { ...this.props, client };
this.setupRoomStateListener();
this.updateSnapshotFromProps();
}
public setRoomId(roomId: string): void {
if (this.props.roomId === roomId) return;
@@ -34,10 +34,22 @@ import {
import { TimelineRenderingType } from "../../../../contexts/RoomContext";
import { type Layout } from "../../../../settings/enums/Layout";
import { MessageTimestampViewModel, type MessageTimestampViewModelProps } from "./timestamp/MessageTimestampViewModel";
import {
ThreadMessagePreviewViewModel,
type ThreadMessagePreviewViewModelProps,
ThreadSummaryViewModel,
type ThreadSummaryViewModelProps,
} from "./ThreadSummaryViewModel.tsx";
import {
E2eMessageSharedIconViewModel,
type E2eMessageSharedIconViewModelProps,
} from "./E2eMessageSharedIconViewModel";
import {
ThreadListActionBarViewModel,
type ThreadListActionBarViewModelProps,
} from "../../ThreadListActionBarViewModel";
import { EventTileActionBarViewModel, type EventTileActionBarViewModelProps } from "../../EventTileActionBarViewModel";
import { ReactionsRowViewModel, type ReactionsRowViewModelProps } from "./reactions/ReactionsRowViewModel";
/** Event-level inputs for deriving the EventTile snapshot. */
export interface EventTileEventInput {
@@ -285,7 +297,12 @@ export interface EventTileRenderState {
export class EventTileViewModel extends BaseViewModel<EventTileRenderState, EventTileViewModelProps> {
private messageTimestampViewModel?: MessageTimestampViewModel;
private linkedMessageTimestampViewModel?: MessageTimestampViewModel;
private threadMessagePreviewViewModel?: ThreadMessagePreviewViewModel;
private threadSummaryViewModel?: ThreadSummaryViewModel;
private threadListActionBarViewModel?: ThreadListActionBarViewModel;
private e2eMessageSharedIconViewModel?: E2eMessageSharedIconViewModel;
private actionBarViewModel?: EventTileActionBarViewModel;
private reactionsRowViewModel?: ReactionsRowViewModel;
public constructor(props: EventTileViewModelProps) {
const initialRenderState = EventTileViewModel.createRenderState(props);
@@ -302,7 +319,12 @@ export class EventTileViewModel extends BaseViewModel<EventTileRenderState, Even
public override dispose(): void {
this.messageTimestampViewModel?.dispose();
this.linkedMessageTimestampViewModel?.dispose();
this.threadMessagePreviewViewModel?.dispose();
this.threadSummaryViewModel?.dispose();
this.threadListActionBarViewModel?.dispose();
this.e2eMessageSharedIconViewModel?.dispose();
this.actionBarViewModel?.dispose();
this.reactionsRowViewModel?.dispose();
super.dispose();
}
@@ -318,12 +340,72 @@ export class EventTileViewModel extends BaseViewModel<EventTileRenderState, Even
return this.linkedMessageTimestampViewModel;
}
/** Lazily creates and returns the thread message preview child view model. */
public getThreadMessagePreviewViewModel(props: ThreadMessagePreviewViewModelProps): ThreadMessagePreviewViewModel {
this.threadMessagePreviewViewModel ??= new ThreadMessagePreviewViewModel(props);
return this.threadMessagePreviewViewModel;
}
/** Releases the thread message preview child view model when its adapter unmounts. */
public releaseThreadMessagePreviewViewModel(): void {
this.threadMessagePreviewViewModel?.dispose();
this.threadMessagePreviewViewModel = undefined;
}
/** Lazily creates and returns the thread summary child view model. */
public getThreadSummaryViewModel(props: ThreadSummaryViewModelProps): ThreadSummaryViewModel {
this.threadSummaryViewModel ??= new ThreadSummaryViewModel(props);
return this.threadSummaryViewModel;
}
/** Releases the thread summary child view model when its adapter unmounts. */
public releaseThreadSummaryViewModel(): void {
this.threadSummaryViewModel?.dispose();
this.threadSummaryViewModel = undefined;
}
/** Lazily creates and returns the thread-list action bar child view model. */
public getThreadListActionBarViewModel(props: ThreadListActionBarViewModelProps): ThreadListActionBarViewModel {
this.threadListActionBarViewModel ??= new ThreadListActionBarViewModel(props);
return this.threadListActionBarViewModel;
}
/** Lazily creates and returns the E2E message-shared icon child view model. */
public getE2eMessageSharedIconViewModel(props: E2eMessageSharedIconViewModelProps): E2eMessageSharedIconViewModel {
this.e2eMessageSharedIconViewModel ??= new E2eMessageSharedIconViewModel(props);
return this.e2eMessageSharedIconViewModel;
}
/** Releases the E2E message-shared icon child view model when its adapter unmounts. */
public releaseE2eMessageSharedIconViewModel(): void {
this.e2eMessageSharedIconViewModel?.dispose();
this.e2eMessageSharedIconViewModel = undefined;
}
/** Lazily creates and returns the event action bar child view model. */
public getActionBarViewModel(props: EventTileActionBarViewModelProps): EventTileActionBarViewModel {
this.actionBarViewModel ??= new EventTileActionBarViewModel(props);
return this.actionBarViewModel;
}
/** Releases the event action bar child view model when its adapter unmounts. */
public releaseActionBarViewModel(): void {
this.actionBarViewModel?.dispose();
this.actionBarViewModel = undefined;
}
/** Lazily creates and returns the reactions row child view model. */
public getReactionsRowViewModel(props: ReactionsRowViewModelProps): ReactionsRowViewModel {
this.reactionsRowViewModel ??= new ReactionsRowViewModel(props);
return this.reactionsRowViewModel;
}
/** Releases the reactions row child view model when its adapter unmounts. */
public releaseReactionsRowViewModel(): void {
this.reactionsRowViewModel?.dispose();
this.reactionsRowViewModel = undefined;
}
/** Derives render-ready EventTile state from component-owned inputs. */
public static createRenderState(props: EventTileViewModelProps): EventTileRenderState {
const snapshot = EventTileViewModel.createSnapshot(props);