mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
fix: track_tile active and blacklist color, playbutton card action positioning
This commit is contained in:
parent
20c424c77f
commit
3f5a1b9587
@ -50,7 +50,11 @@ class UserAlbums extends HookConsumerWidget {
|
|||||||
return const AnonymousFallback();
|
return const AnonymousFallback();
|
||||||
}
|
}
|
||||||
if (albumsQuery.isLoading || !albumsQuery.hasData) {
|
if (albumsQuery.isLoading || !albumsQuery.hasData) {
|
||||||
return const Center(child: ShimmerPlaybuttonCard(count: 7));
|
return Container(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: const ShimmerPlaybuttonCard(count: 7),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
@ -63,6 +67,7 @@ class UserAlbums extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
TextField(
|
TextField(
|
||||||
onChanged: (value) => searchText.value = value,
|
onChanged: (value) => searchText.value = value,
|
||||||
|
@ -7,6 +7,7 @@ import 'package:spotube/collections/spotube_icons.dart';
|
|||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
import 'package:spotube/hooks/use_breakpoint_value.dart';
|
import 'package:spotube/hooks/use_breakpoint_value.dart';
|
||||||
import 'package:spotube/hooks/use_brightness_value.dart';
|
import 'package:spotube/hooks/use_brightness_value.dart';
|
||||||
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
|
||||||
class PlaybuttonCard extends HookWidget {
|
class PlaybuttonCard extends HookWidget {
|
||||||
final void Function()? onTap;
|
final void Function()? onTap;
|
||||||
@ -34,6 +35,7 @@ class PlaybuttonCard extends HookWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final textsKey = useMemoized(() => GlobalKey(), []);
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final radius = BorderRadius.circular(15);
|
final radius = BorderRadius.circular(15);
|
||||||
|
|
||||||
@ -41,15 +43,36 @@ class PlaybuttonCard extends HookWidget {
|
|||||||
sm: 130,
|
sm: 130,
|
||||||
md: 150,
|
md: 150,
|
||||||
others: 170,
|
others: 170,
|
||||||
);
|
) ??
|
||||||
|
170;
|
||||||
|
|
||||||
final end = useBreakpointValue<double>(
|
final end = useBreakpointValue<double>(
|
||||||
sm: 5,
|
sm: 15,
|
||||||
md: 7,
|
others: 20,
|
||||||
others: 10,
|
) ??
|
||||||
|
20;
|
||||||
|
|
||||||
|
final textsHeight = useState(
|
||||||
|
(textsKey.currentContext?.findRenderObject() as RenderBox?)
|
||||||
|
?.size
|
||||||
|
.height ??
|
||||||
|
110.00,
|
||||||
);
|
);
|
||||||
|
|
||||||
return Container(
|
useEffect(() {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
textsHeight.value =
|
||||||
|
(textsKey.currentContext?.findRenderObject() as RenderBox?)
|
||||||
|
?.size
|
||||||
|
.height ??
|
||||||
|
textsHeight.value;
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}, [textsKey]);
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
constraints: BoxConstraints(maxWidth: size),
|
constraints: BoxConstraints(maxWidth: size),
|
||||||
margin: margin,
|
margin: margin,
|
||||||
child: Material(
|
child: Material(
|
||||||
@ -70,16 +93,12 @@ class PlaybuttonCard extends HookWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Stack(
|
Padding(
|
||||||
clipBehavior: Clip.none,
|
padding: const EdgeInsets.only(
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
margin: 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(
|
||||||
@ -88,10 +107,45 @@ class PlaybuttonCard extends HookWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned.directional(
|
Column(
|
||||||
textDirection: TextDirection.ltr,
|
key: textsKey,
|
||||||
end: end,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
bottom: -size * .15,
|
children: [
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
|
child: AutoSizeText(
|
||||||
|
title,
|
||||||
|
maxLines: 1,
|
||||||
|
minFontSize: theme.textTheme.bodyMedium!.fontSize!,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (description != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
|
child: AutoSizeText(
|
||||||
|
description!,
|
||||||
|
maxLines: 2,
|
||||||
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
|
color:
|
||||||
|
theme.colorScheme.onSurface.withOpacity(.5),
|
||||||
|
),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AnimatedPositioned(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
right: end,
|
||||||
|
bottom: textsHeight.value - (kIsMobile ? 5 : 10),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@ -115,8 +169,7 @@ class PlaybuttonCard extends HookWidget {
|
|||||||
icon: isLoading
|
icon: isLoading
|
||||||
? SizedBox.fromSize(
|
? SizedBox.fromSize(
|
||||||
size: const Size.square(15),
|
size: const Size.square(15),
|
||||||
child: const CircularProgressIndicator(
|
child: const CircularProgressIndicator(strokeWidth: 2),
|
||||||
strokeWidth: 2),
|
|
||||||
)
|
)
|
||||||
: isPlaying
|
: isPlaying
|
||||||
? const Icon(SpotubeIcons.pause)
|
? const Icon(SpotubeIcons.pause)
|
||||||
@ -127,38 +180,6 @@ class PlaybuttonCard extends HookWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
const SizedBox(height: 15),
|
|
||||||
Flexible(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
|
||||||
child: AutoSizeText(
|
|
||||||
title,
|
|
||||||
maxLines: 1,
|
|
||||||
minFontSize: theme.textTheme.bodyMedium!.fontSize!,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (description != null)
|
|
||||||
Flexible(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
|
||||||
child: AutoSizeText(
|
|
||||||
description!,
|
|
||||||
maxLines: 2,
|
|
||||||
style: theme.textTheme.bodySmall?.copyWith(
|
|
||||||
color: theme.colorScheme.onSurface.withOpacity(.5),
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ class ShimmerArtistProfile extends HookWidget {
|
|||||||
lg: MediaQuery.of(context).size.width * 0.30,
|
lg: MediaQuery.of(context).size.width * 0.30,
|
||||||
xl: MediaQuery.of(context).size.width * 0.30,
|
xl: MediaQuery.of(context).size.width * 0.30,
|
||||||
xxl: MediaQuery.of(context).size.width * 0.30,
|
xxl: MediaQuery.of(context).size.width * 0.30,
|
||||||
);
|
) ??
|
||||||
|
0;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -51,7 +51,7 @@ class SortTracksDropdown extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
onSelected: onChanged,
|
onSelected: onChanged,
|
||||||
tooltip: "Sort tracks",
|
tooltip: "Sort tracks",
|
||||||
child: const Icon(SpotubeIcons.sort),
|
icon: const Icon(SpotubeIcons.sort),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,12 +100,13 @@ class TrackCollectionView<T> extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// play playlist
|
// play playlist
|
||||||
IconButton(
|
ElevatedButton(
|
||||||
style: IconButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: theme.colorScheme.primary,
|
shape: const CircleBorder(),
|
||||||
|
backgroundColor: theme.colorScheme.inversePrimary,
|
||||||
),
|
),
|
||||||
onPressed: tracksSnapshot.data != null ? onPlay : null,
|
onPressed: tracksSnapshot.data != null ? onPlay : null,
|
||||||
icon: Icon(isPlaying ? SpotubeIcons.stop : SpotubeIcons.play),
|
child: Icon(isPlaying ? SpotubeIcons.stop : SpotubeIcons.play),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
];
|
];
|
||||||
|
@ -179,18 +179,16 @@ class TrackTile extends HookConsumerWidget {
|
|||||||
return AnimatedContainer(
|
return AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isBlackListed
|
color: isActive
|
||||||
? Colors.red[100]
|
? theme.colorScheme.surfaceVariant.withOpacity(0.5)
|
||||||
: isActive
|
|
||||||
? theme.popupMenuTheme.color
|
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
borderRadius: BorderRadius.circular(isActive ? 10 : 0),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
child: Material(
|
child: Material(
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
if (showCheck)
|
if (showCheck && !isBlackListed)
|
||||||
Checkbox(
|
Checkbox(
|
||||||
value: isChecked,
|
value: isChecked,
|
||||||
onChanged: (s) => onCheckChange?.call(s),
|
onChanged: (s) => onCheckChange?.call(s),
|
||||||
@ -222,22 +220,21 @@ class TrackTile extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: IconButton(
|
child: ElevatedButton(
|
||||||
icon: Icon(
|
style: ElevatedButton.styleFrom(
|
||||||
playlist?.activeTrack.id == track.value.id
|
backgroundColor: theme.colorScheme.inversePrimary,
|
||||||
? SpotubeIcons.pause
|
shape: const CircleBorder(),
|
||||||
: SpotubeIcons.play,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
style: IconButton.styleFrom(
|
|
||||||
backgroundColor: theme.colorScheme.primary,
|
|
||||||
hoverColor: theme.colorScheme.primary.withOpacity(0.5),
|
|
||||||
),
|
),
|
||||||
onPressed: !isBlackListed
|
onPressed: !isBlackListed
|
||||||
? () => onTrackPlayButtonPressed?.call(
|
? () => onTrackPlayButtonPressed?.call(
|
||||||
track.value,
|
track.value,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
|
child: Icon(
|
||||||
|
playlist?.activeTrack.id == track.value.id
|
||||||
|
? SpotubeIcons.pause
|
||||||
|
: SpotubeIcons.play,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -197,7 +197,7 @@ class TracksTableView extends HookConsumerWidget {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Icon(SpotubeIcons.moreVertical),
|
icon: const Icon(SpotubeIcons.moreVertical),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
],
|
],
|
||||||
@ -205,12 +205,31 @@ class TracksTableView extends HookConsumerWidget {
|
|||||||
...sortedTracks.asMap().entries.map((track) {
|
...sortedTracks.asMap().entries.map((track) {
|
||||||
String duration =
|
String duration =
|
||||||
"${track.value.duration?.inMinutes.remainder(60)}:${PrimitiveUtils.zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}";
|
"${track.value.duration?.inMinutes.remainder(60)}:${PrimitiveUtils.zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}";
|
||||||
return InkWell(
|
return Consumer(builder: (context, ref, _) {
|
||||||
onLongPress: () {
|
final isBlackListed = ref.watch(
|
||||||
|
BlackListNotifier.provider.select(
|
||||||
|
(blacklist) => blacklist.contains(
|
||||||
|
BlacklistedElement.track(
|
||||||
|
track.value.id!, track.value.name!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
onLongPress: isBlackListed
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
showCheck.value = true;
|
showCheck.value = true;
|
||||||
selected.value = [...selected.value, track.value.id!];
|
selected.value = [
|
||||||
|
...selected.value,
|
||||||
|
track.value.id!
|
||||||
|
];
|
||||||
},
|
},
|
||||||
onTap: () {
|
onTap: isBlackListed
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
if (showCheck.value) {
|
if (showCheck.value) {
|
||||||
final alreadyChecked =
|
final alreadyChecked =
|
||||||
selected.value.contains(track.value.id);
|
selected.value.contains(track.value.id);
|
||||||
@ -219,7 +238,10 @@ class TracksTableView extends HookConsumerWidget {
|
|||||||
.where((id) => id != track.value.id)
|
.where((id) => id != track.value.id)
|
||||||
.toList();
|
.toList();
|
||||||
} else {
|
} else {
|
||||||
selected.value = [...selected.value, track.value.id!];
|
selected.value = [
|
||||||
|
...selected.value,
|
||||||
|
track.value.id!
|
||||||
|
];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final isBlackListed = ref.read(
|
final isBlackListed = ref.read(
|
||||||
@ -255,7 +277,9 @@ class TracksTableView extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}).toList(),
|
}).toList(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:spotube/hooks/use_breakpoints.dart';
|
import 'package:spotube/hooks/use_breakpoints.dart';
|
||||||
|
|
||||||
useBreakpointValue<T>({
|
T useBreakpointValue<T>({
|
||||||
T? sm,
|
T? sm,
|
||||||
T? md,
|
T? md,
|
||||||
T? lg,
|
T? lg,
|
||||||
@ -8,17 +8,37 @@ useBreakpointValue<T>({
|
|||||||
T? xxl,
|
T? xxl,
|
||||||
T? others,
|
T? others,
|
||||||
}) {
|
}) {
|
||||||
|
final isSomeNull =
|
||||||
|
sm == null || md == null || lg == null || xl == null || xxl == null;
|
||||||
|
assert(
|
||||||
|
(isSomeNull && others != null) || (!isSomeNull && others == null),
|
||||||
|
'You must provide a value for all breakpoints or a default value for others',
|
||||||
|
);
|
||||||
final breakpoint = useBreakpoints();
|
final breakpoint = useBreakpoints();
|
||||||
|
|
||||||
|
if (isSomeNull) {
|
||||||
if (breakpoint.isSm) {
|
if (breakpoint.isSm) {
|
||||||
return sm ?? others;
|
return sm ?? others!;
|
||||||
} else if (breakpoint.isMd) {
|
} else if (breakpoint.isMd) {
|
||||||
return md ?? others;
|
return md ?? others!;
|
||||||
} else if (breakpoint.isXl) {
|
} else if (breakpoint.isXl) {
|
||||||
return xl ?? others;
|
return xl ?? others!;
|
||||||
} else if (breakpoint.isXxl) {
|
} else if (breakpoint.isXxl) {
|
||||||
return xxl ?? others;
|
return xxl ?? others!;
|
||||||
} else {
|
} else {
|
||||||
return lg ?? others;
|
return lg ?? others!;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (breakpoint.isSm) {
|
||||||
|
return sm;
|
||||||
|
} else if (breakpoint.isMd) {
|
||||||
|
return md;
|
||||||
|
} else if (breakpoint.isXl) {
|
||||||
|
return xl;
|
||||||
|
} else if (breakpoint.isXxl) {
|
||||||
|
return xxl;
|
||||||
|
} else {
|
||||||
|
return lg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user