mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 15:35:17 +00:00
feat: Player and Playbutton theme respect to platform
This commit is contained in:
parent
69739b4572
commit
512446dcab
@ -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/Category/CategoryCard.dart';
|
||||
import 'package:spotube/components/LoaderShimmers/ShimmerCategories.dart';
|
||||
@ -40,7 +41,8 @@ class Genres extends HookConsumerWidget {
|
||||
.toList()
|
||||
];
|
||||
|
||||
return Scaffold(
|
||||
return PlatformScaffold(
|
||||
backgroundColor: PlatformProperty.all(Colors.transparent),
|
||||
body: ListView.builder(
|
||||
itemCount: categories.length,
|
||||
itemBuilder: (context, index) {
|
||||
|
@ -1,11 +1,16 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:macos_ui/macos_ui.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' as FluentUI;
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Player/PlayerActions.dart';
|
||||
import 'package:spotube/components/Player/PlayerOverlay.dart';
|
||||
import 'package:spotube/components/Player/PlayerTrackDetails.dart';
|
||||
import 'package:spotube/components/Player/PlayerControls.dart';
|
||||
import 'package:spotube/hooks/useBreakpoints.dart';
|
||||
import 'package:spotube/hooks/usePlatformProperty.dart';
|
||||
import 'package:spotube/models/Logger.dart';
|
||||
import 'package:spotube/provider/Playback.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -46,8 +51,43 @@ class Player extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
final backgroundColor = usePlatformProperty<Color?>(
|
||||
(context) => PlatformProperty(
|
||||
android: Theme.of(context).backgroundColor,
|
||||
ios: CupertinoTheme.of(context).scaffoldBackgroundColor,
|
||||
macos: MacosTheme.of(context).brightness == Brightness.dark
|
||||
? Colors.grey[800]
|
||||
: Colors.blueGrey[50],
|
||||
linux: Theme.of(context).backgroundColor,
|
||||
windows: FluentUI.FluentTheme.maybeOf(context)?.micaBackgroundColor,
|
||||
),
|
||||
);
|
||||
|
||||
final border = usePlatformProperty<BoxBorder?>(
|
||||
(context) => PlatformProperty(
|
||||
android: null,
|
||||
ios: Border(
|
||||
top: BorderSide(
|
||||
color: CupertinoTheme.of(context).barBackgroundColor,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
macos: Border(
|
||||
top: BorderSide(
|
||||
color: MacosTheme.of(context).dividerColor,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
linux: null,
|
||||
windows: null,
|
||||
),
|
||||
);
|
||||
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
border: border,
|
||||
),
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Row(
|
||||
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:macos_ui/macos_ui.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Settings/About.dart';
|
||||
import 'package:spotube/components/Settings/ColorSchemePickerDialog.dart';
|
||||
@ -467,10 +468,13 @@ class Settings extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
trailing: (context, update) => PlatformFilledButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.red[100],
|
||||
foregroundColor: Colors.pinkAccent,
|
||||
padding: const EdgeInsets.all(15),
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStatePropertyAll(Colors.red[100]),
|
||||
foregroundColor:
|
||||
const MaterialStatePropertyAll(Colors.pinkAccent),
|
||||
padding: const MaterialStatePropertyAll(
|
||||
EdgeInsets.all(15)),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrlString(
|
||||
@ -479,8 +483,10 @@ class Settings extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: const [
|
||||
Icon(Icons.favorite_outline_rounded),
|
||||
SizedBox(width: 5),
|
||||
Text("Please Sponsor/Donate"),
|
||||
],
|
||||
),
|
||||
|
@ -27,7 +27,7 @@ class TitleBarActionButtons extends StatelessWidget {
|
||||
data: const IconThemeData(size: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
PlatformTextButton(
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
appWindow.minimize();
|
||||
},
|
||||
@ -39,7 +39,7 @@ class TitleBarActionButtons extends StatelessWidget {
|
||||
Icons.minimize_rounded,
|
||||
color: color,
|
||||
)),
|
||||
PlatformTextButton(
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
appWindow.maximizeOrRestore();
|
||||
},
|
||||
@ -51,7 +51,7 @@ class TitleBarActionButtons extends StatelessWidget {
|
||||
Icons.crop_square_rounded,
|
||||
color: color,
|
||||
)),
|
||||
PlatformTextButton(
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
appWindow.close();
|
||||
},
|
||||
|
@ -1,10 +1,15 @@
|
||||
import 'package:fluent_ui/fluent_ui.dart' as FluentUI;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:macos_ui/macos_ui.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Shared/HoverBuilder.dart';
|
||||
import 'package:spotube/components/Shared/SpotubeMarqueeText.dart';
|
||||
import 'package:spotube/components/Shared/UniversalImage.dart';
|
||||
import 'package:spotube/hooks/usePlatformProperty.dart';
|
||||
|
||||
class PlaybuttonCard extends StatelessWidget {
|
||||
class PlaybuttonCard extends HookWidget {
|
||||
final void Function()? onTap;
|
||||
final void Function()? onPlaybuttonPressed;
|
||||
final String? description;
|
||||
@ -27,26 +32,109 @@ class PlaybuttonCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final backgroundColor = usePlatformProperty<Color?>(
|
||||
(context) => PlatformProperty(
|
||||
android: Theme.of(context).backgroundColor,
|
||||
ios: CupertinoTheme.of(context).scaffoldBackgroundColor,
|
||||
macos: MacosTheme.of(context).brightness == Brightness.dark
|
||||
? Colors.grey[800]
|
||||
: Colors.blueGrey[50],
|
||||
linux: Theme.of(context).backgroundColor,
|
||||
windows: FluentUI.FluentTheme.maybeOf(context)?.scaffoldBackgroundColor,
|
||||
),
|
||||
);
|
||||
|
||||
final boxShadow = usePlatformProperty<BoxShadow?>(
|
||||
(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 titleStyle = usePlatformProperty<TextStyle?>(
|
||||
(context) => PlatformProperty(
|
||||
android: Theme.of(context).textTheme.bodyMedium,
|
||||
ios: CupertinoTheme.of(context).textTheme.textStyle,
|
||||
macos: MacosTheme.of(context).typography.body,
|
||||
linux: Theme.of(context).textTheme.bodyMedium,
|
||||
windows: FluentUI.FluentTheme.maybeOf(context)?.typography.body,
|
||||
),
|
||||
);
|
||||
|
||||
final descriptionStyle = usePlatformProperty<TextStyle?>(
|
||||
(context) => PlatformProperty(
|
||||
android: Theme.of(context).textTheme.caption,
|
||||
ios: CupertinoTheme.of(context)
|
||||
.textTheme
|
||||
.textStyle
|
||||
.copyWith(fontSize: 13),
|
||||
macos: MacosTheme.of(context).typography.caption1,
|
||||
linux: Theme.of(context).textTheme.caption,
|
||||
windows: FluentUI.FluentTheme.maybeOf(context)?.typography.caption,
|
||||
),
|
||||
);
|
||||
|
||||
final splash = usePlatformProperty<InteractiveInkFeatureFactory?>(
|
||||
(context) => PlatformProperty.multiPlatformGroup({
|
||||
InkRipple.splashFactory: {TargetPlatform.android, TargetPlatform.linux},
|
||||
NoSplash.splashFactory: {
|
||||
TargetPlatform.windows,
|
||||
TargetPlatform.macOS,
|
||||
TargetPlatform.iOS,
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
final iconBgColor = usePlatformProperty<Color?>(
|
||||
(context) => PlatformProperty(
|
||||
android: Theme.of(context).primaryColor,
|
||||
ios: CupertinoTheme.of(context).primaryColor,
|
||||
macos: MacosTheme.of(context).primaryColor,
|
||||
linux: Theme.of(context).primaryColor,
|
||||
windows: FluentUI.FluentTheme.maybeOf(context)?.accentColor,
|
||||
),
|
||||
);
|
||||
|
||||
return Container(
|
||||
margin: margin,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
splashFactory: splash,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 200),
|
||||
child: HoverBuilder(builder: (context, isHovering) {
|
||||
return Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: backgroundColor,
|
||||
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: platform == TargetPlatform.windows
|
||||
? Border.all(
|
||||
color: FluentUI.FluentTheme.maybeOf(context)
|
||||
?.micaBackgroundColor
|
||||
.withOpacity(.7) ??
|
||||
Colors.transparent,
|
||||
width: 1,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
@ -54,13 +142,20 @@ class PlaybuttonCard extends StatelessWidget {
|
||||
// thumbnail of the playlist
|
||||
Stack(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: UniversalImage(
|
||||
path: imageUrl,
|
||||
width: 200,
|
||||
placeholder: (context, url) =>
|
||||
Image.asset("assets/placeholder.png"),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(
|
||||
platform == TargetPlatform.windows ? 5 : 0,
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
platform == TargetPlatform.windows ? 5 : 8,
|
||||
),
|
||||
child: UniversalImage(
|
||||
path: imageUrl,
|
||||
width: 200,
|
||||
placeholder: (context, url) =>
|
||||
Image.asset("assets/placeholder.png"),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned.directional(
|
||||
@ -68,27 +163,26 @@ class PlaybuttonCard extends StatelessWidget {
|
||||
bottom: 10,
|
||||
end: 5,
|
||||
child: Builder(builder: (context) {
|
||||
return PlatformFilledButton(
|
||||
onPressed: onPlaybuttonPressed,
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(
|
||||
const CircleBorder(),
|
||||
),
|
||||
padding: MaterialStateProperty.all(
|
||||
const EdgeInsets.all(16),
|
||||
),
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: iconBgColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: PlatformIconButton(
|
||||
onPressed: onPlaybuttonPressed,
|
||||
icon: isLoading
|
||||
? const SizedBox(
|
||||
height: 23,
|
||||
width: 23,
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: Icon(
|
||||
isPlaying
|
||||
? Icons.pause_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
color: backgroundColor,
|
||||
),
|
||||
),
|
||||
child: isLoading
|
||||
? const SizedBox(
|
||||
height: 23,
|
||||
width: 23,
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: Icon(
|
||||
isPlaying
|
||||
? Icons.pause_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
),
|
||||
);
|
||||
}),
|
||||
)
|
||||
@ -106,8 +200,8 @@ class PlaybuttonCard extends StatelessWidget {
|
||||
height: 20,
|
||||
child: SpotubeMarqueeText(
|
||||
text: title,
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.bold),
|
||||
style: titleStyle?.copyWith(
|
||||
fontWeight: FontWeight.bold),
|
||||
isHovering: isHovering,
|
||||
),
|
||||
),
|
||||
@ -118,13 +212,7 @@ class PlaybuttonCard extends StatelessWidget {
|
||||
height: 30,
|
||||
child: SpotubeMarqueeText(
|
||||
text: description!,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.headline4
|
||||
?.color,
|
||||
),
|
||||
style: descriptionStyle,
|
||||
isHovering: isHovering,
|
||||
),
|
||||
),
|
||||
|
10
lib/hooks/usePlatformProperty.dart
Normal file
10
lib/hooks/usePlatformProperty.dart
Normal file
@ -0,0 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
|
||||
T usePlatformProperty<T>(
|
||||
PlatformProperty<T> Function(BuildContext context) getProperties) {
|
||||
final context = useContext();
|
||||
|
||||
return getProperties(context).resolve(platform ?? Theme.of(context).platform);
|
||||
}
|
@ -3,11 +3,13 @@ import 'dart:convert';
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:fl_query/fl_query.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' as FluentUI;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:macos_ui/macos_ui.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:spotube/components/Shared/ReplaceDownloadedFileDialog.dart';
|
||||
@ -199,7 +201,7 @@ class SpotubeState extends ConsumerState<Spotube> with WidgetsBindingObserver {
|
||||
};
|
||||
}, []);
|
||||
|
||||
platform = TargetPlatform.windows;
|
||||
platform = TargetPlatform.macOS;
|
||||
|
||||
return PlatformApp.router(
|
||||
routeInformationParser: router.routeInformationParser,
|
||||
@ -215,6 +217,11 @@ class SpotubeState extends ConsumerState<Spotube> with WidgetsBindingObserver {
|
||||
accentMaterialColor: accentMaterialColor,
|
||||
backgroundMaterialColor: backgroundMaterialColor,
|
||||
),
|
||||
iosTheme: iosTheme,
|
||||
windowsTheme: windowsTheme,
|
||||
windowsDarkTheme: windowsDarkTheme,
|
||||
macosTheme: macosTheme,
|
||||
macosDarkTheme: macosDarkTheme,
|
||||
themeMode: themeMode,
|
||||
shortcuts: PlatformProperty.all({
|
||||
...WidgetsApp.defaultShortcuts.map((key, value) {
|
||||
|
@ -1,5 +1,8 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:macos_ui/macos_ui.dart';
|
||||
import 'package:spotube/extensions/ShimmerColorTheme.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' as FluentUI;
|
||||
|
||||
final materialWhite = MaterialColor(Colors.white.value, {
|
||||
50: Colors.white,
|
||||
@ -115,3 +118,27 @@ ThemeData lightTheme({
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final windowsTheme = FluentUI.ThemeData.light().copyWith(
|
||||
buttonTheme: FluentUI.ButtonThemeData(
|
||||
iconButtonStyle: FluentUI.ButtonStyle(
|
||||
iconSize: FluentUI.ButtonState.all(20),
|
||||
),
|
||||
),
|
||||
);
|
||||
final windowsDarkTheme = FluentUI.ThemeData.dark().copyWith(
|
||||
buttonTheme: FluentUI.ButtonThemeData(
|
||||
iconButtonStyle: FluentUI.ButtonStyle(
|
||||
iconSize: FluentUI.ButtonState.all(20),
|
||||
),
|
||||
),
|
||||
);
|
||||
final macosTheme = MacosThemeData.light().copyWith(
|
||||
pushButtonTheme: PushButtonThemeData(
|
||||
secondaryColor: Colors.white,
|
||||
),
|
||||
iconTheme: MacosIconThemeData(size: 16),
|
||||
iconButtonTheme: MacosIconButtonThemeData(),
|
||||
);
|
||||
final macosDarkTheme = MacosThemeData.dark();
|
||||
final iosTheme = CupertinoThemeData();
|
||||
|
@ -494,7 +494,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
fluent_ui:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluent_ui
|
||||
url: "https://pub.dartlang.org"
|
||||
@ -759,7 +759,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
macos_ui:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: macos_ui
|
||||
url: "https://pub.dartlang.org"
|
||||
|
@ -64,6 +64,8 @@ dependencies:
|
||||
uuid: ^3.0.6
|
||||
platform_ui:
|
||||
path: ../platform_ui
|
||||
fluent_ui: ^4.0.3
|
||||
macos_ui: ^1.7.5
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user