mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-14 00:15:17 +00:00
fix: track view header title overflow and player view drag glitch
This commit is contained in:
parent
581b241f99
commit
b04d8849e7
@ -28,9 +28,11 @@ import 'package:spotube/utils/type_conversion_utils.dart';
|
||||
|
||||
class PlayerView extends HookConsumerWidget {
|
||||
final PanelController panelController;
|
||||
final ScrollController scrollController;
|
||||
const PlayerView({
|
||||
Key? key,
|
||||
required this.panelController,
|
||||
required this.scrollController,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -119,40 +121,43 @@ class PlayerView extends HookConsumerWidget {
|
||||
preferredSize: Size.fromHeight(
|
||||
kToolbarHeight + topPadding,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: topPadding),
|
||||
child: PageWindowTitleBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: titleTextColor,
|
||||
toolbarOpacity: 1,
|
||||
leading: IconButton(
|
||||
icon: const Icon(SpotubeIcons.angleDown, size: 18),
|
||||
onPressed: panelController.close,
|
||||
child: ForceDraggableWidget(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: topPadding),
|
||||
child: PageWindowTitleBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: titleTextColor,
|
||||
toolbarOpacity: 1,
|
||||
leading: IconButton(
|
||||
icon: const Icon(SpotubeIcons.angleDown, size: 18),
|
||||
onPressed: panelController.close,
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(SpotubeIcons.info, size: 18),
|
||||
tooltip: context.l10n.details,
|
||||
style: IconButton.styleFrom(
|
||||
foregroundColor: bodyTextColor),
|
||||
onPressed: currentTrack == null
|
||||
? null
|
||||
: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return TrackDetailsDialog(
|
||||
track: currentTrack,
|
||||
);
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(SpotubeIcons.info, size: 18),
|
||||
tooltip: context.l10n.details,
|
||||
style:
|
||||
IconButton.styleFrom(foregroundColor: bodyTextColor),
|
||||
onPressed: currentTrack == null
|
||||
? null
|
||||
: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return TrackDetailsDialog(
|
||||
track: currentTrack,
|
||||
);
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
extendBodyBehindAppBar: true,
|
||||
body: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: double.infinity,
|
||||
@ -163,27 +168,29 @@ class PlayerView extends HookConsumerWidget {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.all(8),
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 300, maxWidth: 300),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black26,
|
||||
spreadRadius: 2,
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 0),
|
||||
ForceDraggableWidget(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8),
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 300, maxWidth: 300),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black26,
|
||||
spreadRadius: 2,
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 0),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: UniversalImage(
|
||||
path: albumArt,
|
||||
placeholder: Assets.albumPlaceholder.path,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: UniversalImage(
|
||||
path: albumArt,
|
||||
placeholder: Assets.albumPlaceholder.path,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -43,6 +43,7 @@ class PlayerOverlay extends HookConsumerWidget {
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
|
||||
final panelController = useMemoized(() => PanelController(), []);
|
||||
final scrollController = useScrollController();
|
||||
|
||||
useEffect(() {
|
||||
return () {
|
||||
@ -174,6 +175,7 @@ class PlayerOverlay extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
scrollController: scrollController,
|
||||
panelBuilder: (position) {
|
||||
// this is the reason we're getting an update
|
||||
final navigationHeight = ref.watch(navigationPanelHeight);
|
||||
@ -188,8 +190,11 @@ class PlayerOverlay extends HookConsumerWidget {
|
||||
decoration: navigationHeight == 0
|
||||
? const BoxDecoration(borderRadius: BorderRadius.zero)
|
||||
: const BoxDecoration(borderRadius: radius),
|
||||
child: HorizontalScrollableWidget(
|
||||
child: PlayerView(panelController: panelController),
|
||||
child: IgnoreDraggableWidget(
|
||||
child: PlayerView(
|
||||
panelController: panelController,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -90,17 +90,19 @@ class PlaybuttonCard extends HookWidget {
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Padding(
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 8,
|
||||
right: 8,
|
||||
top: 8,
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: size),
|
||||
child: ClipRRect(
|
||||
borderRadius: radius,
|
||||
child: UniversalImage(
|
||||
path: imageUrl,
|
||||
placeholder: Assets.albumPlaceholder.path,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -4,6 +4,7 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/shared/hover_builder.dart';
|
||||
@ -158,26 +159,28 @@ class TrackTile extends HookConsumerWidget {
|
||||
child: IconTheme(
|
||||
data: theme.iconTheme
|
||||
.copyWith(size: 26, color: Colors.white),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: (isPlaying && playlist.isFetching) ||
|
||||
isLoading.value
|
||||
? const SizedBox(
|
||||
width: 26,
|
||||
height: 26,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 1.5,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: isPlaying
|
||||
? Icon(
|
||||
SpotubeIcons.pause,
|
||||
color: theme.colorScheme.primary,
|
||||
)
|
||||
: !isHovering
|
||||
? const SizedBox.shrink()
|
||||
: const Icon(SpotubeIcons.play),
|
||||
child: Skeleton.ignore(
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: (isPlaying && playlist.isFetching) ||
|
||||
isLoading.value
|
||||
? const SizedBox(
|
||||
width: 26,
|
||||
height: 26,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 1.5,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: isPlaying
|
||||
? Icon(
|
||||
SpotubeIcons.pause,
|
||||
color: theme.colorScheme.primary,
|
||||
)
|
||||
: !isHovering
|
||||
? const SizedBox.shrink()
|
||||
: const Icon(SpotubeIcons.play),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -93,9 +93,14 @@ class TrackViewBodySection extends HookConsumerWidget {
|
||||
index: 0,
|
||||
),
|
||||
),
|
||||
emptyBuilder: (context) => const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [NotFound()],
|
||||
emptyBuilder: (context) => Skeletonizer(
|
||||
enabled: true,
|
||||
child: Column(
|
||||
children: List.generate(
|
||||
10,
|
||||
(index) => TrackTile(track: FakeData.track, index: index),
|
||||
),
|
||||
),
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
final track = tracks[index];
|
||||
|
@ -88,50 +88,68 @@ class TrackViewFlexHeader extends HookConsumerWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Flex(
|
||||
direction: mediaQuery.mdAndDown
|
||||
? Axis.vertical
|
||||
: Axis.horizontal,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: UniversalImage(
|
||||
path: props.image,
|
||||
width: 200,
|
||||
height: 200,
|
||||
placeholder: Assets.albumPlaceholder.path,
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: mediaQuery.mdAndDown
|
||||
? mediaQuery.size.width
|
||||
: 800,
|
||||
),
|
||||
child: Flex(
|
||||
direction: mediaQuery.mdAndDown
|
||||
? Axis.vertical
|
||||
: Axis.horizontal,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: UniversalImage(
|
||||
path: props.image,
|
||||
width: 200,
|
||||
height: 200,
|
||||
placeholder: Assets.albumPlaceholder.path,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Gap(20),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: mediaQuery.mdAndDown
|
||||
? CrossAxisAlignment.center
|
||||
: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(props.title, style: headingStyle),
|
||||
const SizedBox(height: 10),
|
||||
if (description != null &&
|
||||
description.isNotEmpty)
|
||||
Text(
|
||||
description,
|
||||
style: defaultTextStyle.style.copyWith(
|
||||
color: palette.bodyTextColor,
|
||||
const Gap(20),
|
||||
Flexible(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: mediaQuery.mdAndDown
|
||||
? CrossAxisAlignment.center
|
||||
: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
props.title,
|
||||
style: headingStyle,
|
||||
textAlign: mediaQuery.mdAndDown
|
||||
? TextAlign.center
|
||||
: TextAlign.start,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
textAlign: mediaQuery.mdAndDown
|
||||
? TextAlign.center
|
||||
: TextAlign.start,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const Gap(10),
|
||||
const TrackViewHeaderActions(),
|
||||
const Gap(10),
|
||||
TrackViewHeaderButtons(color: palette),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 10),
|
||||
if (description != null &&
|
||||
description.isNotEmpty)
|
||||
Text(
|
||||
description,
|
||||
style:
|
||||
defaultTextStyle.style.copyWith(
|
||||
color: palette.bodyTextColor,
|
||||
),
|
||||
textAlign: mediaQuery.mdAndDown
|
||||
? TextAlign.center
|
||||
: TextAlign.start,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const Gap(10),
|
||||
const TrackViewHeaderActions(),
|
||||
const Gap(10),
|
||||
TrackViewHeaderButtons(color: palette),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user