fix: track view header title overflow and player view drag glitch

This commit is contained in:
Kingkor Roy Tirtho 2023-12-08 14:46:27 +06:00
parent 581b241f99
commit b04d8849e7
6 changed files with 156 additions and 116 deletions

View File

@ -28,9 +28,11 @@ import 'package:spotube/utils/type_conversion_utils.dart';
class PlayerView extends HookConsumerWidget { class PlayerView extends HookConsumerWidget {
final PanelController panelController; final PanelController panelController;
final ScrollController scrollController;
const PlayerView({ const PlayerView({
Key? key, Key? key,
required this.panelController, required this.panelController,
required this.scrollController,
}) : super(key: key); }) : super(key: key);
@override @override
@ -119,40 +121,43 @@ class PlayerView extends HookConsumerWidget {
preferredSize: Size.fromHeight( preferredSize: Size.fromHeight(
kToolbarHeight + topPadding, kToolbarHeight + topPadding,
), ),
child: Padding( child: ForceDraggableWidget(
padding: EdgeInsets.only(top: topPadding), child: Padding(
child: PageWindowTitleBar( padding: EdgeInsets.only(top: topPadding),
backgroundColor: Colors.transparent, child: PageWindowTitleBar(
foregroundColor: titleTextColor, backgroundColor: Colors.transparent,
toolbarOpacity: 1, foregroundColor: titleTextColor,
leading: IconButton( toolbarOpacity: 1,
icon: const Icon(SpotubeIcons.angleDown, size: 18), leading: IconButton(
onPressed: panelController.close, 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, extendBodyBehindAppBar: true,
body: SingleChildScrollView( body: SingleChildScrollView(
controller: scrollController,
child: Container( child: Container(
alignment: Alignment.center, alignment: Alignment.center,
width: double.infinity, width: double.infinity,
@ -163,27 +168,29 @@ class PlayerView extends HookConsumerWidget {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Column( child: Column(
children: [ children: [
Container( ForceDraggableWidget(
margin: const EdgeInsets.all(8), child: Container(
constraints: const BoxConstraints( margin: const EdgeInsets.all(8),
maxHeight: 300, maxWidth: 300), constraints: const BoxConstraints(
decoration: BoxDecoration( maxHeight: 300, maxWidth: 300),
borderRadius: BorderRadius.circular(20), decoration: BoxDecoration(
boxShadow: const [ borderRadius: BorderRadius.circular(20),
BoxShadow( boxShadow: const [
color: Colors.black26, BoxShadow(
spreadRadius: 2, color: Colors.black26,
blurRadius: 10, spreadRadius: 2,
offset: Offset(0, 0), 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,
), ),
), ),
), ),

View File

@ -43,6 +43,7 @@ class PlayerOverlay extends HookConsumerWidget {
final mediaQuery = MediaQuery.of(context); final mediaQuery = MediaQuery.of(context);
final panelController = useMemoized(() => PanelController(), []); final panelController = useMemoized(() => PanelController(), []);
final scrollController = useScrollController();
useEffect(() { useEffect(() {
return () { return () {
@ -174,6 +175,7 @@ class PlayerOverlay extends HookConsumerWidget {
), ),
), ),
), ),
scrollController: scrollController,
panelBuilder: (position) { panelBuilder: (position) {
// this is the reason we're getting an update // this is the reason we're getting an update
final navigationHeight = ref.watch(navigationPanelHeight); final navigationHeight = ref.watch(navigationPanelHeight);
@ -188,8 +190,11 @@ class PlayerOverlay extends HookConsumerWidget {
decoration: navigationHeight == 0 decoration: navigationHeight == 0
? const BoxDecoration(borderRadius: BorderRadius.zero) ? const BoxDecoration(borderRadius: BorderRadius.zero)
: const BoxDecoration(borderRadius: radius), : const BoxDecoration(borderRadius: radius),
child: HorizontalScrollableWidget( child: IgnoreDraggableWidget(
child: PlayerView(panelController: panelController), child: PlayerView(
panelController: panelController,
scrollController: scrollController,
),
), ),
), ),
); );

View File

@ -90,17 +90,19 @@ class PlaybuttonCard extends HookWidget {
Stack( Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
children: [ children: [
Padding( Container(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 8, left: 8,
right: 8, right: 8,
top: 8, top: 8,
), ),
constraints: BoxConstraints(maxHeight: size),
child: ClipRRect( child: ClipRRect(
borderRadius: radius, borderRadius: radius,
child: UniversalImage( child: UniversalImage(
path: imageUrl, path: imageUrl,
placeholder: Assets.albumPlaceholder.path, placeholder: Assets.albumPlaceholder.path,
fit: BoxFit.cover,
), ),
), ),
), ),

View File

@ -4,6 +4,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; 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:skeletonizer/skeletonizer.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/shared/hover_builder.dart'; import 'package:spotube/components/shared/hover_builder.dart';
@ -158,26 +159,28 @@ class TrackTile extends HookConsumerWidget {
child: IconTheme( child: IconTheme(
data: theme.iconTheme data: theme.iconTheme
.copyWith(size: 26, color: Colors.white), .copyWith(size: 26, color: Colors.white),
child: AnimatedSwitcher( child: Skeleton.ignore(
duration: const Duration(milliseconds: 300), child: AnimatedSwitcher(
child: (isPlaying && playlist.isFetching) || duration: const Duration(milliseconds: 300),
isLoading.value child: (isPlaying && playlist.isFetching) ||
? const SizedBox( isLoading.value
width: 26, ? const SizedBox(
height: 26, width: 26,
child: CircularProgressIndicator( height: 26,
strokeWidth: 1.5, child: CircularProgressIndicator(
color: Colors.white, strokeWidth: 1.5,
), color: Colors.white,
) ),
: isPlaying )
? Icon( : isPlaying
SpotubeIcons.pause, ? Icon(
color: theme.colorScheme.primary, SpotubeIcons.pause,
) color: theme.colorScheme.primary,
: !isHovering )
? const SizedBox.shrink() : !isHovering
: const Icon(SpotubeIcons.play), ? const SizedBox.shrink()
: const Icon(SpotubeIcons.play),
),
), ),
), ),
), ),

View File

@ -93,9 +93,14 @@ class TrackViewBodySection extends HookConsumerWidget {
index: 0, index: 0,
), ),
), ),
emptyBuilder: (context) => const Row( emptyBuilder: (context) => Skeletonizer(
mainAxisAlignment: MainAxisAlignment.center, enabled: true,
children: [NotFound()], child: Column(
children: List.generate(
10,
(index) => TrackTile(track: FakeData.track, index: index),
),
),
), ),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final track = tracks[index]; final track = tracks[index];

View File

@ -88,50 +88,68 @@ class TrackViewFlexHeader extends HookConsumerWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Flex( ConstrainedBox(
direction: mediaQuery.mdAndDown constraints: BoxConstraints(
? Axis.vertical maxWidth: mediaQuery.mdAndDown
: Axis.horizontal, ? mediaQuery.size.width
mainAxisSize: MainAxisSize.min, : 800,
children: [ ),
ClipRRect( child: Flex(
borderRadius: BorderRadius.circular(10), direction: mediaQuery.mdAndDown
child: UniversalImage( ? Axis.vertical
path: props.image, : Axis.horizontal,
width: 200, mainAxisSize: MainAxisSize.min,
height: 200, children: [
placeholder: Assets.albumPlaceholder.path, ClipRRect(
borderRadius: BorderRadius.circular(10),
child: UniversalImage(
path: props.image,
width: 200,
height: 200,
placeholder: Assets.albumPlaceholder.path,
),
), ),
), const Gap(20),
const Gap(20), Flexible(
Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: mediaQuery.mdAndDown crossAxisAlignment: mediaQuery.mdAndDown
? CrossAxisAlignment.center ? CrossAxisAlignment.center
: CrossAxisAlignment.start, : CrossAxisAlignment.start,
children: [ children: [
Text(props.title, style: headingStyle), Text(
const SizedBox(height: 10), props.title,
if (description != null && style: headingStyle,
description.isNotEmpty) textAlign: mediaQuery.mdAndDown
Text( ? TextAlign.center
description, : TextAlign.start,
style: defaultTextStyle.style.copyWith( maxLines: 2,
color: palette.bodyTextColor, overflow: TextOverflow.ellipsis,
), ),
textAlign: mediaQuery.mdAndDown const SizedBox(height: 10),
? TextAlign.center if (description != null &&
: TextAlign.start, description.isNotEmpty)
maxLines: 2, Text(
overflow: TextOverflow.ellipsis, description,
), style:
const Gap(10), defaultTextStyle.style.copyWith(
const TrackViewHeaderActions(), color: palette.bodyTextColor,
const Gap(10), ),
TrackViewHeaderButtons(color: palette), textAlign: mediaQuery.mdAndDown
], ? TextAlign.center
), : TextAlign.start,
], maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const Gap(10),
const TrackViewHeaderActions(),
const Gap(10),
TrackViewHeaderButtons(color: palette),
],
),
),
],
),
), ),
], ],
), ),