Skip to content

Commit c785647

Browse files
authored
fix: only support local files for playlists (#1233)
1 parent 3765e8f commit c785647

26 files changed

+348
-227
lines changed

lib/common/view/audio_tile.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import '../data/audio_type.dart';
1313
import 'audio_page_type.dart';
1414
import 'audio_tile_image.dart';
1515
import 'audio_tile_option_button.dart';
16-
import 'like_icon.dart';
16+
import 'like_icon_button.dart';
17+
import 'stared_station_icon_button.dart';
1718
import 'tapable_text.dart';
1819
import 'theme.dart';
1920
import 'ui_constants.dart';
@@ -229,11 +230,11 @@ class _AudioTileTrail extends StatelessWidget with WatchItMixin {
229230
Opacity(
230231
opacity: hovered || selected || liked || starred ? 1 : 0,
231232
child: switch (audio.audioType) {
232-
AudioType.radio => RadioLikeIcon(
233+
AudioType.radio => StaredStationIconButton(
233234
audio: audio,
234235
color: selected && isPlayerPlaying ? selectedColor : null,
235236
),
236-
AudioType.local => LikeIcon(
237+
AudioType.local => LikeIconButton(
237238
audio: audio,
238239
color: selected && isPlayerPlaying ? selectedColor : null,
239240
),

lib/common/view/audio_tile_bottom_sheet.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ import '../data/audio_type.dart';
1616
import '../page_ids.dart';
1717
import 'audio_tile_image.dart';
1818
import 'icons.dart';
19-
import 'like_all_icon.dart';
20-
import 'like_icon.dart';
19+
import 'like_all_icon_button.dart';
2120
import 'meta_data_dialog.dart';
2221
import 'snackbars.dart';
2322
import 'spaced_divider.dart';
23+
import 'stared_station_icon_button.dart';
2424
import 'stream_provider_share_button.dart';
2525
import 'theme.dart';
2626
import 'ui_constants.dart';
@@ -72,10 +72,10 @@ class AudioTileBottomSheet extends StatelessWidget {
7272
: null,
7373
trailing: audios.isNotEmpty
7474
? switch (audios.first.audioType) {
75-
AudioType.radio => RadioLikeIcon(
75+
AudioType.radio => StaredStationIconButton(
7676
audio: audios.first,
7777
),
78-
AudioType.local => LikeAllIcon(
78+
AudioType.local => LikeAllIconButton(
7979
audios: audios,
8080
),
8181
_ => null,

lib/common/view/audio_tile_option_button.dart

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,31 +64,33 @@ class AudioTileOptionButton extends StatelessWidget {
6464
padding: EdgeInsets.zero,
6565
enabled: audios.isNotEmpty && playlistId.isNotEmpty,
6666
itemBuilder: (context) {
67-
final currentAudioType = di<PlayerModel>().audio?.audioType;
67+
final playerModel = di<PlayerModel>();
68+
final currentAudio = playerModel.audio;
69+
final currentlyLocalPlaying =
70+
currentAudio != null && currentAudio.isLocal;
6871
return [
69-
if (audios.length > 1 &&
70-
audios.none((e) => e.audioType == AudioType.radio))
72+
if (audios.none((e) => e.isRadio) && audios.none((e) => e.isPodcast))
7173
PopupMenuItem(
7274
onTap: () {
73-
if (di<PlayerModel>().audio?.audioType == AudioType.radio) {
74-
di<PlayerModel>()
75-
.startPlaylist(audios: audios, listName: playlistId);
76-
} else {
77-
di<PlayerModel>().insertIntoQueue(audios);
75+
if (currentlyLocalPlaying) {
76+
playerModel.insertIntoQueue(audios);
7877
showSnackBar(
7978
context: context,
8079
content: Text(
8180
'${l10n.addedTo} ${l10n.queue}: $searchTerm',
8281
),
8382
);
83+
} else {
84+
playerModel.startPlaylist(
85+
audios: audios,
86+
listName: playlistId,
87+
);
8488
}
8589
},
8690
child: YaruTile(
8791
leading: Icon(Iconz.insertIntoQueue),
8892
title: Text(
89-
currentAudioType == AudioType.radio
90-
? l10n.playAll
91-
: l10n.playNext,
93+
currentlyLocalPlaying ? l10n.playNext : l10n.playAll,
9294
),
9395
),
9496
),

lib/common/view/common_widgets.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,26 @@ class ImportantButton extends StatelessWidget {
4242
super.key,
4343
required this.onPressed,
4444
required this.child,
45+
this.style,
4546
});
4647

4748
final void Function()? onPressed;
4849
final Widget child;
50+
final ButtonStyle? style;
4951

5052
@override
5153
Widget build(BuildContext context) {
5254
return AppConfig.yaruStyled
5355
? ElevatedButton(
56+
style: style,
5457
onPressed: onPressed,
5558
child: child,
5659
)
57-
: FilledButton(onPressed: onPressed, child: child);
60+
: FilledButton(
61+
style: style,
62+
onPressed: onPressed,
63+
child: child,
64+
);
5865
}
5966
}
6067

lib/common/view/like_all_icon.dart renamed to lib/common/view/like_all_icon_button.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import '../../library/library_model.dart';
55
import '../data/audio.dart';
66
import 'animated_like_icon.dart';
77

8-
class LikeAllIcon extends StatelessWidget with WatchItMixin {
9-
const LikeAllIcon({super.key, required this.audios});
8+
class LikeAllIconButton extends StatelessWidget with WatchItMixin {
9+
const LikeAllIconButton({super.key, required this.audios});
1010

1111
final List<Audio> audios;
1212

lib/common/view/like_icon.dart renamed to lib/common/view/like_icon_button.dart

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import '../data/audio.dart';
88
import '../page_ids.dart';
99
import 'animated_like_icon.dart';
1010

11-
class LikeIcon extends StatelessWidget with WatchItMixin {
12-
const LikeIcon({
11+
class LikeIconButton extends StatelessWidget with WatchItMixin {
12+
const LikeIconButton({
1313
super.key,
1414
required this.audio,
1515
this.color,
@@ -57,48 +57,3 @@ class LikeIcon extends StatelessWidget with WatchItMixin {
5757
);
5858
}
5959
}
60-
61-
class RadioLikeIcon extends StatelessWidget with WatchItMixin {
62-
const RadioLikeIcon({
63-
super.key,
64-
required this.audio,
65-
this.color,
66-
});
67-
68-
final Audio? audio;
69-
final Color? color;
70-
71-
@override
72-
Widget build(BuildContext context) {
73-
final libraryModel = di<LibraryModel>();
74-
75-
watchPropertyValue((LibraryModel m) => m.starredStations.length);
76-
77-
final isStarredStation = libraryModel.isStarredStation(audio?.uuid);
78-
79-
final void Function()? onLike;
80-
if (audio == null && audio?.uuid == null) {
81-
onLike = null;
82-
} else {
83-
onLike = () {
84-
isStarredStation
85-
? libraryModel.unStarStation(audio!.uuid!)
86-
: libraryModel.addStarredStation(
87-
audio!.uuid!,
88-
);
89-
};
90-
}
91-
92-
return IconButton(
93-
tooltip: isStarredStation
94-
? context.l10n.removeFromCollection
95-
: context.l10n.addToCollection,
96-
icon: AnimatedStar(
97-
isStarred: isStarredStation,
98-
color: color,
99-
),
100-
onPressed: onLike,
101-
color: color,
102-
);
103-
}
104-
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:watch_it/watch_it.dart';
3+
import '../../l10n/l10n.dart';
4+
import '../../library/library_model.dart';
5+
import '../data/audio.dart';
6+
import 'animated_like_icon.dart';
7+
8+
class StaredStationIconButton extends StatelessWidget with WatchItMixin {
9+
const StaredStationIconButton({
10+
super.key,
11+
required this.audio,
12+
this.color,
13+
});
14+
15+
final Audio? audio;
16+
final Color? color;
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
final libraryModel = di<LibraryModel>();
21+
22+
watchPropertyValue((LibraryModel m) => m.starredStations.length);
23+
24+
final isStarredStation = libraryModel.isStarredStation(audio?.uuid);
25+
26+
final void Function()? onLike;
27+
if (audio == null && audio?.uuid == null) {
28+
onLike = null;
29+
} else {
30+
onLike = () {
31+
isStarredStation
32+
? libraryModel.unStarStation(audio!.uuid!)
33+
: libraryModel.addStarredStation(
34+
audio!.uuid!,
35+
);
36+
};
37+
}
38+
39+
return IconButton(
40+
tooltip: isStarredStation
41+
? context.l10n.removeFromCollection
42+
: context.l10n.addToCollection,
43+
icon: AnimatedStar(
44+
isStarred: isStarredStation,
45+
color: color,
46+
),
47+
onPressed: onLike,
48+
color: color,
49+
);
50+
}
51+
}

lib/custom_content/custom_content_model.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:io';
22

3+
import 'package:collection/collection.dart';
34
import 'package:file_selector/file_selector.dart';
45
import 'package:flutter/foundation.dart';
56
import 'package:m3u_parser_nullsafe/m3u_parser_nullsafe.dart';
@@ -121,7 +122,7 @@ class CustomContentModel extends SafeChangeNotifier {
121122
}) {
122123
final m3uAsString = StringBuffer();
123124
m3uAsString.writeln('#EXTM3U');
124-
for (var audio in audios) {
125+
for (var audio in audios.where((e) => e.isLocal)) {
125126
if (audio.url != null) {
126127
m3uAsString.writeln('#EXTINF:-1, ${audio.artist} - ${audio.title}');
127128
m3uAsString.writeln(audio.url);
@@ -308,7 +309,9 @@ Future<List<Audio>> _parseM3uPlaylist(String path) async {
308309
);
309310
} else if (e.link.isNotEmpty) {
310311
final file = File(e.link.replaceAll('file://', ''));
311-
audios.add(Audio.local(file));
312+
if (file.existsSync() && file.isPlayable) {
313+
audios.add(Audio.local(file));
314+
}
312315
}
313316
}
314317

0 commit comments

Comments
 (0)