High Constrast color scheme support added

Download button shows done if already downloaded
Search TextField design improved
This commit is contained in:
Kingkor Roy Tirtho 2022-07-09 02:19:27 +06:00
parent 3702e29135
commit ff4e5df44c
5 changed files with 95 additions and 47 deletions

View File

@ -5,6 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:scroll_to_index/scroll_to_index.dart'; import 'package:scroll_to_index/scroll_to_index.dart';
import 'package:spotube/components/Shared/NotFound.dart'; import 'package:spotube/components/Shared/NotFound.dart';
import 'package:spotube/components/Shared/SpotubeMarqueeText.dart';
import 'package:spotube/components/Shared/TrackTile.dart'; import 'package:spotube/components/Shared/TrackTile.dart';
import 'package:spotube/helpers/image-to-url-string.dart'; import 'package:spotube/helpers/image-to-url-string.dart';
import 'package:spotube/helpers/zero-pad-num-str.dart'; import 'package:spotube/helpers/zero-pad-num-str.dart';
@ -48,6 +49,9 @@ class PlayerQueue extends HookConsumerWidget {
return null; return null;
}, []); }, []);
var titleStyle = Theme.of(context).textTheme.headline4?.copyWith(
fontWeight: FontWeight.bold,
);
return BackdropFilter( return BackdropFilter(
filter: ImageFilter.blur( filter: ImageFilter.blur(
sigmaX: 12.0, sigmaX: 12.0,
@ -76,12 +80,17 @@ class PlayerQueue extends HookConsumerWidget {
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
), ),
Text( Text("Queue", style: titleStyle),
"Queue (${playback.playlist?.name})", Padding(
style: Theme.of(context).textTheme.headline4?.copyWith( padding: const EdgeInsets.symmetric(horizontal: 8.0),
fontWeight: FontWeight.bold, child: Text(
), playback.playlist?.name ?? "",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: Theme.of(context)
.textTheme
.bodyText1
?.copyWith(fontWeight: FontWeight.bold),
),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Flexible( Flexible(

View File

@ -43,36 +43,30 @@ class Search extends HookConsumerWidget {
color: Theme.of(context).backgroundColor, color: Theme.of(context).backgroundColor,
child: Column( child: Column(
children: [ children: [
Padding( Container(
padding: padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 10), const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Row( color: Theme.of(context).backgroundColor,
children: [ child: Expanded(
Expanded( child: TextField(
child: TextField( controller: controller,
controller: controller, decoration: InputDecoration(
decoration: isDense: true,
const InputDecoration(hintText: "Search..."), suffix: ElevatedButton(
onSubmitted: (value) { child: const Icon(Icons.search_rounded),
onPressed: () {
ref.read(searchTermStateProvider.notifier).state = ref.read(searchTermStateProvider.notifier).state =
controller.value.text; controller.value.text;
}, },
), ),
hintStyle: const TextStyle(height: 2),
hintText: "Search...",
), ),
const SizedBox(width: 5), onSubmitted: (value) {
MaterialButton( ref.read(searchTermStateProvider.notifier).state =
elevation: 3, controller.value.text;
splashColor: Theme.of(context).primaryColor, },
padding: const EdgeInsets.symmetric(vertical: 21), ),
color: Theme.of(context).primaryColor,
textColor: Colors.white,
child: const Icon(Icons.search_rounded),
onPressed: () {
ref.read(searchTermStateProvider.notifier).state =
controller.value.text;
},
),
],
), ),
), ),
searchSnapshot.when( searchSnapshot.when(

View File

@ -3,6 +3,23 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/provider/UserPreferences.dart'; import 'package:spotube/provider/UserPreferences.dart';
final highContrast = MaterialColor(
const Color.fromARGB(255, 104, 104, 104).value,
const {
50: Colors.white,
100: Color.fromARGB(255, 233, 233, 233),
200: Color.fromARGB(255, 224, 219, 219),
300: Color.fromARGB(255, 207, 207, 207),
400: Color.fromARGB(255, 146, 146, 146),
500: Color.fromARGB(255, 104, 104, 104),
600: Color.fromARGB(255, 78, 78, 78),
700: Color.fromARGB(255, 61, 61, 61),
800: Color.fromARGB(255, 27, 27, 27),
850: Color.fromARGB(255, 20, 20, 20),
900: Colors.black,
},
);
final colorsMap = { final colorsMap = {
"Red": Colors.red, "Red": Colors.red,
"Pink": Colors.pink, "Pink": Colors.pink,
@ -23,6 +40,7 @@ final colorsMap = {
"Brown": Colors.brown, "Brown": Colors.brown,
"BlueGrey": Colors.blueGrey, "BlueGrey": Colors.blueGrey,
"Grey": Colors.grey, "Grey": Colors.grey,
"HighContrast": highContrast,
}; };
enum ColorSchemeType { enum ColorSchemeType {

View File

@ -29,8 +29,29 @@ class DownloadTrackButton extends HookConsumerWidget {
final status = useState<TrackStatus>(TrackStatus.idle); final status = useState<TrackStatus>(TrackStatus.idle);
YoutubeExplode yt = useMemoized(() => YoutubeExplode()); YoutubeExplode yt = useMemoized(() => YoutubeExplode());
final outputFile = useState<File?>(null);
final downloadFolder = useState<String?>(null);
String fileName =
"${track?.name} - ${artistsToString<Artist>(track?.artists ?? [])}";
useEffect(() {
(() async {
downloadFolder.value = path.join(
Platform.isAndroid
? "/storage/emulated/0/Download"
: (await path_provider.getDownloadsDirectory())!.path,
"Spotube");
outputFile.value =
File(path.join(downloadFolder.value!, "$fileName.mp3"));
}());
return null;
}, [fileName, track]);
final _downloadTrack = useCallback(() async { final _downloadTrack = useCallback(() async {
if (track == null) return; if (track == null ||
outputFile.value == null ||
downloadFolder.value == null) return;
if ((kIsMobile) && if ((kIsMobile) &&
!await Permission.storage.isGranted && !await Permission.storage.isGranted &&
!await Permission.storage.isPermanentlyDenied) { !await Permission.storage.isPermanentlyDenied) {
@ -47,18 +68,10 @@ class DownloadTrackButton extends HookConsumerWidget {
StreamManifest manifest = await yt.videos.streamsClient StreamManifest manifest = await yt.videos.streamsClient
.getManifest((track as SpotubeTrack).ytTrack.url); .getManifest((track as SpotubeTrack).ytTrack.url);
String downloadFolder = path.join(
Platform.isAndroid
? "/storage/emulated/0/Download"
: (await path_provider.getDownloadsDirectory())!.path,
"Spotube");
String fileName =
"${track?.name} - ${artistsToString<Artist>(track?.artists ?? [])}";
File outputFile = File(path.join(downloadFolder, "$fileName.mp3"));
File outputLyricsFile = File outputLyricsFile =
File(path.join(downloadFolder, "$fileName-lyrics.txt")); File(path.join(downloadFolder.value!, "$fileName-lyrics.txt"));
if (await outputFile.exists()) { if (await outputFile.value!.exists()) {
final shouldReplace = await showDialog<bool>( final shouldReplace = await showDialog<bool>(
context: context, context: context,
builder: (context) { builder: (context) {
@ -113,9 +126,11 @@ class DownloadTrackButton extends HookConsumerWidget {
}, },
); );
if (!await outputFile.exists()) await outputFile.create(recursive: true); if (!await outputFile.value!.exists()) {
await outputFile.value!.create(recursive: true);
}
IOSink outputFileStream = outputFile.openWrite(); IOSink outputFileStream = outputFile.value!.openWrite();
await audioStream.pipe(outputFileStream); await audioStream.pipe(outputFileStream);
await outputFileStream.flush(); await outputFileStream.flush();
await outputFileStream.close().then((value) async { await outputFileStream.close().then((value) async {
@ -157,12 +172,20 @@ class DownloadTrackButton extends HookConsumerWidget {
yt, yt,
preferences.saveTrackLyrics, preferences.saveTrackLyrics,
playback.track, playback.track,
outputFile.value,
downloadFolder.value,
fileName
]); ]);
useEffect(() { useEffect(() {
return () => yt.close(); return () => yt.close();
}, []); }, []);
final outputFileExists = useMemoized(
() => outputFile.value?.existsSync() == true,
[outputFile.value, status.value, track],
);
if (status.value == TrackStatus.downloading) { if (status.value == TrackStatus.downloading) {
return const SizedBox( return const SizedBox(
child: CircularProgressIndicator.adaptive( child: CircularProgressIndicator.adaptive(
@ -175,7 +198,9 @@ class DownloadTrackButton extends HookConsumerWidget {
return const Icon(Icons.download_done_rounded); return const Icon(Icons.download_done_rounded);
} }
return IconButton( return IconButton(
icon: const Icon(Icons.download_rounded), icon: Icon(
outputFileExists ? Icons.download_done_rounded : Icons.download_rounded,
),
onPressed: track != null && track is SpotubeTrack ? _downloadTrack : null, onPressed: track != null && track is SpotubeTrack ? _downloadTrack : null,
); );
} }

View File

@ -29,6 +29,7 @@ class PlaybuttonCard extends StatelessWidget {
margin: margin, margin: margin,
child: InkWell( child: InkWell(
onTap: onTap, onTap: onTap,
borderRadius: BorderRadius.circular(8),
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 200), constraints: const BoxConstraints(maxWidth: 200),
child: Ink( child: Ink(
@ -37,10 +38,11 @@ class PlaybuttonCard extends StatelessWidget {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
blurRadius: 10, blurRadius: 10,
offset: const Offset(0, 3), offset: const Offset(0, 3),
spreadRadius: 5, spreadRadius: 5,
color: Theme.of(context).shadowColor) color: Theme.of(context).shadowColor,
)
], ],
), ),
child: Column( child: Column(