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:
Mohamed Boudra
2026-07-11 15:39:14 +08:00
committed by GitHub
parent 860fcb2e35
commit 28a27b02d3
40 changed files with 1244 additions and 543 deletions
+8 -28
View File
@@ -9,22 +9,16 @@ import { getMarkdownListMarker } from "@/utils/markdown-list";
type MarkdownRuleStyles = Record<string, TextStyle & ViewStyle & { [key: string]: unknown }>;
function MarkdownInlineText({
textKey,
inheritedStyle,
ruleStyle,
children,
}: {
textKey: string;
inheritedStyle: StyleProp<TextStyle>;
ruleStyle: StyleProp<TextStyle>;
children: ReactNode;
}) {
const style = useMemo(() => [inheritedStyle, ruleStyle], [inheritedStyle, ruleStyle]);
return (
<Text key={textKey} style={style}>
{children}
</Text>
);
return <Text style={style}>{children}</Text>;
}
function MarkdownListItemContent({
@@ -39,12 +33,10 @@ function MarkdownListItemContent({
}
function MarkdownParagraph({
textKey,
paragraphStyle,
isLastChild,
children,
}: {
textKey: string;
paragraphStyle: StyleProp<ViewStyle>;
isLastChild: boolean;
children: ReactNode;
@@ -53,11 +45,7 @@ function MarkdownParagraph({
() => [paragraphStyle, isLastChild ? PARAGRAPH_LAST_CHILD : null],
[paragraphStyle, isLastChild],
);
return (
<View key={textKey} style={style}>
{children}
</View>
);
return <View style={style}>{children}</View>;
}
function createPlanMarkdownRules() {
@@ -69,11 +57,7 @@ function createPlanMarkdownRules() {
styles: MarkdownRuleStyles,
inheritedStyles: TextStyle = {},
) => (
<MarkdownInlineText
textKey={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.text}
>
<MarkdownInlineText key={node.key} inheritedStyle={inheritedStyles} ruleStyle={styles.text}>
{node.content}
</MarkdownInlineText>
),
@@ -85,7 +69,7 @@ function createPlanMarkdownRules() {
inheritedStyles: TextStyle = {},
) => (
<MarkdownInlineText
textKey={node.key}
key={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.textgroup}
>
@@ -100,7 +84,7 @@ function createPlanMarkdownRules() {
inheritedStyles: TextStyle = {},
) => (
<MarkdownInlineText
textKey={node.key}
key={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.code_block}
>
@@ -114,11 +98,7 @@ function createPlanMarkdownRules() {
styles: MarkdownRuleStyles,
inheritedStyles: TextStyle = {},
) => (
<MarkdownInlineText
textKey={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.fence}
>
<MarkdownInlineText key={node.key} inheritedStyle={inheritedStyles} ruleStyle={styles.fence}>
{node.content}
</MarkdownInlineText>
),
@@ -130,7 +110,7 @@ function createPlanMarkdownRules() {
inheritedStyles: TextStyle = {},
) => (
<MarkdownInlineText
textKey={node.key}
key={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.code_inline}
>
@@ -183,7 +163,7 @@ function createPlanMarkdownRules() {
const isLastChild = parent[0]?.children?.at(-1)?.key === node.key;
return (
<MarkdownParagraph
textKey={node.key}
key={node.key}
paragraphStyle={styles.paragraph}
isLastChild={isLastChild}
>