mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
High Constrast color scheme support added
Download button shows done if already downloaded Search TextField design improved
This commit is contained in:
parent
3702e29135
commit
ff4e5df44c
@ -5,6 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:scroll_to_index/scroll_to_index.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/helpers/image-to-url-string.dart';
|
||||
import 'package:spotube/helpers/zero-pad-num-str.dart';
|
||||
@ -48,6 +49,9 @@ class PlayerQueue extends HookConsumerWidget {
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
var titleStyle = Theme.of(context).textTheme.headline4?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
);
|
||||
return BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: 12.0,
|
||||
@ -76,12 +80,17 @@ class PlayerQueue extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Queue (${playback.playlist?.name})",
|
||||
style: Theme.of(context).textTheme.headline4?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
Text("Queue", style: titleStyle),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(
|
||||
playback.playlist?.name ?? "",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText1
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Flexible(
|
||||
|
@ -43,36 +43,30 @@ class Search extends HookConsumerWidget {
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
decoration:
|
||||
const InputDecoration(hintText: "Search..."),
|
||||
onSubmitted: (value) {
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Expanded(
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
suffix: ElevatedButton(
|
||||
child: const Icon(Icons.search_rounded),
|
||||
onPressed: () {
|
||||
ref.read(searchTermStateProvider.notifier).state =
|
||||
controller.value.text;
|
||||
},
|
||||
),
|
||||
hintStyle: const TextStyle(height: 2),
|
||||
hintText: "Search...",
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
MaterialButton(
|
||||
elevation: 3,
|
||||
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;
|
||||
},
|
||||
),
|
||||
],
|
||||
onSubmitted: (value) {
|
||||
ref.read(searchTermStateProvider.notifier).state =
|
||||
controller.value.text;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
searchSnapshot.when(
|
||||
|
@ -3,6 +3,23 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.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 = {
|
||||
"Red": Colors.red,
|
||||
"Pink": Colors.pink,
|
||||
@ -23,6 +40,7 @@ final colorsMap = {
|
||||
"Brown": Colors.brown,
|
||||
"BlueGrey": Colors.blueGrey,
|
||||
"Grey": Colors.grey,
|
||||
"HighContrast": highContrast,
|
||||
};
|
||||
|
||||
enum ColorSchemeType {
|
||||
|
@ -29,8 +29,29 @@ class DownloadTrackButton extends HookConsumerWidget {
|
||||
final status = useState<TrackStatus>(TrackStatus.idle);
|
||||
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 {
|
||||
if (track == null) return;
|
||||
if (track == null ||
|
||||
outputFile.value == null ||
|
||||
downloadFolder.value == null) return;
|
||||
if ((kIsMobile) &&
|
||||
!await Permission.storage.isGranted &&
|
||||
!await Permission.storage.isPermanentlyDenied) {
|
||||
@ -47,18 +68,10 @@ class DownloadTrackButton extends HookConsumerWidget {
|
||||
StreamManifest manifest = await yt.videos.streamsClient
|
||||
.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(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>(
|
||||
context: 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 outputFileStream.flush();
|
||||
await outputFileStream.close().then((value) async {
|
||||
@ -157,12 +172,20 @@ class DownloadTrackButton extends HookConsumerWidget {
|
||||
yt,
|
||||
preferences.saveTrackLyrics,
|
||||
playback.track,
|
||||
outputFile.value,
|
||||
downloadFolder.value,
|
||||
fileName
|
||||
]);
|
||||
|
||||
useEffect(() {
|
||||
return () => yt.close();
|
||||
}, []);
|
||||
|
||||
final outputFileExists = useMemoized(
|
||||
() => outputFile.value?.existsSync() == true,
|
||||
[outputFile.value, status.value, track],
|
||||
);
|
||||
|
||||
if (status.value == TrackStatus.downloading) {
|
||||
return const SizedBox(
|
||||
child: CircularProgressIndicator.adaptive(
|
||||
@ -175,7 +198,9 @@ class DownloadTrackButton extends HookConsumerWidget {
|
||||
return const Icon(Icons.download_done_rounded);
|
||||
}
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ class PlaybuttonCard extends StatelessWidget {
|
||||
margin: margin,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 200),
|
||||
child: Ink(
|
||||
@ -37,10 +38,11 @@ class PlaybuttonCard extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 3),
|
||||
spreadRadius: 5,
|
||||
color: Theme.of(context).shadowColor)
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 3),
|
||||
spreadRadius: 5,
|
||||
color: Theme.of(context).shadowColor,
|
||||
)
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
|
Loading…
Reference in New Issue
Block a user