diff --git a/lib/home/audioplayer.dart b/lib/home/audioplayer.dart index 2682dce..0e89475 100644 --- a/lib/home/audioplayer.dart +++ b/lib/home/audioplayer.dart @@ -466,8 +466,11 @@ class _PlaylistWidgetState extends State { 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 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 { foregroundColor: MaterialStateProperty.all( context.accentColor), overlayColor: MaterialStateProperty.all( - context.primaryColor), + context.primaryColor.withOpacity(0.3)), ), onPressed: () => chapters.url.launchUrl, child: Text('Visit')), @@ -1093,7 +1096,7 @@ class _ChaptersWidgetState extends State { child: Row( children: [ Text( - context.s.settingsInfo, + context.s.homeToprightMenuAbout, overflow: TextOverflow.fade, style: TextStyle( color: context.accentColor, diff --git a/lib/home/search_podcast.dart b/lib/home/search_podcast.dart index c4cf35c..51651c5 100644 --- a/lib/home/search_podcast.dart +++ b/lib/home/search_podcast.dart @@ -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 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 : '${content[index].length.toTime} | ' '${content[index].pubDate.toDate(context)}', style: TextStyle(color: context.accentColor)), + trailing: TextButton( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all( + context.accentColor), + overlayColor: MaterialStateProperty.all( + context.primaryColor.withOpacity(0.3)), + padding: MaterialStateProperty.all( + EdgeInsets.symmetric(horizontal: 2))), + child: Text(context.s.play), + onPressed: () { + context.read().episodeLoad( + content[index].toEpisode, + fromSearch: true); + Fluttertoast.showToast( + msg: 'Wait a moment', + gravity: ToastGravity.BOTTOM, + ); + }, + ), ); }, ); @@ -1106,6 +1125,8 @@ class _SearchResultDetailState extends State fit: BoxFit.fitWidth, alignment: Alignment.center, imageUrl: widget.onlinePodcast.image, + fadeInDuration: Duration.zero, + placeholderFadeInDuration: Duration.zero, progressIndicatorBuilder: (context, url, downloadProgress) => Container( height: 120, diff --git a/lib/state/audio_state.dart b/lib/state/audio_state.dart index ab08430..8542347 100644 --- a/lib/state/audio_state.dart +++ b/lib/state/audio_state.dart @@ -175,6 +175,9 @@ class AudioPlayerNotifier extends ChangeNotifier { bool _markListened; + // Tmep episode list, playing from search result + List _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 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; diff --git a/lib/type/episodebrief.dart b/lib/type/episodebrief.dart index 054e50e..78a101b 100644 --- a/lib/type/episodebrief.dart +++ b/lib/type/episodebrief.dart @@ -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) { diff --git a/lib/type/search_api/index_episode.dart b/lib/type/search_api/index_episode.dart index ec64783..bf380d9 100644 --- a/lib/type/search_api/index_episode.dart +++ b/lib/type/search_api/index_episode.dart @@ -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 json) => _$IndexEpisodeFromJson(json); Map 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); } diff --git a/lib/type/search_api/index_episode.g.dart b/lib/type/search_api/index_episode.g.dart index 0efe179..fdeebc8 100644 --- a/lib/type/search_api/index_episode.g.dart +++ b/lib/type/search_api/index_episode.g.dart @@ -30,6 +30,8 @@ IndexEpisode _$IndexEpisodeFromJson(Map 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 _$IndexEpisodeToJson(IndexEpisode instance) => 'datePublished': instance.datePublished, 'enclosureUrl': instance.enclosureUrl, 'enclosureLength': instance.enclosureLength, + 'duration': instance.duration, + 'feedImage': instance.feedImage, }; diff --git a/lib/type/search_api/searchepisodes.dart b/lib/type/search_api/searchepisodes.dart index edd2900..65a988f 100644 --- a/lib/type/search_api/searchepisodes.dart +++ b/lib/type/search_api/searchepisodes.dart @@ -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 json) => _$OnlineEpisodeFromJson(json); Map 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 + ); + } } diff --git a/lib/type/search_api/searchepisodes.g.dart b/lib/type/search_api/searchepisodes.g.dart index 768008e..5850ddc 100644 --- a/lib/type/search_api/searchepisodes.g.dart +++ b/lib/type/search_api/searchepisodes.g.dart @@ -25,6 +25,8 @@ OnlineEpisode _$OnlineEpisodeFromJson(Map 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 _$OnlineEpisodeToJson(OnlineEpisode instance) => 'title': instance.title, 'pub_date_ms': instance.pubDate, 'audio_length_sec': instance.length, + 'audio': instance.audio, + 'thumbnail': instance.thumbnail, };