mirror of
https://github.com/block/buzz.git
synced 2026-10-31 06:21:34 +00:00
perf(mobile): skip unchanged message footer layout (#8433)
Rebuilding an unchanged message footer currently schedules another layout even when its overlap value is identical. Only invalidate footer layout when that value changes, preserving layout updates for actual geometry changes. ### Stable release recommendation Exclude from `mobile-release/conference-2026-10`; defer to the following release. The regression test demonstrates eliminated redundant layout, but the effect on navigation latency has not been quantified. ### Validation The added widget regression checks that unchanged footer rebuilds do not repeat layout and changed overlap still updates geometry. The independent footer build passes the full mobile suite, analysis, and native iOS Simulator build. Channel scrolling, opening an existing reaction list, and thread navigation were exercised on iOS 26.5 Simulator. The full local repository gate previously encountered an unrelated, unchanged desktop subprocess timing test failure; that test passed in isolation. All PR CI checks pass, including the native iOS suite. <!-- buzz-review-completed --> Signed-off-by: Tom Brow <tomb@block.xyz>
This commit is contained in:
@@ -54,9 +54,7 @@ class _FooterLayout extends MultiChildRenderObjectWidget {
|
||||
BuildContext context,
|
||||
covariant RenderBox renderObject,
|
||||
) {
|
||||
(renderObject as _RenderMessageFooter)
|
||||
..overlap = overlap
|
||||
..markNeedsLayout();
|
||||
(renderObject as _RenderMessageFooter).overlap = overlap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,9 +68,15 @@ class _RenderMessageFooter extends RenderBox
|
||||
RenderBox,
|
||||
ContainerBoxParentData<RenderBox>
|
||||
> {
|
||||
_RenderMessageFooter(this.overlap);
|
||||
_RenderMessageFooter(this._overlap);
|
||||
|
||||
double overlap;
|
||||
double _overlap;
|
||||
double get overlap => _overlap;
|
||||
set overlap(double value) {
|
||||
if (_overlap == value) return;
|
||||
_overlap = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
@override
|
||||
void setupParentData(RenderBox child) {
|
||||
|
||||
@@ -1,8 +1,47 @@
|
||||
import 'package:buzz/features/channels/message_footer_layout.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('unchanged footer geometry does not relayout its timeline row', (
|
||||
tester,
|
||||
) async {
|
||||
var layouts = 0;
|
||||
final overlap = ValueNotifier(8.0);
|
||||
addTearDown(overlap.dispose);
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: _LayoutCounter(
|
||||
onLayout: () => layouts++,
|
||||
child: ValueListenableBuilder(
|
||||
valueListenable: overlap,
|
||||
builder: (context, value, child) => MessageFooterLayout(
|
||||
overlap: value,
|
||||
footer: const SizedBox(width: 100, height: 32),
|
||||
child: const SizedBox(width: 200, height: 60),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
final initialLayouts = layouts;
|
||||
tester.element(find.byType(MessageFooterLayout)).markNeedsBuild();
|
||||
await tester.pump();
|
||||
expect(
|
||||
layouts,
|
||||
initialLayouts,
|
||||
reason: 'Rebuilding unchanged reactions must not dirty the row layout',
|
||||
);
|
||||
overlap.value = 12;
|
||||
await tester.pump();
|
||||
expect(layouts, greaterThan(initialLayouts));
|
||||
expect(tester.getSize(find.byType(MessageFooterLayout)).height, 80);
|
||||
});
|
||||
|
||||
testWidgets('footer global transforms and semantics include overlap offset', (
|
||||
tester,
|
||||
) async {
|
||||
@@ -118,3 +157,21 @@ void main() {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class _LayoutCounter extends SingleChildRenderObjectWidget {
|
||||
const _LayoutCounter({required this.onLayout, required super.child});
|
||||
final VoidCallback onLayout;
|
||||
@override
|
||||
RenderObject createRenderObject(BuildContext context) =>
|
||||
_CountLayouts(onLayout);
|
||||
}
|
||||
|
||||
class _CountLayouts extends RenderProxyBox {
|
||||
_CountLayouts(this.onLayout);
|
||||
final VoidCallback onLayout;
|
||||
@override
|
||||
void performLayout() {
|
||||
onLayout();
|
||||
super.performLayout();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user