mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
refactor: use Appbar titlebar throughout the app
This commit is contained in:
parent
fcefce4b1b
commit
f80ea32de4
@ -1,89 +1,56 @@
|
||||
import 'package:flutter/material.dart' hide AppBar;
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:shadcn_flutter/shadcn_flutter.dart' show AppBar;
|
||||
import 'package:shadcn_flutter/shadcn_flutter.dart'
|
||||
show AppBar, WidgetExtension;
|
||||
import 'package:spotube/components/titlebar/titlebar_buttons.dart';
|
||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class PageWindowTitleBar extends StatefulHookConsumerWidget
|
||||
implements PreferredSizeWidget {
|
||||
final Widget? leading;
|
||||
class TitleBar extends HookConsumerWidget implements PreferredSizeWidget {
|
||||
final bool automaticallyImplyLeading;
|
||||
final List<Widget>? actions;
|
||||
final List<Widget> trailing;
|
||||
final List<Widget> leading;
|
||||
final Widget? child;
|
||||
final Widget? title;
|
||||
final Widget? header; // small widget placed on top of title
|
||||
final Widget? subtitle; // small widget placed below title
|
||||
final bool
|
||||
trailingExpanded; // expand the trailing instead of the main content
|
||||
final AlignmentGeometry alignment;
|
||||
final Color? backgroundColor;
|
||||
final Color? foregroundColor;
|
||||
final IconThemeData? actionsIconTheme;
|
||||
final bool? centerTitle;
|
||||
final double? titleSpacing;
|
||||
final double toolbarOpacity;
|
||||
final double? leadingWidth;
|
||||
final TextStyle? toolbarTextStyle;
|
||||
final TextStyle? titleTextStyle;
|
||||
final double? titleWidth;
|
||||
final Widget? title;
|
||||
final double? leadingGap;
|
||||
final double? trailingGap;
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final double? height;
|
||||
final bool useSafeArea;
|
||||
final double? surfaceBlur;
|
||||
final double? surfaceOpacity;
|
||||
|
||||
final bool _sliver;
|
||||
|
||||
const PageWindowTitleBar({
|
||||
const TitleBar({
|
||||
super.key,
|
||||
this.actions,
|
||||
this.automaticallyImplyLeading = true,
|
||||
this.trailing = const [],
|
||||
this.leading = const [],
|
||||
this.title,
|
||||
this.toolbarOpacity = 1,
|
||||
this.header,
|
||||
this.subtitle,
|
||||
this.child,
|
||||
this.trailingExpanded = false,
|
||||
this.alignment = Alignment.center,
|
||||
this.padding,
|
||||
this.backgroundColor,
|
||||
this.actionsIconTheme,
|
||||
this.automaticallyImplyLeading = false,
|
||||
this.centerTitle,
|
||||
this.foregroundColor,
|
||||
this.leading,
|
||||
this.leadingWidth,
|
||||
this.titleSpacing,
|
||||
this.titleTextStyle,
|
||||
this.titleWidth,
|
||||
this.toolbarTextStyle,
|
||||
}) : _sliver = false,
|
||||
pinned = false,
|
||||
floating = false,
|
||||
snap = false,
|
||||
stretch = false;
|
||||
this.leadingGap,
|
||||
this.trailingGap,
|
||||
this.height,
|
||||
this.surfaceBlur,
|
||||
this.surfaceOpacity,
|
||||
this.useSafeArea = true,
|
||||
});
|
||||
|
||||
final bool pinned;
|
||||
final bool floating;
|
||||
final bool snap;
|
||||
final bool stretch;
|
||||
|
||||
const PageWindowTitleBar.sliver({
|
||||
super.key,
|
||||
this.actions,
|
||||
this.title,
|
||||
this.backgroundColor,
|
||||
this.actionsIconTheme,
|
||||
this.automaticallyImplyLeading = false,
|
||||
this.centerTitle,
|
||||
this.foregroundColor,
|
||||
this.leading,
|
||||
this.leadingWidth,
|
||||
this.titleSpacing,
|
||||
this.titleTextStyle,
|
||||
this.titleWidth,
|
||||
this.toolbarTextStyle,
|
||||
this.pinned = false,
|
||||
this.floating = false,
|
||||
this.snap = false,
|
||||
this.stretch = false,
|
||||
}) : _sliver = true,
|
||||
toolbarOpacity = 1;
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||
|
||||
@override
|
||||
ConsumerState<PageWindowTitleBar> createState() => _PageWindowTitleBarState();
|
||||
}
|
||||
|
||||
class _PageWindowTitleBarState extends ConsumerState<PageWindowTitleBar> {
|
||||
void onDrag(details) {
|
||||
void onDrag(WidgetRef ref) {
|
||||
final systemTitleBar =
|
||||
ref.read(userPreferencesProvider.select((s) => s.systemTitleBar));
|
||||
if (kIsDesktop && !systemTitleBar) {
|
||||
@ -92,86 +59,53 @@ class _PageWindowTitleBarState extends ConsumerState<PageWindowTitleBar> {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
Widget build(BuildContext context, ref) {
|
||||
final hasLeadingOrCanPop = leading.isNotEmpty || Navigator.canPop(context);
|
||||
|
||||
if (widget._sliver) {
|
||||
return SliverLayoutBuilder(
|
||||
return SizedBox(
|
||||
height: height ?? 56,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final hasFullscreen =
|
||||
mediaQuery.size.width == constraints.crossAxisExtent;
|
||||
final hasLeadingOrCanPop =
|
||||
widget.leading != null || Navigator.canPop(context);
|
||||
|
||||
return SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0,
|
||||
),
|
||||
sliver: SliverAppBar(
|
||||
leading: widget.leading,
|
||||
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
||||
actions: [
|
||||
...?widget.actions,
|
||||
WindowTitleBarButtons(foregroundColor: widget.foregroundColor),
|
||||
],
|
||||
backgroundColor: widget.backgroundColor,
|
||||
foregroundColor: widget.foregroundColor,
|
||||
actionsIconTheme: widget.actionsIconTheme,
|
||||
centerTitle: widget.centerTitle,
|
||||
titleSpacing: widget.titleSpacing,
|
||||
leadingWidth: widget.leadingWidth,
|
||||
toolbarTextStyle: widget.toolbarTextStyle,
|
||||
titleTextStyle: widget.titleTextStyle,
|
||||
title: SizedBox(
|
||||
width: double.infinity, // workaround to force dragging
|
||||
child: widget.title ?? const Text(""),
|
||||
),
|
||||
pinned: widget.pinned,
|
||||
floating: widget.floating,
|
||||
snap: widget.snap,
|
||||
stretch: widget.stretch,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return LayoutBuilder(builder: (context, constrains) {
|
||||
final hasFullscreen = mediaQuery.size.width == constrains.maxWidth;
|
||||
final hasLeadingOrCanPop =
|
||||
widget.leading != null || Navigator.canPop(context);
|
||||
MediaQuery.sizeOf(context).width == constraints.maxWidth;
|
||||
|
||||
return GestureDetector(
|
||||
onHorizontalDragStart: onDrag,
|
||||
onVerticalDragStart: onDrag,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0,
|
||||
),
|
||||
onHorizontalDragStart: (_) => onDrag(ref),
|
||||
onVerticalDragStart: (_) => onDrag(ref),
|
||||
child: AppBar(
|
||||
leading: [
|
||||
if (widget.leading != null) widget.leading!,
|
||||
if (widget.leading == null &&
|
||||
widget.automaticallyImplyLeading &&
|
||||
Navigator.canPop(context))
|
||||
leading: leading.isEmpty &&
|
||||
automaticallyImplyLeading &&
|
||||
Navigator.canPop(context)
|
||||
? [
|
||||
const BackButton(),
|
||||
],
|
||||
]
|
||||
: leading,
|
||||
trailing: [
|
||||
...?widget.actions,
|
||||
WindowTitleBarButtons(foregroundColor: widget.foregroundColor),
|
||||
...trailing,
|
||||
WindowTitleBarButtons(foregroundColor: foregroundColor),
|
||||
],
|
||||
backgroundColor: widget.backgroundColor,
|
||||
title: SizedBox(
|
||||
width: double.infinity, // workaround to force dragging
|
||||
child: widget.title ?? const Text(""),
|
||||
),
|
||||
alignment: widget.centerTitle == true
|
||||
? Alignment.center
|
||||
: Alignment.centerLeft,
|
||||
leadingGap: widget.leadingWidth,
|
||||
),
|
||||
title: title,
|
||||
header: header,
|
||||
subtitle: subtitle,
|
||||
trailingExpanded: trailingExpanded,
|
||||
alignment: alignment,
|
||||
padding: padding,
|
||||
backgroundColor: backgroundColor,
|
||||
leadingGap: leadingGap,
|
||||
trailingGap: trailingGap,
|
||||
height: height,
|
||||
surfaceBlur: surfaceBlur,
|
||||
surfaceOpacity: surfaceOpacity,
|
||||
useSafeArea: useSafeArea,
|
||||
child: child,
|
||||
).withPadding(
|
||||
left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => Size.fromHeight(height ?? 56.0);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
|
||||
import 'package:spotify/spotify.dart' hide Offset;
|
||||
import 'package:spotube/collections/assets.gen.dart';
|
||||
@ -344,6 +345,7 @@ class TrackOptions extends HookConsumerWidget {
|
||||
leading: const Icon(SpotubeIcons.album),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(context.l10n.go_to_album),
|
||||
Text(
|
||||
|
@ -20,14 +20,14 @@ class TrackView extends HookConsumerWidget {
|
||||
|
||||
return Scaffold(
|
||||
appBar: kIsDesktop
|
||||
? const PageWindowTitleBar(
|
||||
? const TitleBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Colors.white,
|
||||
leadingWidth: 400,
|
||||
leading: Align(
|
||||
leading: [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: BackButton(color: Colors.white),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: null,
|
||||
extendBodyBehindAppBar: true,
|
||||
|
@ -138,15 +138,15 @@ class PlayerView extends HookConsumerWidget {
|
||||
child: ForceDraggableWidget(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: topPadding),
|
||||
child: PageWindowTitleBar(
|
||||
child: TitleBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: titleTextColor,
|
||||
toolbarOpacity: 1,
|
||||
leading: IconButton(
|
||||
leading: [
|
||||
IconButton(
|
||||
icon: const Icon(SpotubeIcons.angleDown, size: 18),
|
||||
onPressed: panelController.close,
|
||||
),
|
||||
actions: [
|
||||
)
|
||||
],
|
||||
trailing: [
|
||||
if (currentTrack is YoutubeSourcedTrack)
|
||||
TextButton.icon(
|
||||
icon: Assets.logos.songlinkTransparent.image(
|
||||
|
@ -30,8 +30,8 @@ class ArtistPage extends HookConsumerWidget {
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
leading: BackButton(),
|
||||
appBar: const TitleBar(
|
||||
leading: [BackButton()],
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
extendBodyBehindAppBar: true,
|
||||
|
@ -23,10 +23,9 @@ class ConnectPage extends HookConsumerWidget {
|
||||
final discoveredDevices = connectClients.asData?.value.services;
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
title: Text(context.l10n.devices),
|
||||
titleSpacing: 0,
|
||||
),
|
||||
body: ListTileTheme(
|
||||
shape: RoundedRectangleBorder(
|
||||
|
@ -88,7 +88,7 @@ class ConnectControlPage extends HookConsumerWidget {
|
||||
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(resolvedService!.name),
|
||||
automaticallyImplyLeading: true,
|
||||
),
|
||||
|
@ -43,9 +43,9 @@ class GettingStarting extends HookConsumerWidget {
|
||||
return Theme(
|
||||
data: themeData,
|
||||
child: Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
actions: [
|
||||
trailing: [
|
||||
ListenableBuilder(
|
||||
listenable: pageController,
|
||||
builder: (context, _) {
|
||||
|
@ -23,11 +23,9 @@ class HomeFeedSectionPage extends HookConsumerWidget {
|
||||
return Skeletonizer(
|
||||
enabled: homeFeedSection.isLoading,
|
||||
child: Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(section.title ?? ""),
|
||||
centerTitle: false,
|
||||
automaticallyImplyLeading: true,
|
||||
titleSpacing: 0,
|
||||
),
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
|
@ -40,8 +40,8 @@ class GenrePlaylistsPage extends HookConsumerWidget {
|
||||
|
||||
return Scaffold(
|
||||
appBar: kIsDesktop
|
||||
? const PageWindowTitleBar(
|
||||
leading: BackButton(color: Colors.white),
|
||||
? const TitleBar(
|
||||
leading: [BackButton(color: Colors.white)],
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Colors.white,
|
||||
)
|
||||
|
@ -25,10 +25,9 @@ class GenrePage extends HookConsumerWidget {
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(context.l10n.explore_genres),
|
||||
automaticallyImplyLeading: true,
|
||||
titleSpacing: 0,
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
|
@ -34,7 +34,7 @@ class HomePage extends HookConsumerWidget {
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
appBar: kIsMobile || kIsMacOS ? null : const PageWindowTitleBar(),
|
||||
appBar: kIsMobile || kIsMacOS ? null : const TitleBar(),
|
||||
body: CustomScrollView(
|
||||
controller: controller,
|
||||
slivers: [
|
||||
|
@ -27,7 +27,7 @@ class LastFMLoginPage extends HookConsumerWidget {
|
||||
final isLoading = useState(false);
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(leading: BackButton()),
|
||||
appBar: const TitleBar(leading: [BackButton()]),
|
||||
body: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 400),
|
||||
|
@ -37,8 +37,9 @@ class LibraryPage extends HookConsumerWidget {
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
headers: [
|
||||
PageWindowTitleBar(
|
||||
leading: TabList(
|
||||
TitleBar(
|
||||
leading: [
|
||||
TabList(
|
||||
index: index.value,
|
||||
children: [
|
||||
for (final child in children)
|
||||
@ -49,7 +50,8 @@ class LibraryPage extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
child: IndexedStack(
|
||||
@ -60,11 +62,6 @@ class LibraryPage extends HookConsumerWidget {
|
||||
UserDownloads(),
|
||||
UserArtists(),
|
||||
UserAlbums(),
|
||||
// Text("UserPlaylists()"),
|
||||
// Text("UserLocalTracks()"),
|
||||
// Text("UserDownloads()"),
|
||||
// Text("UserArtists()"),
|
||||
// Text("UserAlbums()"),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -93,9 +93,8 @@ class LocalLibraryPage extends HookConsumerWidget {
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
leading: const BackButton(),
|
||||
centerTitle: true,
|
||||
appBar: TitleBar(
|
||||
leading: const [BackButton()],
|
||||
title: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -120,7 +119,7 @@ class LocalLibraryPage extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
actions: [
|
||||
trailing: [
|
||||
if (isCache) ...[
|
||||
IconButton(
|
||||
iconSize: 16,
|
||||
|
@ -231,10 +231,9 @@ class PlaylistGeneratorPage extends HookConsumerWidget {
|
||||
final controller = useScrollController();
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
leading: const BackButton(),
|
||||
appBar: TitleBar(
|
||||
leading: const [BackButton()],
|
||||
title: Text(context.l10n.generate_playlist),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Scrollbar(
|
||||
controller: controller,
|
||||
|
@ -48,7 +48,7 @@ class PlaylistGenerateResultPage extends HookConsumerWidget {
|
||||
(generatedPlaylist.asData?.value.length ?? 0);
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(leading: BackButton()),
|
||||
appBar: const TitleBar(leading: [BackButton()]),
|
||||
body: generatedPlaylist.isLoading
|
||||
? Center(
|
||||
child: Column(
|
||||
|
@ -146,7 +146,7 @@ class LyricsPage extends HookConsumerWidget {
|
||||
child: Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: !kIsMacOS
|
||||
? PageWindowTitleBar(
|
||||
? TitleBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
title: tabbar,
|
||||
)
|
||||
|
@ -24,8 +24,8 @@ class WebViewLogin extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
leading: BackButton(color: Colors.white),
|
||||
appBar: const TitleBar(
|
||||
leading: [BackButton(color: Colors.white)],
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
extendBodyBehindAppBar: true,
|
||||
|
@ -42,11 +42,9 @@ class ProfilePage extends HookConsumerWidget {
|
||||
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(context.l10n.profile),
|
||||
titleSpacing: 0,
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
),
|
||||
body: Skeletonizer(
|
||||
enabled: me.isLoading,
|
||||
|
@ -88,7 +88,7 @@ class SearchPage extends HookConsumerWidget {
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
appBar: kIsDesktop && !kIsMacOS
|
||||
? const PageWindowTitleBar(automaticallyImplyLeading: true)
|
||||
? const TitleBar(automaticallyImplyLeading: true)
|
||||
: null,
|
||||
body: auth.asData?.value == null
|
||||
? const AnonymousFallback()
|
||||
|
@ -29,8 +29,8 @@ class AboutSpotube extends HookConsumerWidget {
|
||||
const colon = Text(":");
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
leading: const BackButton(),
|
||||
appBar: TitleBar(
|
||||
leading: const [BackButton()],
|
||||
title: Text(context.l10n.about_spotube),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
|
@ -44,10 +44,9 @@ class BlackListPage extends HookConsumerWidget {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(context.l10n.blacklist),
|
||||
centerTitle: true,
|
||||
leading: const BackButton(),
|
||||
leading: const [BackButton()],
|
||||
),
|
||||
body: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
@ -21,10 +21,10 @@ class LogsPage extends HookConsumerWidget {
|
||||
final logsQuery = ref.watch(logsProvider);
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(context.l10n.logs),
|
||||
leading: const BackButton(),
|
||||
actions: [
|
||||
leading: const [BackButton()],
|
||||
trailing: [
|
||||
IconButton(
|
||||
icon: const Icon(SpotubeIcons.clipboard),
|
||||
iconSize: 16,
|
||||
|
@ -28,9 +28,8 @@ class SettingsPage extends HookConsumerWidget {
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(context.l10n.settings),
|
||||
centerTitle: true,
|
||||
automaticallyImplyLeading: true,
|
||||
),
|
||||
body: Scrollbar(
|
||||
|
@ -25,9 +25,8 @@ class StatsAlbumsPage extends HookConsumerWidget {
|
||||
final albumsData = topAlbums.asData?.value.items ?? [];
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
title: Text(context.l10n.albums),
|
||||
),
|
||||
body: Skeletonizer(
|
||||
|
@ -28,9 +28,8 @@ class StatsArtistsPage extends HookConsumerWidget {
|
||||
() => topTracks.asData?.value.artists ?? [], [topTracks.asData?.value]);
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
title: Text(context.l10n.artists),
|
||||
),
|
||||
body: Skeletonizer(
|
||||
|
@ -41,9 +41,8 @@ class StatsStreamFeesPage extends HookConsumerWidget {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
title: Text(context.l10n.streaming_fees_hypothetical),
|
||||
),
|
||||
body: CustomScrollView(
|
||||
|
@ -28,9 +28,8 @@ class StatsMinutesPage extends HookConsumerWidget {
|
||||
final tracksData = topTracks.asData?.value.items ?? [];
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(context.l10n.minutes_listened),
|
||||
centerTitle: false,
|
||||
automaticallyImplyLeading: true,
|
||||
),
|
||||
body: Skeletonizer(
|
||||
|
@ -26,9 +26,8 @@ class StatsPlaylistsPage extends HookConsumerWidget {
|
||||
final playlistsData = topPlaylists.asData?.value.items ?? [];
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
centerTitle: false,
|
||||
title: Text(context.l10n.playlists),
|
||||
),
|
||||
body: Skeletonizer(
|
||||
|
@ -16,7 +16,7 @@ class StatsPage extends HookConsumerWidget {
|
||||
return SafeArea(
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
appBar: kIsMacOS || kIsMobile ? null : const PageWindowTitleBar(),
|
||||
appBar: kIsMacOS || kIsMobile ? null : const TitleBar(),
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
if (kIsMacOS) const SliverGap(20),
|
||||
|
@ -28,9 +28,8 @@ class StatsStreamsPage extends HookConsumerWidget {
|
||||
final tracksData = topTracks.asData?.value.items ?? [];
|
||||
|
||||
return Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
appBar: TitleBar(
|
||||
title: Text(context.l10n.streamed_songs),
|
||||
centerTitle: false,
|
||||
automaticallyImplyLeading: true,
|
||||
),
|
||||
body: Skeletonizer(
|
||||
|
@ -53,7 +53,7 @@ class TrackPage extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: const PageWindowTitleBar(
|
||||
appBar: const TitleBar(
|
||||
automaticallyImplyLeading: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user