mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
chore: fix window resizing
This commit is contained in:
parent
3649b67869
commit
5930c342b5
@ -20,17 +20,6 @@ class $AssetsBackgroundsGen {
|
|||||||
List<AssetGenImage> get values => [xmasEffect];
|
List<AssetGenImage> get values => [xmasEffect];
|
||||||
}
|
}
|
||||||
|
|
||||||
class $AssetsIllustrationsGen {
|
|
||||||
const $AssetsIllustrationsGen();
|
|
||||||
|
|
||||||
/// File path: assets/illustrations/fixing_bugs.png
|
|
||||||
AssetGenImage get fixingBugs =>
|
|
||||||
const AssetGenImage('assets/illustrations/fixing_bugs.png');
|
|
||||||
|
|
||||||
/// List of all assets
|
|
||||||
List<AssetGenImage> get values => [fixingBugs];
|
|
||||||
}
|
|
||||||
|
|
||||||
class $AssetsLogosGen {
|
class $AssetsLogosGen {
|
||||||
const $AssetsLogosGen();
|
const $AssetsLogosGen();
|
||||||
|
|
||||||
@ -151,8 +140,6 @@ class Assets {
|
|||||||
AssetGenImage('assets/bengali-patterns-bg.jpg');
|
AssetGenImage('assets/bengali-patterns-bg.jpg');
|
||||||
static const AssetGenImage branding = AssetGenImage('assets/branding.png');
|
static const AssetGenImage branding = AssetGenImage('assets/branding.png');
|
||||||
static const AssetGenImage emptyBox = AssetGenImage('assets/empty_box.png');
|
static const AssetGenImage emptyBox = AssetGenImage('assets/empty_box.png');
|
||||||
static const $AssetsIllustrationsGen illustrations =
|
|
||||||
$AssetsIllustrationsGen();
|
|
||||||
static const AssetGenImage invidious = AssetGenImage('assets/invidious.jpg');
|
static const AssetGenImage invidious = AssetGenImage('assets/invidious.jpg');
|
||||||
static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png');
|
static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png');
|
||||||
static const AssetGenImage likedTracks =
|
static const AssetGenImage likedTracks =
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
typedef MouseStateBuilderCB = Widget Function(
|
|
||||||
BuildContext context, MouseState mouseState);
|
|
||||||
|
|
||||||
class MouseState {
|
|
||||||
bool isMouseOver = false;
|
|
||||||
bool isMouseDown = false;
|
|
||||||
MouseState();
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return "isMouseDown: $isMouseDown - isMouseOver: $isMouseOver";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
T? _ambiguate<T>(T? value) => value;
|
|
||||||
|
|
||||||
class MouseStateBuilder extends StatefulWidget {
|
|
||||||
final MouseStateBuilderCB builder;
|
|
||||||
final VoidCallback? onPressed;
|
|
||||||
const MouseStateBuilder({super.key, required this.builder, this.onPressed});
|
|
||||||
@override
|
|
||||||
// ignore: library_private_types_in_public_api
|
|
||||||
_MouseStateBuilderState createState() => _MouseStateBuilderState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MouseStateBuilderState extends State<MouseStateBuilder> {
|
|
||||||
late MouseState _mouseState;
|
|
||||||
_MouseStateBuilderState() {
|
|
||||||
_mouseState = MouseState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MouseRegion(
|
|
||||||
onEnter: (event) {
|
|
||||||
setState(() {
|
|
||||||
_mouseState.isMouseOver = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onExit: (event) {
|
|
||||||
setState(() {
|
|
||||||
_mouseState.isMouseOver = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: GestureDetector(
|
|
||||||
onTapDown: (_) {
|
|
||||||
setState(() {
|
|
||||||
_mouseState.isMouseDown = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onTapCancel: () {
|
|
||||||
setState(() {
|
|
||||||
_mouseState.isMouseDown = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
_mouseState.isMouseDown = false;
|
|
||||||
_mouseState.isMouseOver = false;
|
|
||||||
});
|
|
||||||
_ambiguate(WidgetsBinding.instance)!.addPostFrameCallback((_) {
|
|
||||||
if (widget.onPressed != null) {
|
|
||||||
widget.onPressed!();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onTapUp: (_) {},
|
|
||||||
child: widget.builder(context, _mouseState),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
|
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
|
||||||
import 'package:spotube/components/button/back_button.dart';
|
import 'package:spotube/components/button/back_button.dart';
|
||||||
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';
|
||||||
@ -49,7 +50,7 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget {
|
|||||||
this.height,
|
this.height,
|
||||||
this.surfaceBlur,
|
this.surfaceBlur,
|
||||||
this.surfaceOpacity,
|
this.surfaceOpacity,
|
||||||
this.useSafeArea = true,
|
this.useSafeArea = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
void onDrag(WidgetRef ref) {
|
void onDrag(WidgetRef ref) {
|
||||||
@ -66,7 +67,7 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget {
|
|||||||
final lastClicked = useRef<int>(DateTime.now().millisecondsSinceEpoch);
|
final lastClicked = useRef<int>(DateTime.now().millisecondsSinceEpoch);
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: height ?? 56,
|
height: height ?? (48 * context.theme.scaling),
|
||||||
child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
final hasFullscreen =
|
final hasFullscreen =
|
||||||
@ -102,18 +103,22 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget {
|
|||||||
: leading,
|
: leading,
|
||||||
trailing: [
|
trailing: [
|
||||||
...trailing,
|
...trailing,
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topRight,
|
||||||
|
child:
|
||||||
WindowTitleBarButtons(foregroundColor: foregroundColor),
|
WindowTitleBarButtons(foregroundColor: foregroundColor),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
title: title,
|
title: title,
|
||||||
header: header,
|
header: header,
|
||||||
subtitle: subtitle,
|
subtitle: subtitle,
|
||||||
trailingExpanded: trailingExpanded,
|
trailingExpanded: trailingExpanded,
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
padding: padding,
|
padding: padding ?? EdgeInsets.zero,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
leadingGap: leadingGap,
|
leadingGap: leadingGap,
|
||||||
trailingGap: trailingGap,
|
trailingGap: trailingGap,
|
||||||
height: height,
|
height: height ?? (48 * context.theme.scaling),
|
||||||
surfaceBlur: surfaceBlur,
|
surfaceBlur: surfaceBlur,
|
||||||
surfaceOpacity: surfaceOpacity,
|
surfaceOpacity: surfaceOpacity,
|
||||||
useSafeArea: useSafeArea,
|
useSafeArea: useSafeArea,
|
||||||
@ -127,5 +132,5 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Size get preferredSize => Size.fromHeight(height ?? 56.0);
|
Size get preferredSize => Size.fromHeight(height ?? 48);
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.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:spotube/components/hover_builder.dart';
|
||||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||||
import 'package:spotube/components/titlebar/titlebar_icon_buttons.dart';
|
import 'package:spotube/components/titlebar/titlebar_icon_buttons.dart';
|
||||||
import 'package:spotube/components/titlebar/window_button.dart';
|
|
||||||
|
import 'package:spotube/hooks/configurators/use_window_listener.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:titlebar_buttons/titlebar_buttons.dart';
|
import 'package:titlebar_buttons/titlebar_buttons.dart';
|
||||||
@ -22,12 +24,20 @@ class WindowTitleBarButtons extends HookConsumerWidget {
|
|||||||
final preferences = ref.watch(userPreferencesProvider);
|
final preferences = ref.watch(userPreferencesProvider);
|
||||||
final isMaximized = useState<bool?>(null);
|
final isMaximized = useState<bool?>(null);
|
||||||
const type = ThemeType.auto;
|
const type = ThemeType.auto;
|
||||||
final scale = context.theme.scaling;
|
|
||||||
|
|
||||||
Future<void> onClose() async {
|
Future<void> onClose() async {
|
||||||
await windowManager.close();
|
await windowManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useWindowListener(
|
||||||
|
onWindowMaximize: () {
|
||||||
|
isMaximized.value = true;
|
||||||
|
},
|
||||||
|
onWindowUnmaximize: () {
|
||||||
|
isMaximized.value = false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
if (kIsDesktop) {
|
if (kIsDesktop) {
|
||||||
windowManager.isMaximized().then((value) {
|
windowManager.isMaximized().then((value) {
|
||||||
@ -42,62 +52,45 @@ class WindowTitleBarButtons extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (kIsWindows) {
|
if (kIsWindows) {
|
||||||
final theme = Theme.of(context);
|
return Row(
|
||||||
final colors = WindowButtonColors(
|
|
||||||
normal: Colors.transparent,
|
|
||||||
iconNormal: foregroundColor ?? theme.colorScheme.onSurface,
|
|
||||||
mouseOver: theme.colorScheme.onSurface.withAlpha(25),
|
|
||||||
mouseDown: theme.colorScheme.onSurface.withAlpha(51),
|
|
||||||
iconMouseOver: theme.colorScheme.onSurface,
|
|
||||||
iconMouseDown: theme.colorScheme.onSurface,
|
|
||||||
);
|
|
||||||
|
|
||||||
final closeColors = WindowButtonColors(
|
|
||||||
normal: Colors.transparent,
|
|
||||||
iconNormal: foregroundColor ?? theme.colorScheme.onSurface,
|
|
||||||
mouseOver: Colors.red,
|
|
||||||
mouseDown: Colors.red[800]!,
|
|
||||||
iconMouseOver: Colors.white,
|
|
||||||
iconMouseDown: Colors.black,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Transform(
|
|
||||||
transform: Matrix4.translationValues(18, -12, 0) * scale,
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
MinimizeWindowButton(
|
ShadcnWindowButton(
|
||||||
|
icon: MinimizeIcon(color: context.theme.colorScheme.foreground),
|
||||||
onPressed: windowManager.minimize,
|
onPressed: windowManager.minimize,
|
||||||
colors: colors,
|
|
||||||
),
|
),
|
||||||
if (isMaximized.value != true)
|
if (isMaximized.value != true)
|
||||||
MaximizeWindowButton(
|
ShadcnWindowButton(
|
||||||
colors: colors,
|
icon: MaximizeIcon(color: context.theme.colorScheme.foreground),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
windowManager.maximize();
|
windowManager.maximize();
|
||||||
isMaximized.value = true;
|
isMaximized.value = true;
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
RestoreWindowButton(
|
ShadcnWindowButton(
|
||||||
colors: colors,
|
icon: RestoreIcon(color: context.theme.colorScheme.foreground),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
windowManager.unmaximize();
|
windowManager.unmaximize();
|
||||||
isMaximized.value = false;
|
isMaximized.value = false;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
CloseWindowButton(
|
HoverBuilder(builder: (context, isHovered) {
|
||||||
colors: closeColors,
|
return ShadcnWindowButton(
|
||||||
|
icon: CloseIcon(
|
||||||
|
color: isHovered
|
||||||
|
? Colors.white
|
||||||
|
: context.theme.colorScheme.foreground,
|
||||||
|
),
|
||||||
onPressed: onClose,
|
onPressed: onClose,
|
||||||
),
|
hoverBackgroundColor: const Color(0xFFD32F2F),
|
||||||
|
);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Transform(
|
return Row(
|
||||||
transform: Matrix4.translationValues(18, -12, 0) * scale,
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
DecoratedMinimizeButton(
|
DecoratedMinimizeButton(
|
||||||
@ -121,7 +114,6 @@ class WindowTitleBarButtons extends HookConsumerWidget {
|
|||||||
onPressed: onClose,
|
onPressed: onClose,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,56 +1,50 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:spotube/components/titlebar/window_button.dart';
|
import 'package:spotube/extensions/button_variance.dart';
|
||||||
|
|
||||||
class MinimizeWindowButton extends WindowButton {
|
class ShadcnWindowButton extends StatelessWidget {
|
||||||
MinimizeWindowButton(
|
final Widget icon;
|
||||||
{super.key, super.colors, super.onPressed, bool? animate})
|
final VoidCallback onPressed;
|
||||||
: super(
|
final Color? hoverBackgroundColor;
|
||||||
animate: animate ?? false,
|
|
||||||
iconBuilder: (buttonContext) =>
|
const ShadcnWindowButton({
|
||||||
MinimizeIcon(color: buttonContext.iconColor),
|
super.key,
|
||||||
|
required this.icon,
|
||||||
|
required this.onPressed,
|
||||||
|
this.hoverBackgroundColor,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 45,
|
||||||
|
height: 32,
|
||||||
|
child: IconButton(
|
||||||
|
variance: ButtonVariance.ghost.copyWith(
|
||||||
|
decoration: (context, states) {
|
||||||
|
final decoration = ButtonVariance.ghost.decoration(context, states)
|
||||||
|
as BoxDecoration;
|
||||||
|
if (hoverBackgroundColor != null &&
|
||||||
|
states.contains(WidgetState.hovered)) {
|
||||||
|
return decoration.copyWith(
|
||||||
|
borderRadius: BorderRadius.zero,
|
||||||
|
color: hoverBackgroundColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MaximizeWindowButton extends WindowButton {
|
return decoration.copyWith(
|
||||||
MaximizeWindowButton(
|
borderRadius: BorderRadius.zero,
|
||||||
{super.key, super.colors, super.onPressed, bool? animate})
|
);
|
||||||
: super(
|
},
|
||||||
animate: animate ?? false,
|
),
|
||||||
iconBuilder: (buttonContext) =>
|
icon: icon,
|
||||||
MaximizeIcon(color: buttonContext.iconColor),
|
onPressed: onPressed,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class RestoreWindowButton extends WindowButton {
|
|
||||||
RestoreWindowButton({super.key, super.colors, super.onPressed, bool? animate})
|
|
||||||
: super(
|
|
||||||
animate: animate ?? false,
|
|
||||||
iconBuilder: (buttonContext) =>
|
|
||||||
RestoreIcon(color: buttonContext.iconColor),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final _defaultCloseButtonColors = WindowButtonColors(
|
|
||||||
mouseOver: const Color(0xFFD32F2F),
|
|
||||||
mouseDown: const Color(0xFFB71C1C),
|
|
||||||
iconNormal: const Color(0xFF805306),
|
|
||||||
iconMouseOver: const Color(0xFFFFFFFF));
|
|
||||||
|
|
||||||
class CloseWindowButton extends WindowButton {
|
|
||||||
CloseWindowButton(
|
|
||||||
{super.key, WindowButtonColors? colors, super.onPressed, bool? animate})
|
|
||||||
: super(
|
|
||||||
colors: colors ?? _defaultCloseButtonColors,
|
|
||||||
animate: animate ?? false,
|
|
||||||
iconBuilder: (buttonContext) =>
|
|
||||||
CloseIcon(color: buttonContext.iconColor),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switched to CustomPaint icons by https://github.com/esDotDev
|
|
||||||
|
|
||||||
/// Close
|
/// Close
|
||||||
class CloseIcon extends StatelessWidget {
|
class CloseIcon extends StatelessWidget {
|
||||||
final Color color;
|
final Color color;
|
||||||
@ -150,7 +144,8 @@ class _AlignedPaint extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: CustomPaint(size: const Size(10, 10), painter: painter));
|
child: CustomPaint(size: const Size(10, 10), painter: painter),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
|
||||||
import 'package:spotube/components/titlebar/mouse_state.dart';
|
|
||||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
|
||||||
|
|
||||||
typedef WindowButtonIconBuilder = Widget Function(
|
|
||||||
WindowButtonContext buttonContext);
|
|
||||||
typedef WindowButtonBuilder = Widget Function(
|
|
||||||
WindowButtonContext buttonContext, Widget icon);
|
|
||||||
|
|
||||||
class WindowButtonContext {
|
|
||||||
BuildContext context;
|
|
||||||
MouseState mouseState;
|
|
||||||
Color? backgroundColor;
|
|
||||||
Color iconColor;
|
|
||||||
WindowButtonContext(
|
|
||||||
{required this.context,
|
|
||||||
required this.mouseState,
|
|
||||||
this.backgroundColor,
|
|
||||||
required this.iconColor});
|
|
||||||
}
|
|
||||||
|
|
||||||
class WindowButtonColors {
|
|
||||||
late Color normal;
|
|
||||||
late Color mouseOver;
|
|
||||||
late Color mouseDown;
|
|
||||||
late Color iconNormal;
|
|
||||||
late Color iconMouseOver;
|
|
||||||
late Color iconMouseDown;
|
|
||||||
WindowButtonColors(
|
|
||||||
{Color? normal,
|
|
||||||
Color? mouseOver,
|
|
||||||
Color? mouseDown,
|
|
||||||
Color? iconNormal,
|
|
||||||
Color? iconMouseOver,
|
|
||||||
Color? iconMouseDown}) {
|
|
||||||
this.normal = normal ?? _defaultButtonColors.normal;
|
|
||||||
this.mouseOver = mouseOver ?? _defaultButtonColors.mouseOver;
|
|
||||||
this.mouseDown = mouseDown ?? _defaultButtonColors.mouseDown;
|
|
||||||
this.iconNormal = iconNormal ?? _defaultButtonColors.iconNormal;
|
|
||||||
this.iconMouseOver = iconMouseOver ?? _defaultButtonColors.iconMouseOver;
|
|
||||||
this.iconMouseDown = iconMouseDown ?? _defaultButtonColors.iconMouseDown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final _defaultButtonColors = WindowButtonColors(
|
|
||||||
normal: Colors.transparent,
|
|
||||||
iconNormal: const Color(0xFF805306),
|
|
||||||
mouseOver: const Color(0xFF404040),
|
|
||||||
mouseDown: const Color(0xFF202020),
|
|
||||||
iconMouseOver: const Color(0xFFFFFFFF),
|
|
||||||
iconMouseDown: const Color(0xFFF0F0F0),
|
|
||||||
);
|
|
||||||
|
|
||||||
class WindowButton extends StatelessWidget {
|
|
||||||
final WindowButtonBuilder? builder;
|
|
||||||
final WindowButtonIconBuilder? iconBuilder;
|
|
||||||
late final WindowButtonColors colors;
|
|
||||||
final bool animate;
|
|
||||||
final EdgeInsets? padding;
|
|
||||||
final VoidCallback? onPressed;
|
|
||||||
|
|
||||||
WindowButton(
|
|
||||||
{super.key,
|
|
||||||
WindowButtonColors? colors,
|
|
||||||
this.builder,
|
|
||||||
@required this.iconBuilder,
|
|
||||||
this.padding,
|
|
||||||
this.onPressed,
|
|
||||||
this.animate = false}) {
|
|
||||||
this.colors = colors ?? _defaultButtonColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color getBackgroundColor(MouseState mouseState) {
|
|
||||||
if (mouseState.isMouseDown) return colors.mouseDown;
|
|
||||||
if (mouseState.isMouseOver) return colors.mouseOver;
|
|
||||||
return colors.normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color getIconColor(MouseState mouseState) {
|
|
||||||
if (mouseState.isMouseDown) return colors.iconMouseDown;
|
|
||||||
if (mouseState.isMouseOver) return colors.iconMouseOver;
|
|
||||||
return colors.iconNormal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (!kTitlebarVisible) return const SizedBox.shrink();
|
|
||||||
|
|
||||||
return MouseStateBuilder(
|
|
||||||
builder: (context, mouseState) {
|
|
||||||
WindowButtonContext buttonContext = WindowButtonContext(
|
|
||||||
mouseState: mouseState,
|
|
||||||
context: context,
|
|
||||||
backgroundColor: getBackgroundColor(mouseState),
|
|
||||||
iconColor: getIconColor(mouseState));
|
|
||||||
|
|
||||||
var icon = (iconBuilder != null)
|
|
||||||
? iconBuilder!(buttonContext)
|
|
||||||
: const SizedBox();
|
|
||||||
|
|
||||||
var fadeOutColor =
|
|
||||||
getBackgroundColor(MouseState()..isMouseOver = true).withAlpha(0);
|
|
||||||
var padding = this.padding ?? const EdgeInsets.all(10);
|
|
||||||
var animationMs =
|
|
||||||
mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0);
|
|
||||||
Widget iconWithPadding = Padding(padding: padding, child: icon);
|
|
||||||
iconWithPadding = AnimatedContainer(
|
|
||||||
curve: Curves.easeOut,
|
|
||||||
duration: Duration(milliseconds: animationMs),
|
|
||||||
color: buttonContext.backgroundColor ?? fadeOutColor,
|
|
||||||
child: iconWithPadding);
|
|
||||||
var button =
|
|
||||||
(builder != null) ? builder!(buttonContext, icon) : iconWithPadding;
|
|
||||||
return SizedBox(
|
|
||||||
width: 45,
|
|
||||||
height: 32,
|
|
||||||
child: button,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onPressed: () {
|
|
||||||
if (onPressed != null) onPressed!();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -207,7 +207,9 @@ class Spotube extends HookConsumerWidget {
|
|||||||
child: child!,
|
child: child!,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (kIsDesktop && !kIsMacOS) child = DragToResizeArea(child: child);
|
if (kIsLinux) {
|
||||||
|
child = DragToResizeArea(child: child);
|
||||||
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
},
|
},
|
||||||
|
@ -36,7 +36,7 @@ class HomePage extends HookConsumerWidget {
|
|||||||
bottom: false,
|
bottom: false,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
headers: [
|
headers: [
|
||||||
if (kTitlebarVisible) const TitleBar(),
|
if (kTitlebarVisible) const TitleBar(height: 30),
|
||||||
],
|
],
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
@ -2,8 +2,6 @@ import 'package:flutter/material.dart' show Badge;
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
|
|
||||||
|
|
||||||
import 'package:spotube/modules/library/user_local_tracks.dart';
|
import 'package:spotube/modules/library/user_local_tracks.dart';
|
||||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||||
import 'package:spotube/modules/library/user_albums.dart';
|
import 'package:spotube/modules/library/user_albums.dart';
|
||||||
@ -19,7 +17,6 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
const LibraryPage({super.key});
|
const LibraryPage({super.key});
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final scale = context.theme.scaling;
|
|
||||||
final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount;
|
final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount;
|
||||||
final index = useState(0);
|
final index = useState(0);
|
||||||
|
|
||||||
@ -40,11 +37,6 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
headers: [
|
headers: [
|
||||||
TitleBar(
|
TitleBar(
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 18,
|
|
||||||
vertical: 12,
|
|
||||||
).copyWith(left: 0) *
|
|
||||||
scale,
|
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: TabList(
|
child: TabList(
|
||||||
|
@ -151,6 +151,8 @@ class LyricsPage extends HookConsumerWidget {
|
|||||||
? TitleBar(
|
? TitleBar(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
title: tabbar,
|
title: tabbar,
|
||||||
|
height: 58 * context.theme.scaling,
|
||||||
|
surfaceBlur: 0,
|
||||||
)
|
)
|
||||||
: tabbar
|
: tabbar
|
||||||
],
|
],
|
||||||
|
@ -70,7 +70,8 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
bottom: false,
|
bottom: false,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
headers: [
|
headers: [
|
||||||
if (kTitlebarVisible) const TitleBar(automaticallyImplyLeading: true)
|
if (kTitlebarVisible)
|
||||||
|
const TitleBar(automaticallyImplyLeading: true, height: 30)
|
||||||
],
|
],
|
||||||
child: auth.asData?.value == null
|
child: auth.asData?.value == null
|
||||||
? const AnonymousFallback()
|
? const AnonymousFallback()
|
||||||
|
Loading…
Reference in New Issue
Block a user