perf: Phase 1 critical performance fixes + production macOS build
Performance: - Move JSON parsing to background isolate via Isolate.run() (eliminates 2-4s UI freeze) - Cache filteredEntries with key-based invalidation (eliminates O(n) recomputation) - Debounce search queries at 300ms (prevents cascade rebuilds on keystroke) - Flatten timeline from 2-level turn×response Column to single virtualized ListView.builder - Add RepaintBoundary per timeline item (isolates repaints during scroll) - Use context.select for granular rebuilds instead of top-level context.watch - Lazy ExpandableCard: child not built until first expand (replaces AnimatedCrossFade) - Use IndexedStack in AppShell (preserves screen state across tab switches) Fixes: - Collect parse errors instead of silently swallowing them - Show parse error count in timeline filter bar - Fix overflow in tokens screen pie chart legend Build: - Configure Developer ID signing with hardened runtime for production distribution - Enable secure timestamps for notarization - Update app name to Claude Session Viewer - Signed, notarized, stapled DMG distribution
This commit is contained in:
@@ -26,11 +26,13 @@ class _ExpandableCardState extends State<ExpandableCard>
|
||||
late bool _expanded;
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _rotation;
|
||||
bool _hasBeenExpanded = false; // Track if ever expanded to lazy-build
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_expanded = widget.initiallyExpanded;
|
||||
_hasBeenExpanded = _expanded;
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
vsync: this,
|
||||
@@ -51,6 +53,7 @@ class _ExpandableCardState extends State<ExpandableCard>
|
||||
setState(() {
|
||||
_expanded = !_expanded;
|
||||
if (_expanded) {
|
||||
_hasBeenExpanded = true;
|
||||
_controller.forward();
|
||||
} else {
|
||||
_controller.reverse();
|
||||
@@ -76,7 +79,8 @@ class _ExpandableCardState extends State<ExpandableCard>
|
||||
onTap: _toggle,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
RotationTransition(
|
||||
@@ -93,19 +97,18 @@ class _ExpandableCardState extends State<ExpandableCard>
|
||||
),
|
||||
),
|
||||
),
|
||||
ClipRect(
|
||||
child: AnimatedCrossFade(
|
||||
firstChild: const SizedBox.shrink(),
|
||||
secondChild: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 0, 12, 12),
|
||||
child: widget.child,
|
||||
// Lazy animated expand: only build child once ever expanded
|
||||
if (_hasBeenExpanded)
|
||||
ClipRect(
|
||||
child: SizeTransition(
|
||||
sizeFactor: _controller,
|
||||
axisAlignment: -1.0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 0, 12, 12),
|
||||
child: widget.child,
|
||||
),
|
||||
),
|
||||
crossFadeState: _expanded
|
||||
? CrossFadeState.showSecond
|
||||
: CrossFadeState.showFirst,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user