Prevent Android chats from freezing or going blank (#1989)
* fix(app): stabilize streamed chat rendering Use deterministic Markdown AST keys and preserve unique row identities when an assistant message resumes after a tool. Keep native gesture and plan-card children correctly keyed to avoid unsupported Fabric reconciliation paths. * fix(app): stabilize retained native panels Keep retained workspace roots in a stable native order and make active panels present in the selection commit. Hidden panels now stop expensive subscriptions and animations without losing mounted state. * fix(app): harden retained panel activity
This commit is contained in:
@@ -62,7 +62,6 @@ import {
|
||||
} from "@/utils/host-routes";
|
||||
import {
|
||||
shouldShowSidebarHostLabels,
|
||||
useSidebarWorkspaceEntry,
|
||||
type SidebarProjectEntry,
|
||||
type SidebarWorkspaceEntry,
|
||||
type SidebarWorkspacePlacement,
|
||||
@@ -223,6 +222,7 @@ function selectionForSelectedWorkspace(
|
||||
interface SidebarWorkspaceListProps {
|
||||
statusGroups: StatusGroup[];
|
||||
projects: SidebarProjectEntry[];
|
||||
workspaceEntriesByKey: ReadonlyMap<string, SidebarWorkspaceEntry>;
|
||||
projectNamesByKey: Map<string, string>;
|
||||
collapsedProjectKeys: ReadonlySet<string>;
|
||||
onToggleProjectCollapsed: (projectKey: string) => void;
|
||||
@@ -1613,6 +1613,7 @@ function WorkspaceRowWithMenu({
|
||||
|
||||
interface WorkspaceRowItemProps {
|
||||
workspace: SidebarWorkspacePlacement;
|
||||
workspaceEntry: SidebarWorkspaceEntry | null;
|
||||
subtitle?: string | null;
|
||||
shortcutNumber: number | null;
|
||||
showShortcutBadge: boolean;
|
||||
@@ -1628,6 +1629,7 @@ interface WorkspaceRowItemProps {
|
||||
|
||||
function WorkspaceRowItem({
|
||||
workspace,
|
||||
workspaceEntry,
|
||||
subtitle,
|
||||
shortcutNumber,
|
||||
showShortcutBadge,
|
||||
@@ -1650,7 +1652,7 @@ function WorkspaceRowItem({
|
||||
|
||||
return (
|
||||
<WorkspaceRow
|
||||
workspace={workspace}
|
||||
workspaceEntry={workspaceEntry}
|
||||
subtitle={subtitle}
|
||||
shortcutNumber={shortcutNumber}
|
||||
showShortcutBadge={showShortcutBadge}
|
||||
@@ -1688,6 +1690,7 @@ function areWorkspaceRowItemPropsEqual(
|
||||
});
|
||||
return (
|
||||
previous.workspace === next.workspace &&
|
||||
previous.workspaceEntry === next.workspaceEntry &&
|
||||
previous.subtitle === next.subtitle &&
|
||||
previous.shortcutNumber === next.shortcutNumber &&
|
||||
previous.showShortcutBadge === next.showShortcutBadge &&
|
||||
@@ -1704,7 +1707,7 @@ function areWorkspaceRowItemPropsEqual(
|
||||
const MemoWorkspaceRowItem = memo(WorkspaceRowItem, areWorkspaceRowItemPropsEqual);
|
||||
|
||||
function WorkspaceRow({
|
||||
workspace,
|
||||
workspaceEntry,
|
||||
subtitle,
|
||||
shortcutNumber,
|
||||
showShortcutBadge,
|
||||
@@ -1716,7 +1719,7 @@ function WorkspaceRow({
|
||||
isCreating = false,
|
||||
selected,
|
||||
}: {
|
||||
workspace: SidebarWorkspacePlacement;
|
||||
workspaceEntry: SidebarWorkspaceEntry | null;
|
||||
subtitle?: string | null;
|
||||
shortcutNumber: number | null;
|
||||
showShortcutBadge: boolean;
|
||||
@@ -1728,15 +1731,13 @@ function WorkspaceRow({
|
||||
isCreating?: boolean;
|
||||
selected: boolean;
|
||||
}) {
|
||||
const hydratedWorkspace = useSidebarWorkspaceEntry(workspace.serverId, workspace.workspaceId);
|
||||
|
||||
if (!hydratedWorkspace) {
|
||||
if (!workspaceEntry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<WorkspaceRowWithMenu
|
||||
workspace={hydratedWorkspace}
|
||||
workspace={workspaceEntry}
|
||||
subtitle={subtitle}
|
||||
selected={selected}
|
||||
shortcutNumber={shortcutNumber}
|
||||
@@ -1753,6 +1754,7 @@ function WorkspaceRow({
|
||||
|
||||
function ProjectBlock({
|
||||
project,
|
||||
workspaceEntriesByKey,
|
||||
collapsed,
|
||||
displayName,
|
||||
iconDataUri,
|
||||
@@ -1775,6 +1777,7 @@ function ProjectBlock({
|
||||
supportsMultiplicityByServerId,
|
||||
}: {
|
||||
project: SidebarProjectEntry;
|
||||
workspaceEntriesByKey: ReadonlyMap<string, SidebarWorkspaceEntry>;
|
||||
collapsed: boolean;
|
||||
displayName: string;
|
||||
iconDataUri: string | null;
|
||||
@@ -1824,6 +1827,7 @@ function ProjectBlock({
|
||||
return (
|
||||
<MemoWorkspaceRowItem
|
||||
workspace={item}
|
||||
workspaceEntry={workspaceEntriesByKey.get(item.workspaceKey) ?? null}
|
||||
subtitle={
|
||||
showHostLabels ? (hostLabelByServerId.get(item.serverId) ?? item.serverId) : null
|
||||
}
|
||||
@@ -1850,6 +1854,7 @@ function ProjectBlock({
|
||||
selectionEnabled,
|
||||
shortcutIndexByWorkspaceKey,
|
||||
showShortcutBadges,
|
||||
workspaceEntriesByKey,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -2004,6 +2009,7 @@ type ProjectBlockProps = Parameters<typeof ProjectBlock>[0];
|
||||
function areProjectBlockPropsEqual(previous: ProjectBlockProps, next: ProjectBlockProps): boolean {
|
||||
return (
|
||||
previous.project === next.project &&
|
||||
previous.workspaceEntriesByKey === next.workspaceEntriesByKey &&
|
||||
previous.collapsed === next.collapsed &&
|
||||
previous.displayName === next.displayName &&
|
||||
previous.iconDataUri === next.iconDataUri &&
|
||||
@@ -2058,6 +2064,7 @@ const MemoProjectBlock = memo(ProjectBlock, areProjectBlockPropsEqual);
|
||||
export function SidebarWorkspaceList({
|
||||
statusGroups,
|
||||
projects,
|
||||
workspaceEntriesByKey,
|
||||
projectNamesByKey,
|
||||
collapsedProjectKeys,
|
||||
onToggleProjectCollapsed,
|
||||
@@ -2096,6 +2103,7 @@ export function SidebarWorkspaceList({
|
||||
) : (
|
||||
<ProjectModeList
|
||||
projects={projects}
|
||||
workspaceEntriesByKey={workspaceEntriesByKey}
|
||||
collapsedProjectKeys={collapsedProjectKeys}
|
||||
onToggleProjectCollapsed={onToggleProjectCollapsed}
|
||||
shortcutIndexByWorkspaceKey={shortcutIndexByWorkspaceKey}
|
||||
@@ -2145,6 +2153,7 @@ function SidebarStatusModeWrapper({
|
||||
|
||||
function ProjectModeList({
|
||||
projects,
|
||||
workspaceEntriesByKey,
|
||||
collapsedProjectKeys,
|
||||
onToggleProjectCollapsed,
|
||||
shortcutIndexByWorkspaceKey,
|
||||
@@ -2333,6 +2342,7 @@ function ProjectModeList({
|
||||
return (
|
||||
<MemoProjectBlock
|
||||
project={item}
|
||||
workspaceEntriesByKey={workspaceEntriesByKey}
|
||||
collapsed={collapsedProjectKeys.has(item.projectKey)}
|
||||
displayName={item.projectName}
|
||||
iconDataUri={projectIconByProjectKey.get(item.projectKey) ?? null}
|
||||
@@ -2371,6 +2381,7 @@ function ProjectModeList({
|
||||
selectionEnabled,
|
||||
shortcutIndexByWorkspaceKey,
|
||||
showShortcutBadges,
|
||||
workspaceEntriesByKey,
|
||||
creatingWorkspaceIds,
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user