diff --git a/lib/components/Artist/ArtistCard.dart b/lib/components/Artist/ArtistCard.dart index 8619fee1f..aec4b3e78 100644 --- a/lib/components/Artist/ArtistCard.dart +++ b/lib/components/Artist/ArtistCard.dart @@ -1,12 +1,16 @@ import 'package:auto_size_text/auto_size_text.dart'; +import 'package:fluent_ui/fluent_ui.dart' hide Colors; import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:platform_ui/platform_ui.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/Shared/HoverBuilder.dart'; import 'package:spotube/components/Shared/UniversalImage.dart'; +import 'package:spotube/hooks/usePlatformProperty.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; -class ArtistCard extends StatelessWidget { +class ArtistCard extends HookWidget { final Artist artist; const ArtistCard(this.artist, {Key? key}) : super(key: key); @@ -18,28 +22,76 @@ class ArtistCard extends StatelessWidget { placeholder: ImagePlaceholder.artist, ), ); + final boxShadow = usePlatformProperty( + (context) => PlatformProperty( + android: BoxShadow( + blurRadius: 10, + offset: const Offset(0, 3), + spreadRadius: 5, + color: Theme.of(context).shadowColor, + ), + ios: null, + macos: null, + linux: BoxShadow( + blurRadius: 10, + offset: const Offset(0, 3), + spreadRadius: 5, + color: Theme.of(context).shadowColor, + ), + windows: null, + ), + ); + + final splash = usePlatformProperty( + (context) => PlatformProperty.multiPlatformGroup({ + InkRipple.splashFactory: {TargetPlatform.android, TargetPlatform.linux}, + NoSplash.splashFactory: { + TargetPlatform.windows, + TargetPlatform.macOS, + TargetPlatform.iOS, + } + }), + ); + return SizedBox( height: 240, width: 200, child: InkWell( + splashFactory: splash, onTap: () { ServiceUtils.navigate(context, "/artist/${artist.id}"); }, - borderRadius: BorderRadius.circular(10), + customBorder: platform == TargetPlatform.windows + ? Border.all( + color: FluentTheme.maybeOf(context) + ?.micaBackgroundColor + .withOpacity(.7) ?? + Colors.transparent, + width: 1, + ) + : null, + borderRadius: BorderRadius.circular( + platform == TargetPlatform.windows ? 5 : 8, + ), child: HoverBuilder(builder: (context, isHovering) { return Ink( width: 200, decoration: BoxDecoration( - color: Theme.of(context).backgroundColor, - borderRadius: BorderRadius.circular(8), + color: PlatformTheme.of(context).secondaryBackgroundColor, + borderRadius: BorderRadius.circular( + platform == TargetPlatform.windows ? 5 : 8, + ), boxShadow: [ - BoxShadow( - blurRadius: 10, - offset: const Offset(0, 3), - spreadRadius: 5, - color: Theme.of(context).shadowColor, - ) + if (boxShadow != null) boxShadow, ], + border: [TargetPlatform.windows, TargetPlatform.macOS] + .contains(platform) + ? Border.all( + color: PlatformTheme.of(context).borderColor ?? + Colors.transparent, + width: 1, + ) + : null, ), child: Padding( padding: const EdgeInsets.all(15), @@ -79,7 +131,7 @@ class ArtistCard extends StatelessWidget { artist.name!, maxLines: 2, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( + style: PlatformTextTheme.of(context).body?.copyWith( fontWeight: FontWeight.bold, ), ), diff --git a/lib/components/Artist/ArtistProfile.dart b/lib/components/Artist/ArtistProfile.dart index 556ca6fa4..b16d011a9 100644 --- a/lib/components/Artist/ArtistProfile.dart +++ b/lib/components/Artist/ArtistProfile.dart @@ -31,13 +31,13 @@ class ArtistProfile extends HookConsumerWidget { Widget build(BuildContext context, ref) { SpotifyApi spotify = ref.watch(spotifyProvider); final parentScrollController = useScrollController(); - final textTheme = Theme.of(context).textTheme; + final textTheme = PlatformTheme.of(context).textTheme; final chipTextVariant = useBreakpointValue( - sm: textTheme.bodySmall, - md: textTheme.bodyMedium, - lg: textTheme.headline6, - xl: textTheme.headline6, - xxl: textTheme.headline6, + sm: textTheme!.caption, + md: textTheme.body, + lg: textTheme.subheading, + xl: textTheme.headline, + xxl: textTheme.headline, ); final avatarWidth = useBreakpointValue( @@ -53,7 +53,7 @@ class ArtistProfile extends HookConsumerWidget { final Playback playback = ref.watch(playbackProvider); return SafeArea( - child: Scaffold( + child: PlatformScaffold( appBar: const PageWindowTitleBar( leading: BackButton(), ), @@ -68,7 +68,7 @@ class ArtistProfile extends HookConsumerWidget { return const ShimmerArtistProfile(); } else if (artistsQuery.hasError) { return Center( - child: Text(artistsQuery.error.toString()), + child: PlatformText(artistsQuery.error.toString()), ); } @@ -106,21 +106,22 @@ class ArtistProfile extends HookConsumerWidget { decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(50)), - child: Text(data.type!.toUpperCase(), + child: PlatformText(data.type!.toUpperCase(), style: chipTextVariant?.copyWith( color: Colors.white)), ), - Text( + PlatformText( data.name!, style: breakpoint.isSm - ? textTheme.headline4 - : textTheme.headline2, + ? textTheme.subheading + : textTheme.headline, ), - Text( + PlatformText( "${PrimitiveUtils.toReadableNumber(data.followers!.total!.toDouble())} followers", style: breakpoint.isSm - ? textTheme.bodyText1 - : textTheme.headline5, + ? textTheme.body + : textTheme.body + ?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 20), Row( @@ -144,7 +145,7 @@ class ArtistProfile extends HookConsumerWidget { ); } - return OutlinedButton( + return PlatformFilledButton( onPressed: () async { try { isFollowingQuery.data! @@ -170,7 +171,7 @@ class ArtistProfile extends HookConsumerWidget { ]); } }, - child: Text( + child: PlatformText( isFollowingQuery.data! ? "Following" : "Follow", @@ -190,7 +191,7 @@ class ArtistProfile extends HookConsumerWidget { const SnackBar( width: 300, behavior: SnackBarBehavior.floating, - content: Text( + content: PlatformText( "Artist URL copied to clipboard", textAlign: TextAlign.center, ), @@ -218,7 +219,7 @@ class ArtistProfile extends HookConsumerWidget { return const PlatformCircularProgressIndicator(); } else if (topTracksQuery.hasError) { return Center( - child: Text(topTracksQuery.error.toString()), + child: PlatformText(topTracksQuery.error.toString()), ); } @@ -252,9 +253,10 @@ class ArtistProfile extends HookConsumerWidget { return Column(children: [ Row( children: [ - Text( + PlatformText( "Top Tracks", - style: Theme.of(context).textTheme.headline4, + style: + PlatformTheme.of(context).textTheme?.headline, ), Container( margin: const EdgeInsets.symmetric(horizontal: 5), @@ -294,16 +296,16 @@ class ArtistProfile extends HookConsumerWidget { }, ), const SizedBox(height: 50), - Text( + PlatformText( "Albums", - style: Theme.of(context).textTheme.headline4, + style: PlatformTheme.of(context).textTheme?.headline, ), const SizedBox(height: 10), ArtistAlbumList(artistId), const SizedBox(height: 20), - Text( + PlatformText( "Fans also likes", - style: Theme.of(context).textTheme.headline4, + style: PlatformTheme.of(context).textTheme?.headline, ), const SizedBox(height: 10), HookBuilder( @@ -317,7 +319,7 @@ class ArtistProfile extends HookConsumerWidget { return const PlatformCircularProgressIndicator(); } else if (relatedArtists.hasError) { return Center( - child: Text(relatedArtists.error.toString()), + child: PlatformText(relatedArtists.error.toString()), ); } diff --git a/lib/components/Category/CategoryCard.dart b/lib/components/Category/CategoryCard.dart index 550255265..c94b65f8f 100644 --- a/lib/components/Category/CategoryCard.dart +++ b/lib/components/Category/CategoryCard.dart @@ -3,6 +3,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart' hide Page; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:platform_ui/platform_ui.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/LoaderShimmers/ShimmerPlaybuttonCard.dart'; import 'package:spotube/components/Playlist/PlaylistCard.dart'; @@ -46,15 +47,13 @@ class CategoryCard extends HookConsumerWidget { padding: const EdgeInsets.all(8.0), child: Row( children: [ - Text( - category.name ?? "Unknown", - style: Theme.of(context).textTheme.headline5, - ), + PlatformText.headline(category.name ?? "Unknown"), ], ), ), playlistQuery.hasError - ? Text("Something Went Wrong\n${playlistQuery.errors.first}") + ? PlatformText( + "Something Went Wrong\n${playlistQuery.errors.first}") : SizedBox( height: 245, child: ScrollConfiguration( diff --git a/lib/components/Home/Genres.dart b/lib/components/Home/Genres.dart index 0f614f1b1..558a19b0e 100644 --- a/lib/components/Home/Genres.dart +++ b/lib/components/Home/Genres.dart @@ -42,7 +42,6 @@ class Genres extends HookConsumerWidget { ]; return PlatformScaffold( - backgroundColor: PlatformProperty.all(Colors.transparent), body: ListView.builder( itemCount: categories.length, itemBuilder: (context, index) { diff --git a/lib/components/Library/UserAlbums.dart b/lib/components/Library/UserAlbums.dart index 520afa0b3..866c1ddbd 100644 --- a/lib/components/Library/UserAlbums.dart +++ b/lib/components/Library/UserAlbums.dart @@ -1,6 +1,7 @@ import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:flutter/material.dart' hide Image; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:platform_ui/platform_ui.dart'; import 'package:spotube/components/Album/AlbumCard.dart'; import 'package:spotube/components/LoaderShimmers/ShimmerPlaybuttonCard.dart'; import 'package:spotube/provider/SpotifyDI.dart'; @@ -22,16 +23,21 @@ class UserAlbums extends HookConsumerWidget { } return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - spacing: 20, // gap between adjacent chips - runSpacing: 20, // gap between lines - alignment: WrapAlignment.center, - children: albumsQuery.data! - .map((album) => - AlbumCard(TypeConversionUtils.simpleAlbum_X_Album(album))) - .toList(), + child: Material( + type: MaterialType.transparency, + color: PlatformTheme.of(context).scaffoldBackgroundColor, + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 20, // gap between adjacent chips + runSpacing: 20, // gap between lines + alignment: WrapAlignment.center, + children: albumsQuery.data! + .map((album) => + AlbumCard(TypeConversionUtils.simpleAlbum_X_Album(album))) + .toList(), + ), ), ), ); diff --git a/lib/components/Library/UserArtists.dart b/lib/components/Library/UserArtists.dart index 1641bcb7a..921825dec 100644 --- a/lib/components/Library/UserArtists.dart +++ b/lib/components/Library/UserArtists.dart @@ -2,6 +2,7 @@ import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:platform_ui/platform_ui.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/Artist/ArtistCard.dart'; import 'package:spotube/components/Shared/Waypoint.dart'; @@ -28,26 +29,30 @@ class UserArtists extends HookConsumerWidget { ? false : (artistQuery.pages.last?.items?.length ?? 0) == 15; - return GridView.builder( - itemCount: artists.length, - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - mainAxisExtent: 250, - crossAxisSpacing: 20, - mainAxisSpacing: 20, + return Material( + type: MaterialType.transparency, + color: PlatformTheme.of(context).scaffoldBackgroundColor, + child: GridView.builder( + itemCount: artists.length, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: 250, + crossAxisSpacing: 20, + mainAxisSpacing: 20, + ), + padding: const EdgeInsets.all(10), + itemBuilder: (context, index) { + if (index == artists.length - 1 && hasNextPage) { + return Waypoint( + onEnter: () { + artistQuery.fetchNextPage(); + }, + child: ArtistCard(artists[index]), + ); + } + return ArtistCard(artists[index]); + }, ), - padding: const EdgeInsets.all(10), - itemBuilder: (context, index) { - if (index == artists.length - 1 && hasNextPage) { - return Waypoint( - onEnter: () { - artistQuery.fetchNextPage(); - }, - child: ArtistCard(artists[index]), - ); - } - return ArtistCard(artists[index]); - }, ); } } diff --git a/lib/components/Library/UserDownloads.dart b/lib/components/Library/UserDownloads.dart index 340d80718..bd7fb732f 100644 --- a/lib/components/Library/UserDownloads.dart +++ b/lib/components/Library/UserDownloads.dart @@ -26,7 +26,7 @@ class UserDownloads extends HookConsumerWidget { child: AutoSizeText( "Currently downloading (${downloader.currentlyRunning})", maxLines: 1, - style: Theme.of(context).textTheme.headline5, + style: PlatformTextTheme.of(context).headline, ), ), const SizedBox(width: 10), @@ -38,7 +38,8 @@ class UserDownloads extends HookConsumerWidget { onPressed: downloader.currentlyRunning > 0 ? downloader.cancelAll : null, - child: const Text("Cancel All"), + macOSIsSecondary: true, + child: const PlatformText("Cancel All"), ), ], ), diff --git a/lib/components/Library/UserPlaylists.dart b/lib/components/Library/UserPlaylists.dart index 26d2bf91d..705a13ddf 100644 --- a/lib/components/Library/UserPlaylists.dart +++ b/lib/components/Library/UserPlaylists.dart @@ -34,19 +34,23 @@ class UserPlaylists extends HookConsumerWidget { } return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - spacing: 20, // gap between adjacent chips - runSpacing: 20, // gap between lines - alignment: WrapAlignment.center, - children: [ - const PlaylistCreateDialog(), - PlaylistCard(likedTracksPlaylist), - ...playlistsQuery.data! - .map((playlist) => PlaylistCard(playlist)) - .toList(), - ], + child: Material( + type: MaterialType.transparency, + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(8.0), + child: Wrap( + spacing: 20, // gap between adjacent chips + runSpacing: 20, // gap between lines + alignment: WrapAlignment.center, + children: [ + const PlaylistCreateDialog(), + PlaylistCard(likedTracksPlaylist), + ...playlistsQuery.data! + .map((playlist) => PlaylistCard(playlist)) + .toList(), + ], + ), ), ), ); diff --git a/lib/components/Player/PlayerControls.dart b/lib/components/Player/PlayerControls.dart index 0bfc88187..580a346c1 100644 --- a/lib/components/Player/PlayerControls.dart +++ b/lib/components/Player/PlayerControls.dart @@ -95,7 +95,7 @@ class PlayerControls extends HookConsumerWidget { return Column( children: [ - Tooltip( + PlatformTooltip( message: "Slide to seek forward or backward", child: PlatformSlider( focusNode: FocusNode(), @@ -123,10 +123,10 @@ class PlayerControls extends HookConsumerWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( + PlatformText( "$currentMinutes:$currentSeconds", ), - Text("$totalMinutes:$totalSeconds"), + PlatformText("$totalMinutes:$totalSeconds"), ], ), ), diff --git a/lib/components/Player/PlayerTrackDetails.dart b/lib/components/Player/PlayerTrackDetails.dart index 4a8a03426..9dfc079b2 100644 --- a/lib/components/Player/PlayerTrackDetails.dart +++ b/lib/components/Player/PlayerTrackDetails.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:platform_ui/platform_ui.dart'; import 'package:spotube/components/Shared/UniversalImage.dart'; import 'package:spotube/hooks/useBreakpoints.dart'; import 'package:spotube/provider/Playback.dart'; @@ -36,13 +37,10 @@ class PlayerTrackDetails extends HookConsumerWidget { ), if (breakpoint.isLessThanOrEqualTo(Breakpoints.md)) Flexible( - child: Text( + child: PlatformText( playback.track?.name ?? "Not playing", overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .bodyText1 - ?.copyWith(fontWeight: FontWeight.bold, color: color), + style: TextStyle(fontWeight: FontWeight.bold, color: color), ), ), @@ -52,13 +50,10 @@ class PlayerTrackDetails extends HookConsumerWidget { flex: 1, child: Column( children: [ - Text( + PlatformText( playback.track?.name ?? "Not playing", overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .bodyText1 - ?.copyWith(fontWeight: FontWeight.bold, color: color), + style: TextStyle(fontWeight: FontWeight.bold, color: color), ), TypeConversionUtils.artists_X_ClickableArtists( playback.track?.artists ?? [], diff --git a/lib/components/Search/Search.dart b/lib/components/Search/Search.dart index 39982108b..240246a56 100644 --- a/lib/components/Search/Search.dart +++ b/lib/components/Search/Search.dart @@ -77,7 +77,7 @@ class Search extends HookConsumerWidget { return SafeArea( child: Material( - color: Theme.of(context).backgroundColor, + color: PlatformTheme.of(context).scaffoldBackgroundColor, child: Column( children: [ Container( @@ -85,7 +85,6 @@ class Search extends HookConsumerWidget { horizontal: 20, vertical: 10, ), - color: Theme.of(context).backgroundColor, child: PlatformTextField( onChanged: (value) { ref.read(searchTermStateProvider.notifier).state = value; @@ -136,16 +135,12 @@ class Search extends HookConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (tracks.isNotEmpty) - Text( - "Songs", - style: Theme.of(context).textTheme.headline5, - ), + if (tracks.isNotEmpty) PlatformText.headline("Songs"), if (searchTrack.isLoading && !searchTrack.isFetchingNextPage) const PlatformCircularProgressIndicator() else if (searchTrack.hasError) - Text( + PlatformText( searchTrack.error?[searchTrack.pageParams.last]) else ...tracks.asMap().entries.map((track) { @@ -191,20 +186,17 @@ class Search extends HookConsumerWidget { : () => searchTrack.fetchNextPage(), child: searchTrack.isFetchingNextPage ? const PlatformCircularProgressIndicator() - : const Text("Load more"), + : const PlatformText("Load more"), ), ), if (playlists.isNotEmpty) - Text( - "Playlists", - style: Theme.of(context).textTheme.headline5, - ), + PlatformText.headline("Playlists"), const SizedBox(height: 10), if (searchPlaylist.isLoading && !searchPlaylist.isFetchingNextPage) const PlatformCircularProgressIndicator() else if (searchPlaylist.hasError) - Text(searchPlaylist + PlatformText(searchPlaylist .error?[searchPlaylist.pageParams.last]) else ScrollConfiguration( @@ -249,16 +241,13 @@ class Search extends HookConsumerWidget { ), const SizedBox(height: 20), if (artists.isNotEmpty) - Text( - "Artists", - style: Theme.of(context).textTheme.headline5, - ), + PlatformText.headline("Artists"), const SizedBox(height: 10), if (searchArtist.isLoading && !searchArtist.isFetchingNextPage) const PlatformCircularProgressIndicator() else if (searchArtist.hasError) - Text(searchArtist + PlatformText(searchArtist .error?[searchArtist.pageParams.last]) else ScrollConfiguration( @@ -303,7 +292,7 @@ class Search extends HookConsumerWidget { ), const SizedBox(height: 20), if (albums.isNotEmpty) - Text( + PlatformText( "Albums", style: Theme.of(context).textTheme.headline5, ), @@ -312,7 +301,7 @@ class Search extends HookConsumerWidget { !searchAlbum.isFetchingNextPage) const PlatformCircularProgressIndicator() else if (searchAlbum.hasError) - Text( + PlatformText( searchAlbum.error?[searchAlbum.pageParams.last]) else ScrollConfiguration( diff --git a/lib/components/Settings/About.dart b/lib/components/Settings/About.dart index f243b561c..0d44dfb1e 100644 --- a/lib/components/Settings/About.dart +++ b/lib/components/Settings/About.dart @@ -32,7 +32,10 @@ class About extends HookWidget { return PlatformListTile( leading: const Icon(Icons.info_outline_rounded), - title: const Text("About Spotube"), + title: Text( + "About Spotube", + style: PlatformTextTheme.of(context).body, + ), onTap: () { showAboutDialog( context: context, diff --git a/lib/components/Settings/Settings.dart b/lib/components/Settings/Settings.dart index d8fde0267..28a652e4c 100644 --- a/lib/components/Settings/Settings.dart +++ b/lib/components/Settings/Settings.dart @@ -50,11 +50,11 @@ class Settings extends HookConsumerWidget { ); return SafeArea( - child: Scaffold( + child: PlatformScaffold( appBar: PageWindowTitleBar( - center: Text( + center: PlatformText( "Settings", - style: Theme.of(context).textTheme.headline5, + style: PlatformTheme.of(context).textTheme?.headline, ), ), body: Row( @@ -65,10 +65,11 @@ class Settings extends HookConsumerWidget { constraints: const BoxConstraints(maxWidth: 1366), child: ListView( children: [ - const Text( + PlatformText( " Account", - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + style: PlatformTextTheme.of(context) + .headline + ?.copyWith(fontWeight: FontWeight.bold), ), if (auth.isAnonymous) AdaptiveListTile( @@ -101,7 +102,8 @@ class Settings extends HookConsumerWidget { ), ), ), - child: Text("Connect with Spotify".toUpperCase()), + child: PlatformText( + "Connect with Spotify".toUpperCase()), ), ), if (auth.isLoggedIn) @@ -109,7 +111,7 @@ class Settings extends HookConsumerWidget { Auth auth = ref.watch(authProvider); return PlatformListTile( leading: const Icon(Icons.logout_rounded), - title: const SizedBox( + title: SizedBox( height: 50, width: 180, child: Align( @@ -117,6 +119,7 @@ class Settings extends HookConsumerWidget { child: AutoSizeText( "Log out of this account", maxLines: 1, + style: PlatformTextTheme.of(context).body, ), ), ), @@ -131,19 +134,20 @@ class Settings extends HookConsumerWidget { auth.logout(); GoRouter.of(context).pop(); }, - child: const Text("Logout"), + child: const PlatformText("Logout"), ), ); }), - const Text( + PlatformText( " Appearance", - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + style: PlatformTextTheme.of(context) + .headline + ?.copyWith(fontWeight: FontWeight.bold), ), AdaptiveListTile( leading: const Icon(Icons.dashboard_rounded), - title: const Text("Layout Mode"), - subtitle: const Text( + title: const PlatformText("Layout Mode"), + subtitle: const PlatformText( "Override responsive layout mode settings", ), trailing: (context, update) => @@ -152,19 +156,19 @@ class Settings extends HookConsumerWidget { items: [ PlatformDropDownMenuItem( value: LayoutMode.adaptive, - child: const Text( + child: const PlatformText( "Adaptive", ), ), PlatformDropDownMenuItem( value: LayoutMode.compact, - child: const Text( + child: const PlatformText( "Compact", ), ), PlatformDropDownMenuItem( value: LayoutMode.extended, - child: const Text("Extended"), + child: const PlatformText("Extended"), ), ], onChanged: (value) { @@ -177,26 +181,22 @@ class Settings extends HookConsumerWidget { ), AdaptiveListTile( leading: const Icon(Icons.dark_mode_outlined), - title: const Text("Theme"), + title: const PlatformText("Theme"), trailing: (context, update) => PlatformDropDownMenu( value: preferences.themeMode, items: [ PlatformDropDownMenuItem( value: ThemeMode.dark, - child: const Text( - "Dark", - ), + child: const PlatformText("Dark"), ), PlatformDropDownMenuItem( value: ThemeMode.light, - child: const Text( - "Light", - ), + child: const PlatformText("Light"), ), PlatformDropDownMenuItem( value: ThemeMode.system, - child: const Text("System"), + child: const PlatformText("System"), ), ], onChanged: (value) { @@ -209,7 +209,7 @@ class Settings extends HookConsumerWidget { ), PlatformListTile( leading: const Icon(Icons.palette_outlined), - title: const Text("Accent Color Scheme"), + title: const PlatformText("Accent Color Scheme"), contentPadding: const EdgeInsets.symmetric( horizontal: 15, vertical: 5, @@ -223,7 +223,7 @@ class Settings extends HookConsumerWidget { ), PlatformListTile( leading: const Icon(Icons.format_color_fill_rounded), - title: const Text("Background Color Scheme"), + title: const PlatformText("Background Color Scheme"), contentPadding: const EdgeInsets.symmetric( horizontal: 15, vertical: 5, @@ -237,7 +237,7 @@ class Settings extends HookConsumerWidget { ), PlatformListTile( leading: const Icon(Icons.album_rounded), - title: const Text("Rotating Album Art"), + title: const PlatformText("Rotating Album Art"), trailing: PlatformSwitch( value: preferences.rotatingAlbumArt, onChanged: (state) { @@ -245,27 +245,28 @@ class Settings extends HookConsumerWidget { }, ), ), - const Text( + PlatformText( " Playback", - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + style: PlatformTextTheme.of(context) + .headline + ?.copyWith(fontWeight: FontWeight.bold), ), AdaptiveListTile( leading: const Icon(Icons.multitrack_audio_rounded), - title: const Text("Audio Quality"), + title: const PlatformText("Audio Quality"), trailing: (context, update) => PlatformDropDownMenu( value: preferences.audioQuality, items: [ PlatformDropDownMenuItem( value: AudioQuality.high, - child: const Text( + child: const PlatformText( "High", ), ), PlatformDropDownMenuItem( value: AudioQuality.low, - child: const Text("Low"), + child: const PlatformText("Low"), ), ], onChanged: (value) { @@ -279,10 +280,10 @@ class Settings extends HookConsumerWidget { if (kIsMobile) PlatformListTile( leading: const Icon(Icons.download_for_offline_rounded), - title: const Text( + title: const PlatformText( "Pre download and play", ), - subtitle: const Text( + subtitle: const PlatformText( "Instead of streaming audio, download bytes and play instead (Recommended for higher bandwidth users)", ), trailing: PlatformSwitch( @@ -294,7 +295,7 @@ class Settings extends HookConsumerWidget { ), PlatformListTile( leading: const Icon(Icons.fast_forward_rounded), - title: const Text( + title: const PlatformText( "Skip non-music segments (SponsorBlock)", ), trailing: PlatformSwitch( @@ -304,20 +305,17 @@ class Settings extends HookConsumerWidget { }, ), ), - const Text( + PlatformText( " Search", - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + style: PlatformTextTheme.of(context) + .headline + ?.copyWith(fontWeight: FontWeight.bold), ), AdaptiveListTile( leading: const Icon(Icons.shopping_bag_rounded), - title: Text( - "Market Place", - style: Theme.of(context).textTheme.bodyText1, - ), - subtitle: Text( + title: const PlatformText("Market Place"), + subtitle: PlatformText.caption( "Recommendation Country", - style: Theme.of(context).textTheme.caption, ), trailing: (context, update) => ConstrainedBox( constraints: const BoxConstraints(maxWidth: 250), @@ -327,7 +325,7 @@ class Settings extends HookConsumerWidget { .map( (country) => (PlatformDropDownMenuItem( value: country.first, - child: Text(country.last), + child: PlatformText(country.last), )), ) .toList(), @@ -343,18 +341,21 @@ class Settings extends HookConsumerWidget { ), AdaptiveListTile( leading: const Icon(Icons.screen_search_desktop_rounded), - title: const SizedBox( + title: SizedBox( height: 50, width: 200, child: Align( alignment: Alignment.centerLeft, - child: AutoSizeText( - "Format of the YouTube Search term", - maxLines: 2, + child: DefaultTextStyle( + style: PlatformTextTheme.of(context).body!, + child: const AutoSizeText( + "Format of the YouTube Search term", + maxLines: 2, + ), ), ), ), - subtitle: const Text("(Case sensitive)"), + subtitle: const PlatformText("(Case sensitive)"), breakOn: Breakpoints.lg, trailing: (context, update) => ConstrainedBox( constraints: const BoxConstraints(maxWidth: 450), @@ -377,7 +378,7 @@ class Settings extends HookConsumerWidget { ), AdaptiveListTile( leading: const Icon(Icons.low_priority_rounded), - title: const SizedBox( + title: SizedBox( height: 50, width: 180, child: Align( @@ -385,6 +386,7 @@ class Settings extends HookConsumerWidget { child: AutoSizeText( "Track Match Algorithm", maxLines: 1, + style: PlatformTextTheme.of(context).body, ), ), ), @@ -394,19 +396,19 @@ class Settings extends HookConsumerWidget { items: [ PlatformDropDownMenuItem( value: SpotubeTrackMatchAlgorithm.authenticPopular, - child: const Text( + child: const PlatformText( "Popular from Author", ), ), PlatformDropDownMenuItem( value: SpotubeTrackMatchAlgorithm.popular, - child: const Text( + child: const PlatformText( "Accurately Popular", ), ), PlatformDropDownMenuItem( value: SpotubeTrackMatchAlgorithm.youtube, - child: const Text("YouTube's Top choice"), + child: const PlatformText("YouTube's Top choice"), ), ], onChanged: (value) { @@ -417,15 +419,16 @@ class Settings extends HookConsumerWidget { }, ), ), - const Text( + PlatformText( " Downloads", - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + style: PlatformTextTheme.of(context) + .headline + ?.copyWith(fontWeight: FontWeight.bold), ), PlatformListTile( leading: const Icon(Icons.file_download_outlined), - title: const Text("Download Location"), - subtitle: Text(preferences.downloadLocation), + title: const PlatformText("Download Location"), + subtitle: PlatformText(preferences.downloadLocation), trailing: PlatformFilledButton( onPressed: pickDownloadLocation, child: const Icon(Icons.folder_rounded), @@ -434,7 +437,8 @@ class Settings extends HookConsumerWidget { ), PlatformListTile( leading: const Icon(Icons.lyrics_rounded), - title: const Text("Download lyrics along with the Track"), + title: const PlatformText( + "Download lyrics along with the Track"), trailing: PlatformSwitch( value: preferences.saveTrackLyrics, onChanged: (state) { @@ -442,10 +446,11 @@ class Settings extends HookConsumerWidget { }, ), ), - const Text( + PlatformText( " About", - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 20), + style: PlatformTextTheme.of(context) + .headline + ?.copyWith(fontWeight: FontWeight.bold), ), AdaptiveListTile( leading: const Icon( @@ -487,14 +492,14 @@ class Settings extends HookConsumerWidget { children: const [ Icon(Icons.favorite_outline_rounded), SizedBox(width: 5), - Text("Please Sponsor/Donate"), + PlatformText("Please Sponsor/Donate"), ], ), ), ), PlatformListTile( leading: const Icon(Icons.update_rounded), - title: const Text("Check for Update"), + title: const PlatformText("Check for Update"), trailing: PlatformSwitch( value: preferences.checkUpdate, onChanged: (checked) => diff --git a/lib/components/Shared/AdaptivePopupMenuButton.dart b/lib/components/Shared/AdaptivePopupMenuButton.dart index fc1d0a987..5dd34b3e5 100644 --- a/lib/components/Shared/AdaptivePopupMenuButton.dart +++ b/lib/components/Shared/AdaptivePopupMenuButton.dart @@ -20,15 +20,15 @@ class Action extends StatelessWidget { @override Widget build(BuildContext context) { if (isExpanded != true) { - return Tooltip( - message: text.toStringShallow().split(",").last.replaceAll( - "\"", - "", - ), - child: PlatformIconButton( - icon: icon, - onPressed: onPressed, - ), + return PlatformIconButton( + icon: icon, + onPressed: onPressed, + tooltip: text is Text + ? (text as Text).data + : text.toStringShallow().split(",").last.replaceAll( + "\"", + "", + ), ); } return PlatformTextButton( diff --git a/lib/components/Shared/AnchorButton.dart b/lib/components/Shared/AnchorButton.dart index ede984e9a..9660cfc11 100644 --- a/lib/components/Shared/AnchorButton.dart +++ b/lib/components/Shared/AnchorButton.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:platform_ui/platform_ui.dart'; class AnchorButton extends HookWidget { final String text; @@ -28,7 +29,7 @@ class AnchorButton extends HookWidget { onTap: onTap, child: MouseRegion( cursor: MaterialStateMouseCursor.clickable, - child: Text( + child: PlatformText( text, style: style.copyWith( decoration: diff --git a/lib/components/Shared/PageWindowTitleBar.dart b/lib/components/Shared/PageWindowTitleBar.dart index 1d3afe4a0..06fd4923c 100644 --- a/lib/components/Shared/PageWindowTitleBar.dart +++ b/lib/components/Shared/PageWindowTitleBar.dart @@ -33,7 +33,7 @@ class TitleBarActionButtons extends StatelessWidget { }, style: ButtonStyle( foregroundColor: MaterialStateProperty.all( - Theme.of(context).iconTheme.color), + PlatformTheme.of(context).iconTheme?.color), ), child: Icon( Icons.minimize_rounded, @@ -45,7 +45,7 @@ class TitleBarActionButtons extends StatelessWidget { }, style: ButtonStyle( foregroundColor: MaterialStateProperty.all( - Theme.of(context).iconTheme.color), + PlatformTheme.of(context).iconTheme?.color), ), child: Icon( Icons.crop_square_rounded, @@ -57,7 +57,7 @@ class TitleBarActionButtons extends StatelessWidget { }, style: ButtonStyle( foregroundColor: MaterialStateProperty.all( - color ?? Theme.of(context).iconTheme.color), + color ?? PlatformTheme.of(context).iconTheme?.color), overlayColor: MaterialStateProperty.all(Colors.redAccent), ), child: const Icon( diff --git a/lib/components/Shared/PlaybuttonCard.dart b/lib/components/Shared/PlaybuttonCard.dart index b86c2a927..7f88d17ec 100644 --- a/lib/components/Shared/PlaybuttonCard.dart +++ b/lib/components/Shared/PlaybuttonCard.dart @@ -77,6 +77,7 @@ class PlaybuttonCard extends HookWidget { onTap: onTap, borderRadius: BorderRadius.circular(8), splashFactory: splash, + highlightColor: Colors.black12, child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 200), child: HoverBuilder(builder: (context, isHovering) { @@ -89,11 +90,10 @@ class PlaybuttonCard extends HookWidget { boxShadow: [ if (boxShadow != null) boxShadow, ], - border: platform == TargetPlatform.windows + border: [TargetPlatform.windows, TargetPlatform.macOS] + .contains(platform) ? Border.all( - color: FluentUI.FluentTheme.maybeOf(context) - ?.micaBackgroundColor - .withOpacity(.7) ?? + color: PlatformTheme.of(context).borderColor ?? Colors.transparent, width: 1, ) diff --git a/lib/components/Shared/TrackCollectionView.dart b/lib/components/Shared/TrackCollectionView.dart index f89d750a4..b42ef7cc0 100644 --- a/lib/components/Shared/TrackCollectionView.dart +++ b/lib/components/Shared/TrackCollectionView.dart @@ -132,12 +132,12 @@ class TrackCollectionView extends HookConsumerWidget { primary: true, backgroundColor: color?.color, title: collapsed.value - ? Text( + ? PlatformText.headline( title, - style: Theme.of(context).textTheme.headline4?.copyWith( - color: color?.titleTextColor, - fontWeight: FontWeight.w600, - ), + style: TextStyle( + color: color?.titleTextColor, + fontWeight: FontWeight.w600, + ), ) : null, flexibleSpace: LayoutBuilder(builder: (context, constrains) { @@ -188,25 +188,19 @@ class TrackCollectionView extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( + PlatformText.headline( title, - style: Theme.of(context) - .textTheme - .headline4 - ?.copyWith( - color: color?.titleTextColor, - fontWeight: FontWeight.w600, - ), + style: TextStyle( + color: color?.titleTextColor, + fontWeight: FontWeight.w600, + ), ), if (description != null) - Text( + PlatformText( description!, - style: Theme.of(context) - .textTheme - .bodyLarge - ?.copyWith( - color: color?.bodyTextColor, - ), + style: TextStyle( + color: color?.bodyTextColor, + ), maxLines: 2, overflow: TextOverflow.fade, ), @@ -232,7 +226,7 @@ class TrackCollectionView extends HookConsumerWidget { } else if (tracksSnapshot.hasError && tracksSnapshot.isError) { return SliverToBoxAdapter( - child: Text("Error ${tracksSnapshot.error}")); + child: PlatformText("Error ${tracksSnapshot.error}")); } final tracks = tracksSnapshot.data!; diff --git a/lib/components/Shared/TrackTile.dart b/lib/components/Shared/TrackTile.dart index 4605fd0bc..8250e768f 100644 --- a/lib/components/Shared/TrackTile.dart +++ b/lib/components/Shared/TrackTile.dart @@ -74,7 +74,7 @@ class TrackTile extends HookConsumerWidget { SnackBar( width: 300, behavior: SnackBarBehavior.floating, - content: Text( + content: PlatformText( "Copied $data to clipboard", textAlign: TextAlign.center, ), @@ -98,7 +98,7 @@ class TrackTile extends HookConsumerWidget { return HookBuilder(builder: (context) { final playlistsCheck = useState({}); return AlertDialog( - title: Text( + title: PlatformText( "Add `${track.value.name}` to following Playlists"), titleTextStyle: Theme.of(context).textTheme.bodyText1?.copyWith( @@ -107,11 +107,11 @@ class TrackTile extends HookConsumerWidget { ), actions: [ PlatformTextButton( - child: const Text("Cancel"), + child: const PlatformText("Cancel"), onPressed: () => Navigator.pop(context), ), PlatformFilledButton( - child: const Text("Add"), + child: const PlatformText("Add"), onPressed: () async { final selectedPlaylists = playlistsCheck .value.entries @@ -140,7 +140,7 @@ class TrackTile extends HookConsumerWidget { final playlist = snapshot.data!.elementAt(index); return CheckboxListTile( - title: Text(playlist.name!), + title: PlatformText(playlist.name!), controlAffinity: ListTileControlAffinity.leading, value: playlistsCheck.value[playlist.id] ?? @@ -191,7 +191,7 @@ class TrackTile extends HookConsumerWidget { height: 20, width: 25, child: Center( - child: Text((track.key + 1).toString()), + child: PlatformText((track.key + 1).toString()), ), ), Padding( @@ -221,7 +221,7 @@ class TrackTile extends HookConsumerWidget { playback.track?.id == track.value.id ? Icons.pause_circle_rounded : Icons.play_circle_rounded, - color: Theme.of(context).primaryColor, + color: PlatformTheme.of(context).primaryColor, ), onPressed: () => onTrackPlayButtonPressed?.call( track.value, @@ -231,7 +231,7 @@ class TrackTile extends HookConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( + PlatformText( track.value.name ?? "", style: TextStyle( fontWeight: FontWeight.bold, @@ -240,7 +240,7 @@ class TrackTile extends HookConsumerWidget { overflow: TextOverflow.ellipsis, ), isReallyLocal - ? Text( + ? PlatformText( TypeConversionUtils.artists_X_String( track.value.artists ?? []), ) @@ -256,7 +256,7 @@ class TrackTile extends HookConsumerWidget { if (breakpoint.isMoreThan(Breakpoints.md) && showAlbum) Expanded( child: isReallyLocal - ? Text(track.value.album?.name ?? "") + ? PlatformText(track.value.album?.name ?? "") : LinkText( track.value.album!.name!, "/album/${track.value.album?.id}", @@ -266,7 +266,7 @@ class TrackTile extends HookConsumerWidget { ), if (!breakpoint.isSm) ...[ const SizedBox(width: 10), - Text(duration), + PlatformText(duration), ], const SizedBox(width: 10), if (!isReallyLocal) @@ -280,7 +280,7 @@ class TrackTile extends HookConsumerWidget { color: Colors.pink, ) : const Icon(Icons.favorite_border_rounded), - text: const Text("Save as favorite"), + text: const PlatformText("Save as favorite"), onPressed: () { toggler.item2.mutate(Tuple2(spotify, toggler.item1)); }, @@ -288,18 +288,18 @@ class TrackTile extends HookConsumerWidget { if (auth.isLoggedIn) Action( icon: const Icon(Icons.add_box_rounded), - text: const Text("Add To playlist"), + text: const PlatformText("Add To playlist"), onPressed: actionAddToPlaylist, ), if (userPlaylist && auth.isLoggedIn) Action( icon: const Icon(Icons.remove_circle_outline_rounded), - text: const Text("Remove from playlist"), + text: const PlatformText("Remove from playlist"), onPressed: actionRemoveFromPlaylist, ), Action( icon: const Icon(Icons.share_rounded), - text: const Text("Share"), + text: const PlatformText("Share"), onPressed: () { actionShare(track.value); }, diff --git a/lib/components/Shared/TracksTableView.dart b/lib/components/Shared/TracksTableView.dart index 212104408..05922eb93 100644 --- a/lib/components/Shared/TracksTableView.dart +++ b/lib/components/Shared/TracksTableView.dart @@ -82,7 +82,7 @@ class TracksTableView extends HookConsumerWidget { ), Padding( padding: const EdgeInsets.all(8.0), - child: Text( + child: PlatformText( "#", textAlign: TextAlign.center, style: tableHeadStyle, @@ -91,7 +91,7 @@ class TracksTableView extends HookConsumerWidget { Expanded( child: Row( children: [ - Text( + PlatformText( "Title", style: tableHeadStyle, overflow: TextOverflow.ellipsis, @@ -105,7 +105,7 @@ class TracksTableView extends HookConsumerWidget { Expanded( child: Row( children: [ - Text( + PlatformText( "Album", overflow: TextOverflow.ellipsis, style: tableHeadStyle, @@ -116,7 +116,7 @@ class TracksTableView extends HookConsumerWidget { ], if (!breakpoint.isSm) ...[ const SizedBox(width: 10), - Text("Time", style: tableHeadStyle), + PlatformText("Time", style: tableHeadStyle), const SizedBox(width: 10), ], SortTracksDropdown( @@ -135,7 +135,7 @@ class TracksTableView extends HookConsumerWidget { child: Row( children: [ const Icon(Icons.file_download_outlined), - Text( + PlatformText( "Download ${selectedTracks.isNotEmpty ? "(${selectedTracks.length})" : ""}", ), ], diff --git a/lib/main.dart b/lib/main.dart index 688cf9c2b..cdc1260e0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -201,7 +201,7 @@ class SpotubeState extends ConsumerState with WidgetsBindingObserver { }; }, []); - platform = TargetPlatform.windows; + platform = TargetPlatform.macOS; return PlatformApp.router( routeInformationParser: router.routeInformationParser, diff --git a/lib/themes/light-theme.dart b/lib/themes/light-theme.dart index dbf5996a7..5a9d55908 100644 --- a/lib/themes/light-theme.dart +++ b/lib/themes/light-theme.dart @@ -134,14 +134,17 @@ final windowsDarkTheme = FluentUI.ThemeData.dark().copyWith( ), ); final macosTheme = MacosThemeData.light().copyWith( - pushButtonTheme: PushButtonThemeData( + pushButtonTheme: const PushButtonThemeData( secondaryColor: Colors.white, ), - iconTheme: MacosIconThemeData(size: 16), - iconButtonTheme: MacosIconButtonThemeData(), - typography: MacosTypography(color: Colors.green), + iconTheme: const MacosIconThemeData(size: 14), + typography: MacosTypography(color: Colors.grey[900]!), ); final macosDarkTheme = MacosThemeData.dark().copyWith( - typography: MacosTypography(color: Colors.red), + pushButtonTheme: const PushButtonThemeData( + secondaryColor: Colors.white, + ), + iconTheme: const MacosIconThemeData(size: 14), + typography: MacosTypography(color: MacosColors.textColor), ); final iosTheme = CupertinoThemeData();