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