Play episode from search result.
This commit is contained in:
parent
5b2a95cd2d
commit
190f4b992d
|
@ -466,8 +466,11 @@ class _PlaylistWidgetState extends State<PlaylistWidget> {
|
|||
child: SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Image.file(File(
|
||||
"${episodes[index].imagePath}"))),
|
||||
child: Image(
|
||||
image: episodes[index].avatarImage)
|
||||
// Image.file(File(
|
||||
// "${episodes[index].imagePath}"))
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
|
@ -590,7 +593,7 @@ class SleepModeState extends State<SleepMode>
|
|||
Future _getDefaultTime() async {
|
||||
var defaultSleepTimerStorage = KeyValueStorage(defaultSleepTimerKey);
|
||||
var defaultTime = await defaultSleepTimerStorage.getInt(defaultValue: 30);
|
||||
if(mounted) setState(() => _minSelected = defaultTime);
|
||||
if (mounted) setState(() => _minSelected = defaultTime);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -992,7 +995,7 @@ class _ChaptersWidgetState extends State<ChaptersWidget> {
|
|||
foregroundColor: MaterialStateProperty.all<Color>(
|
||||
context.accentColor),
|
||||
overlayColor: MaterialStateProperty.all<Color>(
|
||||
context.primaryColor),
|
||||
context.primaryColor.withOpacity(0.3)),
|
||||
),
|
||||
onPressed: () => chapters.url.launchUrl,
|
||||
child: Text('Visit')),
|
||||
|
@ -1093,7 +1096,7 @@ class _ChaptersWidgetState extends State<ChaptersWidget> {
|
|||
child: Row(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
context.s.settingsInfo,
|
||||
context.s.homeToprightMenuAbout,
|
||||
overflow: TextOverflow.fade,
|
||||
style: TextStyle(
|
||||
color: context.accentColor,
|
||||
|
|
|
@ -10,7 +10,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tsacdop/type/episodebrief.dart';
|
||||
import 'package:tsacdop/state/audio_state.dart';
|
||||
import 'package:webfeed/webfeed.dart';
|
||||
|
||||
import '../.env.dart';
|
||||
|
@ -898,7 +898,7 @@ class _SearchResultDetailState extends State<SearchResultDetail>
|
|||
var searchResult = await searchEngine.fetchEpisode(rssUrl: id);
|
||||
var episodes = searchResult.items.cast();
|
||||
for (var episode in episodes) {
|
||||
_episodeList.add(episode.toOnlineWEpisode);
|
||||
_episodeList.add(episode.toOnlineEpisode);
|
||||
}
|
||||
_loading = false;
|
||||
return _episodeList;
|
||||
|
@ -1027,6 +1027,25 @@ class _SearchResultDetailState extends State<SearchResultDetail>
|
|||
: '${content[index].length.toTime} | '
|
||||
'${content[index].pubDate.toDate(context)}',
|
||||
style: TextStyle(color: context.accentColor)),
|
||||
trailing: TextButton(
|
||||
style: ButtonStyle(
|
||||
foregroundColor: MaterialStateProperty.all<Color>(
|
||||
context.accentColor),
|
||||
overlayColor: MaterialStateProperty.all<Color>(
|
||||
context.primaryColor.withOpacity(0.3)),
|
||||
padding: MaterialStateProperty.all<EdgeInsetsGeometry>(
|
||||
EdgeInsets.symmetric(horizontal: 2))),
|
||||
child: Text(context.s.play),
|
||||
onPressed: () {
|
||||
context.read<AudioPlayerNotifier>().episodeLoad(
|
||||
content[index].toEpisode,
|
||||
fromSearch: true);
|
||||
Fluttertoast.showToast(
|
||||
msg: 'Wait a moment',
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -1106,6 +1125,8 @@ class _SearchResultDetailState extends State<SearchResultDetail>
|
|||
fit: BoxFit.fitWidth,
|
||||
alignment: Alignment.center,
|
||||
imageUrl: widget.onlinePodcast.image,
|
||||
fadeInDuration: Duration.zero,
|
||||
placeholderFadeInDuration: Duration.zero,
|
||||
progressIndicatorBuilder:
|
||||
(context, url, downloadProgress) => Container(
|
||||
height: 120,
|
||||
|
|
|
@ -175,6 +175,9 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
|
||||
bool _markListened;
|
||||
|
||||
// Tmep episode list, playing from search result
|
||||
List<EpisodeBrief> _playFromSearchList = [];
|
||||
|
||||
@override
|
||||
void addListener(VoidCallback listener) {
|
||||
super.addListener(listener);
|
||||
|
@ -279,7 +282,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
await _playlist.getPlaylist();
|
||||
if (state[1] != '') {
|
||||
var episode = await _dbHelper.getRssItemWithUrl(state[1]);
|
||||
if ((!_playlist.isQueue && _playlist.contains(episode)) ||
|
||||
if ((!_playlist.isQueue && episode != null && _playlist.contains(episode)) ||
|
||||
(_playlist.isQueue &&
|
||||
_queue.isNotEmpty &&
|
||||
_queue.episodes.first.title == episode.title)) {
|
||||
|
@ -358,15 +361,21 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
}
|
||||
|
||||
Future<void> episodeLoad(EpisodeBrief episode,
|
||||
{int startPosition = 0}) async {
|
||||
final episodeNew = await _dbHelper.getRssItemWithUrl(episode.enclosureUrl);
|
||||
{int startPosition = 0, bool fromSearch = false}) async {
|
||||
var episodeNew;
|
||||
if (fromSearch) {
|
||||
episodeNew = episode;
|
||||
_playFromSearchList.add(episode);
|
||||
} else {
|
||||
episodeNew = await _dbHelper.getRssItemWithUrl(episode.enclosureUrl);
|
||||
}
|
||||
//TODO load episode from last position when player running
|
||||
if (playerRunning) {
|
||||
final history = PlayHistory(_episode.title, _episode.enclosureUrl,
|
||||
backgroundAudioPosition ~/ 1000, seekSliderValue);
|
||||
await _dbHelper.saveHistory(history);
|
||||
_queue.addToPlayListAt(episodeNew, 0);
|
||||
await updatePlaylist(_queue);
|
||||
await updatePlaylist(_queue, updateEpisodes: !fromSearch);
|
||||
if (!_playlist.isQueue) {
|
||||
AudioService.customAction('setIsQueue', true);
|
||||
AudioService.customAction('changeQueue', [
|
||||
|
@ -486,7 +495,9 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||
.where((event) => event != null)
|
||||
.listen((item) async {
|
||||
var episode = await _dbHelper.getRssItemWithMediaId(item.id);
|
||||
|
||||
if(episode == null){
|
||||
episode = _playFromSearchList.firstWhere((e) => e.mediaId == item.id, orElse: () => null);
|
||||
}
|
||||
_backgroundAudioDuration = item.duration?.inMilliseconds ?? 0;
|
||||
if (episode != null) {
|
||||
_episode = episode;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
|
@ -55,7 +56,7 @@ class EpisodeBrief extends Equatable {
|
|||
artist: feedTitle,
|
||||
album: feedTitle,
|
||||
duration: Duration.zero,
|
||||
artUri: 'file://$imagePath',
|
||||
artUri: imagePath == '' ? episodeImage : 'file://$imagePath',
|
||||
extras: {
|
||||
'skipSecondsStart': skipSecondsStart,
|
||||
'skipSecondsEnd': skipSecondsEnd
|
||||
|
@ -65,7 +66,9 @@ class EpisodeBrief extends Equatable {
|
|||
ImageProvider get avatarImage {
|
||||
return File(imagePath).existsSync()
|
||||
? FileImage(File(imagePath))
|
||||
: const AssetImage('assets/avatar_backup.png');
|
||||
: episodeImage != ''
|
||||
? CachedNetworkImageProvider(episodeImage)
|
||||
: AssetImage('assets/avatar_backup.png');
|
||||
}
|
||||
|
||||
Color backgroudColor(BuildContext context) {
|
||||
|
|
|
@ -35,17 +35,25 @@ class IndexEpisode {
|
|||
final int datePublished;
|
||||
final String enclosureUrl;
|
||||
final int enclosureLength;
|
||||
final int duration;
|
||||
final String feedImage;
|
||||
IndexEpisode(
|
||||
{this.title,
|
||||
this.description,
|
||||
this.datePublished,
|
||||
this.enclosureLength,
|
||||
this.enclosureUrl});
|
||||
this.enclosureUrl,
|
||||
this.duration,
|
||||
this.feedImage});
|
||||
|
||||
factory IndexEpisode.fromJson(Map<String, dynamic> json) =>
|
||||
_$IndexEpisodeFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$IndexEpisodeToJson(this);
|
||||
|
||||
OnlineEpisode get toOnlineWEpisode =>
|
||||
OnlineEpisode(title: title, pubDate: datePublished * 1000, length: 0);
|
||||
OnlineEpisode get toOnlineEpisode => OnlineEpisode(
|
||||
title: title,
|
||||
pubDate: datePublished * 1000,
|
||||
length: duration ?? 0,
|
||||
audio: enclosureUrl,
|
||||
thumbnail: feedImage);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ IndexEpisode _$IndexEpisodeFromJson(Map<String, dynamic> json) {
|
|||
datePublished: json['datePublished'] as int,
|
||||
enclosureLength: json['enclosureLength'] as int,
|
||||
enclosureUrl: json['enclosureUrl'] as String,
|
||||
duration: json['duration'] as int,
|
||||
feedImage: json['feedImage'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -40,4 +42,6 @@ Map<String, dynamic> _$IndexEpisodeToJson(IndexEpisode instance) =>
|
|||
'datePublished': instance.datePublished,
|
||||
'enclosureUrl': instance.enclosureUrl,
|
||||
'enclosureLength': instance.enclosureLength,
|
||||
'duration': instance.duration,
|
||||
'feedImage': instance.feedImage,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:tsacdop/type/episodebrief.dart';
|
||||
part 'searchepisodes.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
|
@ -33,8 +36,31 @@ class OnlineEpisode {
|
|||
final int pubDate;
|
||||
@JsonKey(name: 'audio_length_sec')
|
||||
final int length;
|
||||
OnlineEpisode({this.title, this.pubDate, this.length});
|
||||
final String audio;
|
||||
final String thumbnail;
|
||||
|
||||
OnlineEpisode({this.title, this.pubDate, this.length, this.audio, this.thumbnail});
|
||||
factory OnlineEpisode.fromJson(Map<String, dynamic> json) =>
|
||||
_$OnlineEpisodeFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$OnlineEpisodeToJson(this);
|
||||
|
||||
EpisodeBrief get toEpisode {
|
||||
return EpisodeBrief(
|
||||
title,
|
||||
audio,
|
||||
0,
|
||||
pubDate,
|
||||
title,
|
||||
jsonEncode([120,220,128]),
|
||||
length ?? 0,
|
||||
0,
|
||||
'',
|
||||
0,
|
||||
mediaId: audio,
|
||||
skipSecondsEnd: 0,
|
||||
skipSecondsStart: 0,
|
||||
chapterLink: '',
|
||||
episodeImage: thumbnail
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ OnlineEpisode _$OnlineEpisodeFromJson(Map<String, dynamic> json) {
|
|||
title: json['title'] as String,
|
||||
pubDate: json['pub_date_ms'] as int,
|
||||
length: json['audio_length_sec'] as int,
|
||||
audio: json['audio'] as String,
|
||||
thumbnail: json['thumbnail'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -33,4 +35,6 @@ Map<String, dynamic> _$OnlineEpisodeToJson(OnlineEpisode instance) =>
|
|||
'title': instance.title,
|
||||
'pub_date_ms': instance.pubDate,
|
||||
'audio_length_sec': instance.length,
|
||||
'audio': instance.audio,
|
||||
'thumbnail': instance.thumbnail,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue