feat: artist card redesign

chore: add license as asset for about
This commit is contained in:
Kingkor Roy Tirtho 2023-03-12 10:06:37 +06:00
parent dcdb16676d
commit 92a418c8a8
27 changed files with 247 additions and 261 deletions

View File

@ -1,6 +1,6 @@
BSD-4-Clause License BSD-4-Clause License
Copyright (c) 2022 Kingkor Roy Tirtho. All rights reserved. Copyright (c) 2023 Kingkor Roy Tirtho. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View File

@ -3,8 +3,9 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/components/shared/hover_builder.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_brightness_value.dart';
import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/blacklist_provider.dart';
import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart';
@ -15,6 +16,7 @@ class ArtistCard extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final backgroundImage = UniversalImage.imageProvider( final backgroundImage = UniversalImage.imageProvider(
TypeConversionUtils.image_X_UrlString( TypeConversionUtils.image_X_UrlString(
artist.images, artist.images,
@ -29,46 +31,53 @@ class ArtistCard extends HookConsumerWidget {
), ),
); );
return SizedBox( final radius = BorderRadius.circular(15);
height: 240,
width: 200, final double size = useBreakpointValue<double>(
child: InkWell( sm: 130,
onTap: () { md: 150,
ServiceUtils.navigate(context, "/artist/${artist.id}"); others: 170,
}, );
borderRadius: BorderRadius.circular(8),
child: HoverBuilder(builder: (context, isHovering) { return Container(
return Ink( width: size,
width: 200, margin: const EdgeInsets.symmetric(vertical: 5),
decoration: BoxDecoration( child: Material(
color: Theme.of(context).cardColor, shadowColor: theme.colorScheme.background,
borderRadius: BorderRadius.circular(8), color: Color.lerp(
boxShadow: [ theme.colorScheme.surfaceVariant,
BoxShadow( theme.colorScheme.surface,
blurRadius: 10, useBrightnessValue(.9, .7),
offset: const Offset(0, 3), ),
spreadRadius: 5, elevation: 3,
color: Theme.of(context).colorScheme.shadow, shape: RoundedRectangleBorder(
), borderRadius: radius,
], side: isBlackListed
border: isBlackListed ? const BorderSide(
? Border.all( color: Colors.red,
color: Colors.red[400]!, width: 2,
width: 2, )
) : BorderSide.none,
: null, ),
), child: InkWell(
onTap: () {
ServiceUtils.navigate(context, "/artist/${artist.id}");
},
borderRadius: radius,
child: Padding( child: Padding(
padding: const EdgeInsets.all(15), padding: const EdgeInsets.all(12),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
Stack( Stack(
children: [ children: [
CircleAvatar( ConstrainedBox(
maxRadius: 80, constraints: BoxConstraints(
minRadius: 20, maxHeight: size,
backgroundImage: backgroundImage, ),
child: CircleAvatar(
backgroundImage: backgroundImage,
radius: size / 2,
),
), ),
Positioned( Positioned(
right: 0, right: 0,
@ -92,19 +101,19 @@ class ArtistCard extends HookConsumerWidget {
), ),
], ],
), ),
const SizedBox(height: 10),
AutoSizeText( AutoSizeText(
artist.name!, artist.name!,
maxLines: 2, maxLines: 1,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith( overflow: TextOverflow.ellipsis,
fontWeight: FontWeight.bold, style: theme.textTheme.bodyMedium?.copyWith(
), fontWeight: FontWeight.bold,
),
), ),
], ],
), ),
), )),
);
}),
), ),
); );
} }

View File

@ -18,6 +18,7 @@ class UserArtists extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final auth = ref.watch(AuthenticationNotifier.provider); final auth = ref.watch(AuthenticationNotifier.provider);
final artistQuery = useQueries.artist.followedByMe(ref); final artistQuery = useQueries.artist.followedByMe(ref);
@ -46,6 +47,8 @@ class UserArtists extends HookConsumerWidget {
.toList(); .toList();
}, [artistQuery.pages, searchText.value]); }, [artistQuery.pages, searchText.value]);
final controller = useScrollController();
if (auth == null) { if (auth == null) {
return const AnonymousFallback(); return const AnonymousFallback();
} }
@ -56,7 +59,7 @@ class UserArtists extends HookConsumerWidget {
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0), padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ColoredBox( child: ColoredBox(
color: Theme.of(context).scaffoldBackgroundColor, color: theme.scaffoldBackgroundColor,
child: TextField( child: TextField(
onChanged: (value) => searchText.value = value, onChanged: (value) => searchText.value = value,
decoration: const InputDecoration( decoration: const InputDecoration(
@ -67,7 +70,7 @@ class UserArtists extends HookConsumerWidget {
), ),
), ),
), ),
backgroundColor: Theme.of(context).scaffoldBackgroundColor, backgroundColor: theme.scaffoldBackgroundColor,
body: artistQuery.pages.isEmpty body: artistQuery.pages.isEmpty
? Padding( ? Padding(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
@ -84,33 +87,30 @@ class UserArtists extends HookConsumerWidget {
onRefresh: () async { onRefresh: () async {
await artistQuery.refreshAll(); await artistQuery.refreshAll();
}, },
child: SafeArea( child: SingleChildScrollView(
child: GridView.builder( controller: controller,
itemCount: filteredArtists.length, child: SizedBox(
physics: const AlwaysScrollableScrollPhysics(), width: double.infinity,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( child: SafeArea(
maxCrossAxisExtent: 200, child: Center(
mainAxisExtent: 250, child: Wrap(
crossAxisSpacing: 20, spacing: 15,
mainAxisSpacing: 20, runSpacing: 5,
children: filteredArtists.mapIndexed((index, artist) {
if (index == artistQuery.pages.length - 1 &&
hasNextPage) {
return Waypoint(
controller: controller,
isGrid: true,
onTouchEdge: artistQuery.fetchNext,
child: ArtistCard(artist),
);
}
return ArtistCard(artist);
}).toList(),
),
),
), ),
padding: const EdgeInsets.all(10),
itemBuilder: (context, index) {
return HookBuilder(builder: (context) {
if (index == artistQuery.pages.length - 1 &&
hasNextPage) {
return Waypoint(
controller: useScrollController(),
isGrid: true,
onTouchEdge: () {
artistQuery.fetchNext();
},
child: ArtistCard(filteredArtists[index]),
);
}
return ArtistCard(filteredArtists[index]);
});
},
), ),
), ),
), ),

View File

@ -79,7 +79,6 @@ class UserPlaylists extends HookConsumerWidget {
onRefresh: playlistsQuery.refresh, onRefresh: playlistsQuery.refresh,
child: SingleChildScrollView( child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.all(8.0),
child: SafeArea( child: SafeArea(
child: Column( child: Column(
children: [ children: [

View File

@ -41,6 +41,7 @@ class PlayerControls extends HookConsumerWidget {
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
final playing = useStream(PlaylistQueueNotifier.playing).data ?? final playing = useStream(PlaylistQueueNotifier.playing).data ??
PlaylistQueueNotifier.isPlaying; PlaylistQueueNotifier.isPlaying;
final theme = Theme.of(context);
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
@ -139,7 +140,7 @@ class PlayerControls extends HookConsumerWidget {
icon: Icon( icon: Icon(
SpotubeIcons.shuffle, SpotubeIcons.shuffle,
color: playlist?.isShuffled == true color: playlist?.isShuffled == true
? Theme.of(context).primaryColor ? theme.colorScheme.primary
: null, : null,
), ),
onPressed: playlist == null onPressed: playlist == null
@ -194,7 +195,7 @@ class PlayerControls extends HookConsumerWidget {
? SpotubeIcons.repeatOne ? SpotubeIcons.repeatOne
: SpotubeIcons.repeat, : SpotubeIcons.repeat,
color: playlist?.isLooping == true color: playlist?.isLooping == true
? Theme.of(context).primaryColor ? theme.colorScheme.primary
: null, : null,
), ),
onPressed: playlist == null || playlist.isLoading onPressed: playlist == null || playlist.isLoading

View File

@ -30,7 +30,8 @@ class PlayerOverlay extends HookConsumerWidget {
final playing = useStream(PlaylistQueueNotifier.playing).data ?? final playing = useStream(PlaylistQueueNotifier.playing).data ??
PlaylistQueueNotifier.isPlaying; PlaylistQueueNotifier.isPlaying;
final textColor = Theme.of(context).colorScheme.primary; final theme = Theme.of(context);
final textColor = theme.colorScheme.primary;
const radius = BorderRadius.only( const radius = BorderRadius.only(
topLeft: Radius.circular(10), topLeft: Radius.circular(10),
@ -54,10 +55,7 @@ class PlayerOverlay extends HookConsumerWidget {
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
height: canShow ? 53 : 0, height: canShow ? 53 : 0,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context) color: theme.colorScheme.secondaryContainer.withOpacity(.8),
.colorScheme
.secondaryContainer
.withOpacity(.8),
borderRadius: radius, borderRadius: radius,
), ),
child: AnimatedOpacity( child: AnimatedOpacity(
@ -81,7 +79,7 @@ class PlayerOverlay extends HookConsumerWidget {
minHeight: 2, minHeight: 2,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
valueColor: AlwaysStoppedAnimation( valueColor: AlwaysStoppedAnimation(
Theme.of(context).colorScheme.primary, theme.colorScheme.primary,
), ),
); );
}, },

View File

@ -36,7 +36,8 @@ class PlayerQueue extends HookConsumerWidget {
topLeft: Radius.circular(10), topLeft: Radius.circular(10),
topRight: Radius.circular(10), topRight: Radius.circular(10),
); );
final headlineColor = Theme.of(context).textTheme.headlineSmall?.color; final theme = Theme.of(context);
final headlineColor = theme.textTheme.headlineSmall?.color;
useEffect(() { useEffect(() {
if (playlist == null) return null; if (playlist == null) return null;
@ -60,7 +61,7 @@ class PlayerQueue extends HookConsumerWidget {
top: 5.0, top: 5.0,
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.5), color: theme.scaffoldBackgroundColor.withOpacity(0.5),
borderRadius: borderRadius, borderRadius: borderRadius,
), ),
child: Column( child: Column(
@ -88,11 +89,9 @@ class PlayerQueue extends HookConsumerWidget {
const Spacer(), const Spacer(),
FilledButton( FilledButton(
style: FilledButton.styleFrom( style: FilledButton.styleFrom(
backgroundColor: Theme.of(context) backgroundColor:
.scaffoldBackgroundColor theme.scaffoldBackgroundColor.withOpacity(0.5),
.withOpacity(0.5), foregroundColor: theme.textTheme.headlineSmall?.color,
foregroundColor:
Theme.of(context).textTheme.headlineSmall?.color,
), ),
child: Row( child: Row(
children: const [ children: const [

View File

@ -16,6 +16,7 @@ class PlayerTrackDetails extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final breakpoint = useBreakpoints(); final breakpoint = useBreakpoints();
final playback = ref.watch(PlaylistQueueNotifier.provider); final playback = ref.watch(PlaylistQueueNotifier.provider);
@ -50,19 +51,16 @@ class PlayerTrackDetails extends HookConsumerWidget {
Text( Text(
playback?.activeTrack.name ?? "", playback?.activeTrack.name ?? "",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyMedium?.copyWith( style: theme.textTheme.bodyMedium?.copyWith(
color: color, color: color,
), ),
), ),
Text( Text(
TypeConversionUtils.artists_X_String<Artist>( TypeConversionUtils.artists_X_String<Artist>(
playback?.activeTrack.artists ?? [], playback?.activeTrack.artists ?? [],
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: Theme.of(context) style: theme.textTheme.bodySmall!.copyWith(color: color),
.textTheme
.bodySmall!
.copyWith(color: color),
) )
], ],
), ),

View File

@ -19,6 +19,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final playlist = ref.watch(PlaylistQueueNotifier.provider); final playlist = ref.watch(PlaylistQueueNotifier.provider);
final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier); final playlistNotifier = ref.watch(PlaylistQueueNotifier.notifier);
@ -50,7 +51,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
margin: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius, borderRadius: borderRadius,
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.3), color: theme.scaffoldBackgroundColor.withOpacity(.3),
), ),
child: Scaffold( child: Scaffold(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
@ -58,7 +59,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
centerTitle: true, centerTitle: true,
title: Text( title: Text(
'Alternative Tracks Sources', 'Alternative Tracks Sources',
style: Theme.of(context).textTheme.headlineSmall, style: theme.textTheme.headlineSmall,
), ),
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
@ -96,7 +97,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
.ytTrack .ytTrack
.id .id
.value, .value,
selectedTileColor: Theme.of(context).popupMenuTheme.color, selectedTileColor: theme.popupMenuTheme.color,
onTap: () async { onTap: () async {
if (playlist?.isLoading == false && if (playlist?.isLoading == false &&
video.id.value != video.id.value !=

View File

@ -40,7 +40,8 @@ class BottomPlayer extends HookConsumerWidget {
[playlist?.activeTrack.album?.images], [playlist?.activeTrack.album?.images],
); );
final bg = Theme.of(context).colorScheme.surfaceVariant; final theme = Theme.of(context);
final bg = theme.colorScheme.surfaceVariant;
final bgColor = useBrightnessValue( final bgColor = useBrightnessValue(
Color.lerp(bg, Colors.white, 0.7), Color.lerp(bg, Colors.white, 0.7),
@ -62,7 +63,7 @@ class BottomPlayer extends HookConsumerWidget {
decoration: BoxDecoration(color: bgColor?.withOpacity(0.8)), decoration: BoxDecoration(color: bgColor?.withOpacity(0.8)),
child: Material( child: Material(
type: MaterialType.transparency, type: MaterialType.transparency,
textStyle: Theme.of(context).textTheme.bodyMedium!, textStyle: theme.textTheme.bodyMedium!,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [

View File

@ -61,7 +61,8 @@ class Sidebar extends HookConsumerWidget {
extended: breakpoints > Breakpoints.md, extended: breakpoints > Breakpoints.md,
); );
final bg = Theme.of(context).colorScheme.surfaceVariant; final theme = Theme.of(context);
final bg = theme.colorScheme.surfaceVariant;
final bgColor = useBrightnessValue( final bgColor = useBrightnessValue(
Color.lerp(bg, Colors.white, 0.7), Color.lerp(bg, Colors.white, 0.7),
@ -98,7 +99,7 @@ class Sidebar extends HookConsumerWidget {
(e) { (e) {
return SidebarXItem( return SidebarXItem(
// iconWidget: Badge( // iconWidget: Badge(
// backgroundColor: Theme.of(context).primaryColor, // backgroundColor: theme.colorScheme.primary,
// isLabelVisible: e.title == "Library" && downloadCount > 0, // isLabelVisible: e.title == "Library" && downloadCount > 0,
// label: Text( // label: Text(
// downloadCount.toString(), // downloadCount.toString(),
@ -125,10 +126,10 @@ class Sidebar extends HookConsumerWidget {
margin: EdgeInsets.only(bottom: 10, top: kIsMacOS ? 35 : 5), margin: EdgeInsets.only(bottom: 10, top: kIsMacOS ? 35 : 5),
selectedItemDecoration: BoxDecoration( selectedItemDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
color: Theme.of(context).colorScheme.primary.withOpacity(0.1), color: theme.colorScheme.primary.withOpacity(0.1),
), ),
selectedIconTheme: IconThemeData( selectedIconTheme: IconThemeData(
color: Theme.of(context).colorScheme.primary, color: theme.colorScheme.primary,
), ),
), ),
extendedTheme: SidebarXTheme( extendedTheme: SidebarXTheme(
@ -148,16 +149,15 @@ class Sidebar extends HookConsumerWidget {
), ),
selectedItemDecoration: BoxDecoration( selectedItemDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
color: Theme.of(context).colorScheme.primary.withOpacity(0.1), color: theme.colorScheme.primary.withOpacity(0.1),
), ),
selectedIconTheme: IconThemeData( selectedIconTheme: IconThemeData(
color: Theme.of(context).colorScheme.primary, color: theme.colorScheme.primary,
),
selectedTextStyle: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.primary,
fontWeight: FontWeight.w600,
), ),
selectedTextStyle:
Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w600,
),
itemTextPadding: const EdgeInsets.only(left: 10), itemTextPadding: const EdgeInsets.only(left: 10),
selectedItemTextPadding: const EdgeInsets.only(left: 10), selectedItemTextPadding: const EdgeInsets.only(left: 10),
), ),
@ -175,6 +175,7 @@ class SidebarHeader extends HookWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final breakpoint = useBreakpoints(); final breakpoint = useBreakpoints();
final theme = Theme.of(context);
if (breakpoint <= Breakpoints.md) { if (breakpoint <= Breakpoints.md) {
return Container( return Container(
@ -196,7 +197,7 @@ class SidebarHeader extends HookWidget {
const SizedBox(width: 10), const SizedBox(width: 10),
Text( Text(
"Spotube", "Spotube",
style: Theme.of(context).textTheme.titleLarge, style: theme.textTheme.titleLarge,
), ),
], ],
), ),
@ -213,6 +214,7 @@ class SidebarFooter extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final breakpoint = useBreakpoints(); final breakpoint = useBreakpoints();
final me = useQueries.user.me(ref); final me = useQueries.user.me(ref);
final data = me.data; final data = me.data;
@ -260,9 +262,7 @@ class SidebarFooter extends HookConsumerWidget {
maxLines: 1, maxLines: 1,
softWrap: false, softWrap: false,
overflow: TextOverflow.fade, overflow: TextOverflow.fade,
style: Theme.of(context) style: theme.textTheme.bodyMedium
.textTheme
.bodyMedium
?.copyWith(fontWeight: FontWeight.bold), ?.copyWith(fontWeight: FontWeight.bold),
), ),
), ),

View File

@ -13,6 +13,7 @@ class ReplaceDownloadedDialog extends ConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final groupValue = ref.watch(replaceDownloadedFileState); final groupValue = ref.watch(replaceDownloadedFileState);
final theme = Theme.of(context);
return AlertDialog( return AlertDialog(
title: Text("Track ${track.name} Already Exists"), title: Text("Track ${track.name} Already Exists"),
@ -23,7 +24,7 @@ class ReplaceDownloadedDialog extends ConsumerWidget {
RadioListTile<bool>( RadioListTile<bool>(
dense: true, dense: true,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
activeColor: Theme.of(context).primaryColor, activeColor: theme.colorScheme.primary,
value: true, value: true,
groupValue: groupValue, groupValue: groupValue,
onChanged: (value) { onChanged: (value) {
@ -36,7 +37,7 @@ class ReplaceDownloadedDialog extends ConsumerWidget {
RadioListTile<bool>( RadioListTile<bool>(
dense: true, dense: true,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
activeColor: Theme.of(context).primaryColor, activeColor: theme.colorScheme.primary,
value: false, value: false,
groupValue: groupValue, groupValue: groupValue,
onChanged: (value) { onChanged: (value) {

View File

@ -7,6 +7,7 @@ class NotFound extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
final widgets = [ final widgets = [
SizedBox( SizedBox(
height: 150, height: 150,
@ -17,10 +18,10 @@ class NotFound extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text("Nothing found", style: Theme.of(context).textTheme.headline6), Text("Nothing found", style: theme.textTheme.titleLarge),
Text( Text(
"The box is empty", "The box is empty",
style: Theme.of(context).textTheme.subtitle1, style: theme.textTheme.titleMedium,
), ),
], ],
), ),

View File

@ -37,11 +37,6 @@ class PlaybuttonCard extends HookWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
final radius = BorderRadius.circular(15); final radius = BorderRadius.circular(15);
final shadowColor = useBrightnessValue(
theme.colorScheme.background,
theme.colorScheme.background,
);
final double size = useBreakpointValue<double>( final double size = useBreakpointValue<double>(
sm: 130, sm: 130,
md: 150, md: 150,
@ -64,7 +59,7 @@ class PlaybuttonCard extends HookWidget {
useBrightnessValue(.9, .7), useBrightnessValue(.9, .7),
), ),
borderRadius: radius, borderRadius: radius,
shadowColor: shadowColor, shadowColor: theme.colorScheme.background,
elevation: 3, elevation: 3,
child: InkWell( child: InkWell(
mouseCursor: SystemMouseCursors.click, mouseCursor: SystemMouseCursors.click,

View File

@ -91,7 +91,7 @@ class ShimmerPlaybuttonCard extends HookWidget {
others: const Size(170, 240), others: const Size(170, 240),
); );
final isDark = Theme.of(context).brightness == Brightness.dark; final isDark = theme.brightness == Brightness.dark;
final bgColor = theme.colorScheme.surfaceVariant.withOpacity(.2); final bgColor = theme.colorScheme.surfaceVariant.withOpacity(.2);
final fgColor = Color.lerp( final fgColor = Color.lerp(
theme.colorScheme.surfaceVariant, theme.colorScheme.surfaceVariant,

View File

@ -67,7 +67,8 @@ class ShimmerTrackTile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark; final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
final shimmerTheme = ShimmerColorTheme( final shimmerTheme = ShimmerColorTheme(
shimmerBackgroundColor: isDark ? Colors.grey[700] : Colors.grey[200], shimmerBackgroundColor: isDark ? Colors.grey[700] : Colors.grey[200],
shimmerColor: isDark ? Colors.grey[800] : Colors.grey[300], shimmerColor: isDark ? Colors.grey[800] : Colors.grey[300],
@ -83,9 +84,8 @@ class ShimmerTrackTile extends StatelessWidget {
size: const Size(double.infinity, 50), size: const Size(double.infinity, 50),
painter: ShimmerTrackTilePainter( painter: ShimmerTrackTilePainter(
background: shimmerTheme.shimmerBackgroundColor ?? background: shimmerTheme.shimmerBackgroundColor ??
Theme.of(context).scaffoldBackgroundColor, theme.scaffoldBackgroundColor,
foreground: foreground: shimmerTheme.shimmerColor ?? theme.cardColor,
shimmerTheme.shimmerColor ?? Theme.of(context).cardColor,
), ),
), ),
); );
@ -101,9 +101,8 @@ class ShimmerTrackTile extends StatelessWidget {
size: const Size(double.infinity, 50), size: const Size(double.infinity, 50),
painter: ShimmerTrackTilePainter( painter: ShimmerTrackTilePainter(
background: shimmerTheme.shimmerBackgroundColor ?? background: shimmerTheme.shimmerBackgroundColor ??
Theme.of(context).scaffoldBackgroundColor, theme.scaffoldBackgroundColor,
foreground: foreground: shimmerTheme.shimmerColor ?? theme.cardColor,
shimmerTheme.shimmerColor ?? Theme.of(context).cardColor,
), ),
), ),
), ),

View File

@ -11,9 +11,10 @@ class ThemedButtonsTabBar extends HookWidget implements PreferredSizeWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context);
final bgColor = useBrightnessValue( final bgColor = useBrightnessValue(
Theme.of(context).colorScheme.primaryContainer, theme.colorScheme.primaryContainer,
Color.lerp(Theme.of(context).colorScheme.primary, Colors.black, 0.7)!, Color.lerp(theme.colorScheme.primary, Colors.black, 0.7)!,
); );
final breakpoint = useBreakpointValue( final breakpoint = useBreakpointValue(
@ -34,18 +35,18 @@ class ThemedButtonsTabBar extends HookWidget implements PreferredSizeWidget {
color: bgColor, color: bgColor,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
), ),
labelStyle: Theme.of(context).textTheme.labelLarge?.copyWith( labelStyle: theme.textTheme.labelLarge?.copyWith(
color: Theme.of(context).colorScheme.primary, color: theme.colorScheme.primary,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
borderWidth: 0, borderWidth: 0,
unselectedDecoration: BoxDecoration( unselectedDecoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: theme.colorScheme.background,
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
), ),
unselectedLabelStyle: Theme.of(context).textTheme.labelLarge?.copyWith( unselectedLabelStyle: theme.textTheme.labelLarge?.copyWith(
color: Theme.of(context).colorScheme.primary, color: theme.colorScheme.primary,
), ),
tabs: tabs.map((tab) { tabs: tabs.map((tab) {
return Tab(text: " $tab "); return Tab(text: " $tab ");
}).toList(), }).toList(),

View File

@ -64,6 +64,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final auth = ref.watch(AuthenticationNotifier.provider); final auth = ref.watch(AuthenticationNotifier.provider);
final color = usePaletteGenerator( final color = usePaletteGenerator(
context, context,
@ -101,7 +102,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
// play playlist // play playlist
IconButton( IconButton(
style: IconButton.styleFrom( style: IconButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor, backgroundColor: theme.colorScheme.primary,
), ),
onPressed: tracksSnapshot.data != null ? onPlay : null, onPressed: tracksSnapshot.data != null ? onPlay : null,
icon: Icon(isPlaying ? SpotubeIcons.stop : SpotubeIcons.play), icon: Icon(isPlaying ? SpotubeIcons.stop : SpotubeIcons.play),
@ -138,7 +139,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
}, [tracksSnapshot.data, searchText.value]); }, [tracksSnapshot.data, searchText.value]);
useCustomStatusBarColor( useCustomStatusBarColor(
color?.color ?? Theme.of(context).scaffoldBackgroundColor, color?.color ?? theme.scaffoldBackgroundColor,
GoRouter.of(context).location == routePath, GoRouter.of(context).location == routePath,
); );
@ -168,11 +169,11 @@ class TrackCollectionView<T> extends HookConsumerWidget {
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search tracks...", hintText: "Search tracks...",
hintStyle: TextStyle(color: color?.titleTextColor), hintStyle: TextStyle(color: color?.titleTextColor),
border: Theme.of(context).inputDecorationTheme.border?.copyWith( border: theme.inputDecorationTheme.border?.copyWith(
borderSide: BorderSide( borderSide: BorderSide(
color: color?.titleTextColor ?? Colors.white, color: color?.titleTextColor ?? Colors.white,
), ),
), ),
prefixIconColor: color?.titleTextColor, prefixIconColor: color?.titleTextColor,
prefixIcon: const Icon(SpotubeIcons.search), prefixIcon: const Icon(SpotubeIcons.search),
), ),
@ -228,11 +229,10 @@ class TrackCollectionView<T> extends HookConsumerWidget {
title: collapsed.value title: collapsed.value
? Text( ? Text(
title, title,
style: style: theme.textTheme.titleLarge!.copyWith(
Theme.of(context).textTheme.titleLarge!.copyWith( color: color?.titleTextColor,
color: color?.titleTextColor, fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600, ),
),
) )
: null, : null,
centerTitle: true, centerTitle: true,
@ -242,7 +242,7 @@ class TrackCollectionView<T> extends HookConsumerWidget {
gradient: LinearGradient( gradient: LinearGradient(
colors: [ colors: [
color?.color ?? Colors.transparent, color?.color ?? Colors.transparent,
Theme.of(context).canvasColor, theme.canvasColor,
], ],
begin: const FractionalOffset(0, 0), begin: const FractionalOffset(0, 0),
end: const FractionalOffset(0, 1), end: const FractionalOffset(0, 1),
@ -282,13 +282,10 @@ class TrackCollectionView<T> extends HookConsumerWidget {
children: [ children: [
Text( Text(
title, title,
style: Theme.of(context) style: theme.textTheme.titleLarge!.copyWith(
.textTheme color: color?.titleTextColor,
.titleLarge! fontWeight: FontWeight.w600,
.copyWith( ),
color: color?.titleTextColor,
fontWeight: FontWeight.w600,
),
), ),
if (description != null) if (description != null)
Text( Text(

View File

@ -174,6 +174,7 @@ class TrackTile extends HookConsumerWidget {
); );
final toggler = useTrackToggleLike(track.value, ref); final toggler = useTrackToggleLike(track.value, ref);
final theme = Theme.of(context);
return AnimatedContainer( return AnimatedContainer(
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 500),
@ -181,7 +182,7 @@ class TrackTile extends HookConsumerWidget {
color: isBlackListed color: isBlackListed
? Colors.red[100] ? Colors.red[100]
: isActive : isActive
? Theme.of(context).popupMenuTheme.color ? theme.popupMenuTheme.color
: Colors.transparent, : Colors.transparent,
borderRadius: BorderRadius.circular(isActive ? 10 : 0), borderRadius: BorderRadius.circular(isActive ? 10 : 0),
), ),
@ -234,8 +235,8 @@ class TrackTile extends HookConsumerWidget {
color: Colors.white, color: Colors.white,
), ),
style: IconButton.styleFrom( style: IconButton.styleFrom(
backgroundColor: Theme.of(context).primaryColor, backgroundColor: theme.colorScheme.primary,
hoverColor: Theme.of(context).primaryColor.withOpacity(0.5), hoverColor: theme.colorScheme.primary.withOpacity(0.5),
), ),
onPressed: !isBlackListed onPressed: !isBlackListed
? () => onTrackPlayButtonPressed?.call( ? () => onTrackPlayButtonPressed?.call(

View File

@ -33,7 +33,8 @@ class ArtistPage extends HookConsumerWidget {
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
SpotifyApi spotify = ref.watch(spotifyProvider); SpotifyApi spotify = ref.watch(spotifyProvider);
final parentScrollController = useScrollController(); final parentScrollController = useScrollController();
final textTheme = Theme.of(context).textTheme; final theme = Theme.of(context);
final textTheme = theme.textTheme;
final chipTextVariant = useBreakpointValue( final chipTextVariant = useBreakpointValue(
sm: textTheme.bodySmall, sm: textTheme.bodySmall,
md: textTheme.bodyMedium, md: textTheme.bodyMedium,
@ -42,12 +43,14 @@ class ArtistPage extends HookConsumerWidget {
xxl: textTheme.titleMedium, xxl: textTheme.titleMedium,
); );
final mediaQuery = MediaQuery.of(context);
final avatarWidth = useBreakpointValue( final avatarWidth = useBreakpointValue(
sm: MediaQuery.of(context).size.width * 0.50, sm: mediaQuery.size.width * 0.50,
md: MediaQuery.of(context).size.width * 0.40, md: mediaQuery.size.width * 0.40,
lg: MediaQuery.of(context).size.width * 0.18, lg: mediaQuery.size.width * 0.18,
xl: MediaQuery.of(context).size.width * 0.18, xl: mediaQuery.size.width * 0.18,
xxl: MediaQuery.of(context).size.width * 0.18, xxl: mediaQuery.size.width * 0.18,
); );
final breakpoint = useBreakpoints(); final breakpoint = useBreakpoints();
@ -316,8 +319,7 @@ class ArtistPage extends HookConsumerWidget {
children: [ children: [
Text( Text(
"Top Tracks", "Top Tracks",
style: style: theme.textTheme.headlineSmall,
Theme.of(context).textTheme.headlineSmall,
), ),
if (!isPlaylistPlaying) if (!isPlaylistPlaying)
IconButton( IconButton(
@ -347,8 +349,7 @@ class ArtistPage extends HookConsumerWidget {
color: Colors.white, color: Colors.white,
), ),
style: IconButton.styleFrom( style: IconButton.styleFrom(
backgroundColor: backgroundColor: theme.colorScheme.primary,
Theme.of(context).primaryColor,
), ),
onPressed: () => onPressed: () =>
playPlaylist(topTracks.toList()), playPlaylist(topTracks.toList()),
@ -377,14 +378,14 @@ class ArtistPage extends HookConsumerWidget {
const SizedBox(height: 50), const SizedBox(height: 50),
Text( Text(
"Albums", "Albums",
style: Theme.of(context).textTheme.headlineSmall, style: theme.textTheme.headlineSmall,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
ArtistAlbumList(artistId), ArtistAlbumList(artistId),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
"Fans also likes", "Fans also likes",
style: Theme.of(context).textTheme.headlineSmall, style: theme.textTheme.headlineSmall,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
HookBuilder( HookBuilder(

View File

@ -13,6 +13,8 @@ class DesktopLoginPage extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final breakpoint = useBreakpoints(); final breakpoint = useBreakpoints();
final theme = Theme.of(context);
final color = theme.colorScheme.surfaceVariant.withOpacity(.3);
return SafeArea( return SafeArea(
child: Scaffold( child: Scaffold(
@ -25,7 +27,7 @@ class DesktopLoginPage extends HookConsumerWidget {
margin: const EdgeInsets.all(10), margin: const EdgeInsets.all(10),
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).cardColor, color: color,
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
child: Column( child: Column(
@ -36,11 +38,11 @@ class DesktopLoginPage extends HookConsumerWidget {
), ),
Text( Text(
"Add your spotify credentials to get started", "Add your spotify credentials to get started",
style: Theme.of(context).textTheme.titleMedium, style: theme.textTheme.titleMedium,
), ),
Text( Text(
"Don't worry, any of your credentials won't be collected or shared with anyone", "Don't worry, any of your credentials won't be collected or shared with anyone",
style: Theme.of(context).textTheme.labelMedium, style: theme.textTheme.labelMedium,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
TokenLoginForm( TokenLoginForm(

View File

@ -19,10 +19,11 @@ class LoginTutorial extends ConsumerWidget {
final authenticationNotifier = final authenticationNotifier =
ref.watch(AuthenticationNotifier.provider.notifier); ref.watch(AuthenticationNotifier.provider.notifier);
final key = GlobalKey<State<IntroductionScreen>>(); final key = GlobalKey<State<IntroductionScreen>>();
final theme = Theme.of(context);
final pageDecoration = PageDecoration( final pageDecoration = PageDecoration(
bodyTextStyle: Theme.of(context).textTheme.bodyMedium!, bodyTextStyle: theme.textTheme.bodyMedium!,
titleTextStyle: Theme.of(context).textTheme.headlineMedium!, titleTextStyle: theme.textTheme.headlineMedium!,
); );
return Scaffold( return Scaffold(
appBar: PageWindowTitleBar( appBar: PageWindowTitleBar(
@ -35,7 +36,7 @@ class LoginTutorial extends ConsumerWidget {
), ),
body: IntroductionScreen( body: IntroductionScreen(
key: key, key: key,
globalBackgroundColor: Theme.of(context).scaffoldBackgroundColor, globalBackgroundColor: theme.scaffoldBackgroundColor,
overrideBack: OutlinedButton( overrideBack: OutlinedButton(
child: const Center(child: Text("Previous")), child: const Center(child: Text("Previous")),
onPressed: () { onPressed: () {
@ -113,7 +114,7 @@ class LoginTutorial extends ConsumerWidget {
children: [ children: [
Text( Text(
"Paste the copied \"sp_dc\" and \"sp_key\" values in the respective fields", "Paste the copied \"sp_dc\" and \"sp_key\" values in the respective fields",
style: Theme.of(context).textTheme.labelMedium, style: theme.textTheme.labelMedium,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
TokenLoginForm( TokenLoginForm(

View File

@ -28,6 +28,7 @@ class PlayerView extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
final currentTrack = ref.watch(PlaylistQueueNotifier.provider.select( final currentTrack = ref.watch(PlaylistQueueNotifier.provider.select(
(value) => value?.activeTrack, (value) => value?.activeTrack,
)); ));
@ -94,13 +95,10 @@ class PlayerView extends HookConsumerWidget {
height: 30, height: 30,
child: Text( child: Text(
currentTrack?.name ?? "Not playing", currentTrack?.name ?? "Not playing",
style: Theme.of(context) style: theme.textTheme.headlineSmall?.copyWith(
.textTheme fontWeight: FontWeight.bold,
.headlineSmall color: paletteColor.titleTextColor,
?.copyWith( ),
fontWeight: FontWeight.bold,
color: paletteColor.titleTextColor,
),
), ),
), ),
if (isLocalTrack) if (isLocalTrack)
@ -108,24 +106,18 @@ class PlayerView extends HookConsumerWidget {
TypeConversionUtils.artists_X_String<Artist>( TypeConversionUtils.artists_X_String<Artist>(
currentTrack?.artists ?? [], currentTrack?.artists ?? [],
), ),
style: Theme.of(context) style: theme.textTheme.titleLarge!.copyWith(
.textTheme fontWeight: FontWeight.bold,
.titleLarge! color: paletteColor.bodyTextColor,
.copyWith( ),
fontWeight: FontWeight.bold,
color: paletteColor.bodyTextColor,
),
) )
else else
TypeConversionUtils.artists_X_ClickableArtists( TypeConversionUtils.artists_X_ClickableArtists(
currentTrack?.artists ?? [], currentTrack?.artists ?? [],
textStyle: Theme.of(context) textStyle: theme.textTheme.titleLarge!.copyWith(
.textTheme fontWeight: FontWeight.bold,
.titleLarge! color: paletteColor.bodyTextColor,
.copyWith( ),
fontWeight: FontWeight.bold,
color: paletteColor.bodyTextColor,
),
onRouteChange: (route) { onRouteChange: (route) {
GoRouter.of(context).pop(); GoRouter.of(context).pop();
GoRouter.of(context).push(route); GoRouter.of(context).push(route);

View File

@ -33,6 +33,7 @@ class SearchPage extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final theme = Theme.of(context);
ref.watch(AuthenticationNotifier.provider); ref.watch(AuthenticationNotifier.provider);
final authenticationNotifier = final authenticationNotifier =
ref.watch(AuthenticationNotifier.provider.notifier); ref.watch(AuthenticationNotifier.provider.notifier);
@ -74,7 +75,7 @@ class SearchPage extends HookConsumerWidget {
horizontal: 20, horizontal: 20,
vertical: 10, vertical: 10,
), ),
color: Theme.of(context).scaffoldBackgroundColor, color: theme.scaffoldBackgroundColor,
child: TextField( child: TextField(
decoration: const InputDecoration( decoration: const InputDecoration(
prefixIcon: Icon(SpotubeIcons.search), prefixIcon: Icon(SpotubeIcons.search),
@ -134,9 +135,7 @@ class SearchPage extends HookConsumerWidget {
if (tracks.isNotEmpty) if (tracks.isNotEmpty)
Text( Text(
"Songs", "Songs",
style: Theme.of(context) style: theme.textTheme.titleLarge!,
.textTheme
.titleLarge!,
), ),
if (searchTrack.isLoadingPage) if (searchTrack.isLoadingPage)
const CircularProgressIndicator() const CircularProgressIndicator()
@ -198,9 +197,7 @@ class SearchPage extends HookConsumerWidget {
if (playlists.isNotEmpty) if (playlists.isNotEmpty)
Text( Text(
"Playlists", "Playlists",
style: Theme.of(context) style: theme.textTheme.titleLarge!,
.textTheme
.titleLarge!,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
ScrollConfiguration( ScrollConfiguration(
@ -258,9 +255,7 @@ class SearchPage extends HookConsumerWidget {
if (artists.isNotEmpty) if (artists.isNotEmpty)
Text( Text(
"Artists", "Artists",
style: Theme.of(context) style: theme.textTheme.titleLarge!,
.textTheme
.titleLarge!,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
ScrollConfiguration( ScrollConfiguration(
@ -317,9 +312,7 @@ class SearchPage extends HookConsumerWidget {
if (albums.isNotEmpty) if (albums.isNotEmpty)
Text( Text(
"Albums", "Albums",
style: Theme.of(context) style: theme.textTheme.titleMedium!,
.textTheme
.titleMedium!,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
ScrollConfiguration( ScrollConfiguration(

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/assets.gen.dart';
import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/image/universal_image.dart';
import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart';
@ -9,12 +10,18 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
final _licenseProvider = FutureProvider<String>((ref) async {
return await rootBundle.loadString("LICENSE");
});
class AboutSpotube extends HookConsumerWidget { class AboutSpotube extends HookConsumerWidget {
const AboutSpotube({Key? key}) : super(key: key); const AboutSpotube({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final packageInfo = usePackageInfo(); final packageInfo = usePackageInfo();
final license = ref.watch(_licenseProvider);
final theme = Theme.of(context);
return Scaffold( return Scaffold(
appBar: const PageWindowTitleBar( appBar: const PageWindowTitleBar(
@ -36,7 +43,7 @@ class AboutSpotube extends HookConsumerWidget {
children: [ children: [
Text( Text(
"Spotube, a light-weight, cross-platform, free-for-all spotify client", "Spotube, a light-weight, cross-platform, free-for-all spotify client",
style: Theme.of(context).textTheme.titleLarge, style: theme.textTheme.titleLarge,
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Row( Row(
@ -181,21 +188,35 @@ class AboutSpotube extends HookConsumerWidget {
Text( Text(
"Made with ❤️ in Bangladesh🇧🇩", "Made with ❤️ in Bangladesh🇧🇩",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodySmall, style: theme.textTheme.bodySmall,
), ),
Text( Text(
"© 2021-${DateTime.now().year} Kingkor Roy Tirtho", "© 2021-${DateTime.now().year} Kingkor Roy Tirtho",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodySmall, style: theme.textTheme.bodySmall,
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
ConstrainedBox( ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 750), constraints: const BoxConstraints(maxWidth: 750),
child: SafeArea( child: SafeArea(
child: Text( child: license.when(
licenseText, data: (data) {
textAlign: TextAlign.justify, return Text(
style: Theme.of(context).textTheme.bodySmall, data,
style: theme.textTheme.bodySmall,
);
},
loading: () {
return const Center(
child: CircularProgressIndicator(),
);
},
error: (e, s) {
return Text(
e.toString(),
style: theme.textTheme.bodySmall,
);
},
), ),
), ),
), ),
@ -206,18 +227,3 @@ class AboutSpotube extends HookConsumerWidget {
); );
} }
} }
const licenseText = """
BSD-4-Clause License
Copyright (c) 2022 Kingkor Roy Tirtho. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software must display the following acknowledgement:
This product includes software developed by Kingkor Roy Tirtho.
4. Neither the name of the Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY KINGKOR ROY TIRTHO AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KINGKOR ROY TIRTHO AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
""";

View File

@ -21,6 +21,7 @@ class SettingsPage extends HookConsumerWidget {
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final UserPreferences preferences = ref.watch(userPreferencesProvider); final UserPreferences preferences = ref.watch(userPreferencesProvider);
final auth = ref.watch(AuthenticationNotifier.provider); final auth = ref.watch(AuthenticationNotifier.provider);
final theme = Theme.of(context);
final pickColorScheme = useCallback((ColorSchemeType schemeType) { final pickColorScheme = useCallback((ColorSchemeType schemeType) {
return () => showDialog( return () => showDialog(
@ -57,16 +58,14 @@ class SettingsPage extends HookConsumerWidget {
children: [ children: [
Text( Text(
" Account", " Account",
style: Theme.of(context) style: theme.textTheme.headlineSmall
.textTheme
.headlineSmall
?.copyWith(fontWeight: FontWeight.bold), ?.copyWith(fontWeight: FontWeight.bold),
), ),
if (auth == null) if (auth == null)
AdaptiveListTile( AdaptiveListTile(
leading: Icon( leading: Icon(
SpotubeIcons.login, SpotubeIcons.login,
color: Theme.of(context).primaryColor, color: theme.colorScheme.primary,
), ),
title: SizedBox( title: SizedBox(
height: 50, height: 50,
@ -77,7 +76,7 @@ class SettingsPage extends HookConsumerWidget {
"Login with your Spotify account", "Login with your Spotify account",
maxLines: 1, maxLines: 1,
style: TextStyle( style: TextStyle(
color: Theme.of(context).primaryColor, color: theme.colorScheme.primary,
), ),
), ),
), ),
@ -131,9 +130,7 @@ class SettingsPage extends HookConsumerWidget {
}), }),
Text( Text(
" Appearance", " Appearance",
style: Theme.of(context) style: theme.textTheme.headlineSmall
.textTheme
.headlineSmall
?.copyWith(fontWeight: FontWeight.bold), ?.copyWith(fontWeight: FontWeight.bold),
), ),
AdaptiveListTile( AdaptiveListTile(
@ -217,9 +214,7 @@ class SettingsPage extends HookConsumerWidget {
), ),
Text( Text(
" Playback", " Playback",
style: Theme.of(context) style: theme.textTheme.headlineSmall
.textTheme
.headlineSmall
?.copyWith(fontWeight: FontWeight.bold), ?.copyWith(fontWeight: FontWeight.bold),
), ),
AdaptiveListTile( AdaptiveListTile(
@ -279,9 +274,7 @@ class SettingsPage extends HookConsumerWidget {
), ),
Text( Text(
" Search", " Search",
style: Theme.of(context) style: theme.textTheme.headlineSmall
.textTheme
.headlineSmall
?.copyWith(fontWeight: FontWeight.bold), ?.copyWith(fontWeight: FontWeight.bold),
), ),
AdaptiveListTile( AdaptiveListTile(
@ -312,9 +305,7 @@ class SettingsPage extends HookConsumerWidget {
), ),
Text( Text(
" Downloads", " Downloads",
style: Theme.of(context) style: theme.textTheme.headlineSmall
.textTheme
.headlineSmall
?.copyWith(fontWeight: FontWeight.bold), ?.copyWith(fontWeight: FontWeight.bold),
), ),
ListTile( ListTile(
@ -337,9 +328,7 @@ class SettingsPage extends HookConsumerWidget {
), ),
Text( Text(
" About", " About",
style: Theme.of(context) style: theme.textTheme.headlineSmall
.textTheme
.headlineSmall
?.copyWith(fontWeight: FontWeight.bold), ?.copyWith(fontWeight: FontWeight.bold),
), ),
AdaptiveListTile( AdaptiveListTile(

View File

@ -102,6 +102,7 @@ flutter:
- assets/ - assets/
- assets/tutorial/ - assets/tutorial/
- .env - .env
- LICENSE
flutter_icons: flutter_icons:
android: true android: true