Play episode from search result.

This commit is contained in:
Stonegate 2021-02-09 15:36:29 +08:00
parent 5b2a95cd2d
commit 190f4b992d
8 changed files with 98 additions and 18 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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) {

View File

@ -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);
}

View File

@ -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,
};

View File

@ -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
);
}
}

View File

@ -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,
};