Fix status-bar overlap on scroll, and reposition/elevate the avatar menu
- Every tab now wraps its CustomScrollView in SafeArea(top: true) - the pinned sort/filter row was riding up underneath the status bar once the floating top bar above it fully collapsed, since that bar's own internal SafeArea only reserved the inset while it had some height left to put it in. Reserving it outside the scrolling region entirely fixes this regardless of the floating header's state. Caught live on device and backed by a new regression test. - The avatar menu now covers the top bar (title included) instead of sitting below it - positioned off just the status-bar inset rather than the top bar's full height on top of that. - The avatar menu's card now carries a second, tighter contact shadow alongside nooDialogShadow - that shadow alone was essentially invisible on a small card over a dark theme's near-black background. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -100,12 +100,19 @@ class ActivityView extends StatelessWidget {
|
||||
...tabBottomInsetSlivers(context),
|
||||
];
|
||||
|
||||
final scrollView = CustomScrollView(
|
||||
controller: scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item feed.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
// See files_view.dart's identical fix - without this, the sticky
|
||||
// controls row rides up under the status bar once the floating top bar
|
||||
// above it fully collapses.
|
||||
final scrollView = SafeArea(
|
||||
top: true,
|
||||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
controller: scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item feed.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
),
|
||||
);
|
||||
|
||||
return ColoredBox(
|
||||
|
||||
@@ -658,12 +658,19 @@ class _FavoritesViewState extends State<FavoritesView> {
|
||||
color: colors.accent,
|
||||
backgroundColor: colors.surface,
|
||||
onRefresh: favoritesController.fetchAll,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
// See files_view.dart's identical fix - without this, the sticky
|
||||
// controls row rides up under the status bar once the floating
|
||||
// top bar above it fully collapses.
|
||||
child: SafeArea(
|
||||
top: true,
|
||||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -853,14 +853,30 @@ class _FilesViewState extends State<FilesView> {
|
||||
unawaited(sync.syncOnPull());
|
||||
return browser.reload();
|
||||
},
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// Pull-to-refresh needs a scroll physics that allows dragging
|
||||
// past the edge even when content doesn't fill the viewport -
|
||||
// an empty or single-item list otherwise can't be pulled at all
|
||||
// under the platform default physics.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
// `topBarSliver`'s floating header can collapse all the way to
|
||||
// zero height (fully scrolled away), at which point the sticky
|
||||
// controls row right below it in `contentSlivers` would otherwise
|
||||
// ride up underneath the status bar instead of stopping below it
|
||||
// - the floating top bar used to be the only thing reserving that
|
||||
// space (via its own internal `SafeArea`), and that reservation
|
||||
// disappears along with it once it's fully hidden. Wrapping the
|
||||
// whole scroll view keeps the inset outside the scrolling region
|
||||
// entirely, so it's never implicated in the floating header's own
|
||||
// collapse/reveal math - safe to apply unconditionally, since
|
||||
// desktop's `MediaQuery.padding.top` is 0 anyway (no topBar / no
|
||||
// status bar there).
|
||||
child: SafeArea(
|
||||
top: true,
|
||||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// Pull-to-refresh needs a scroll physics that allows dragging
|
||||
// past the edge even when content doesn't fill the viewport -
|
||||
// an empty or single-item list otherwise can't be pulled at
|
||||
// all under the platform default physics.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -369,12 +369,19 @@ class _PhotosViewState extends State<PhotosView> {
|
||||
color: colors.accent,
|
||||
backgroundColor: colors.surface,
|
||||
onRefresh: photosController.fetchAllMedia,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
// See files_view.dart's identical fix - without this, the sticky
|
||||
// controls row rides up under the status bar once the floating
|
||||
// top bar above it fully collapses.
|
||||
child: SafeArea(
|
||||
top: true,
|
||||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -88,12 +88,19 @@ class _RecentViewState extends State<RecentView> {
|
||||
color: colors.accent,
|
||||
backgroundColor: colors.surface,
|
||||
onRefresh: recent.fetchAll,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
// See files_view.dart's identical fix - without this, the sticky
|
||||
// controls row rides up under the status bar once the floating top
|
||||
// bar above it fully collapses.
|
||||
child: SafeArea(
|
||||
top: true,
|
||||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -134,12 +134,19 @@ class _SharesViewState extends State<SharesView> {
|
||||
color: colors.accent,
|
||||
backgroundColor: colors.surface,
|
||||
onRefresh: sharesController.fetchAll,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
// See files_view.dart's identical fix - without this, the sticky
|
||||
// controls row rides up under the status bar once the floating top
|
||||
// bar above it fully collapses.
|
||||
child: SafeArea(
|
||||
top: true,
|
||||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -103,12 +103,19 @@ class _TrashViewState extends State<TrashView> {
|
||||
color: colors.accent,
|
||||
backgroundColor: colors.surface,
|
||||
onRefresh: trashController.fetchAll,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
// See files_view.dart's identical fix - without this, the sticky
|
||||
// controls row rides up under the status bar once the floating top
|
||||
// bar above it fully collapses.
|
||||
child: SafeArea(
|
||||
top: true,
|
||||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
// See files_view.dart's identical fix - without this, pull-to-
|
||||
// refresh can't be triggered on an empty or single-item list.
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: contentSlivers,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user