Profile traces showed 100-370ms UI-thread frames while scrolling the library screen, dominated by rebuilding and inflating media cards. - Gate per-card focus/pointer chrome on input mode: FocusableWrapper skips the scale/border wrappers and creates its AnimationController lazily outside keyboard mode, and ClickableCursor plus the card tap region only build MouseRegion/InkWell machinery on desktop - TV and touch use a bare GestureDetector. Hub cards also drop their outer gesture wrapper outside keyboard mode; the card's own tap region always won the gesture arena anyway. - Memoize sliver children (SliverChildMemo): browse/collections grids and hub rows return identical widget instances for unchanged items, so delegate swaps from pagination, watch-state, and deletion setStates no longer rebuild every realized card inside layout. The browse tab prunes the memo in lockstep with focus-node eviction so a cached card can never resurrect a disposed FocusNode. - Budget fresh inflation (CardInflationBudget): while a scrollable is moving in pointer/touch mode at most one new card inflates per frame, the rest render as SkeletonMediaCard and upgrade on following frames. Hub rows also stop pre-inflating 250px of off-screen cards on entry. Device traces: worst frame 373ms -> 103ms, per-card build 3.6ms -> 2.4ms median; remaining row-entry work is spread across frames.
20 lines
653 B
Dart
20 lines
653 B
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../utils/platform_detector.dart';
|
|
|
|
class ClickableCursor extends StatelessWidget {
|
|
final Widget child;
|
|
final bool enabled;
|
|
|
|
const ClickableCursor({super.key, required this.child, this.enabled = true});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// Cursor feedback only matters where a pointer exists: skip the
|
|
// MouseRegion on TV and touch handhelds — one exists per card and they
|
|
// add up on low-end devices.
|
|
if (!PlatformDetector.isDesktopOS()) return child;
|
|
return MouseRegion(cursor: enabled ? SystemMouseCursors.click : MouseCursor.defer, child: child);
|
|
}
|
|
}
|