offline podcasts + code cleaning + bug fixes

This commit is contained in:
MohammadTaha Basiri 2022-03-29 15:14:50 +04:30
parent 658d74b9ed
commit 9369dffc03
19 changed files with 187 additions and 74 deletions

View File

@ -23,15 +23,13 @@ class MediaService {
static Future<void> handleAudioPlayback({ static Future<void> handleAudioPlayback({
required dynamic audioSource, required dynamic audioSource,
required int id,
bool? isNetworkAudio,
bool isVoiceMessage = true, bool isVoiceMessage = true,
}) async { }) async {
bool isNetworkAudio = audioSource.runtimeType == String;
String tag; String tag;
if (isNetworkAudio) { tag = '${isVoiceMessage ? 'message' : 'podcast'}-$id';
tag = audioSource; isNetworkAudio ??= audioSource.runtimeType == String;
} else {
tag = audioSource.path;
}
if (audioPlayerTag == tag) { if (audioPlayerTag == tag) {
if (audioPlayer.playing) { if (audioPlayer.playing) {
await audioPlayer.pause(); await audioPlayer.pause();
@ -51,10 +49,9 @@ class MediaService {
); );
} else { } else {
if (kIsWeb) { if (kIsWeb) {
await audioPlayer await audioPlayer.setUrl(audioSource!.replaceAll('%3A', ':'));
.setUrl(audioSource!.uri.path.replaceAll('%3A', ':'));
} else { } else {
await audioPlayer.setFilePath(audioSource.path); await audioPlayer.setFilePath(audioSource);
} }
} }
audioPlayer.play(); audioPlayer.play();

View File

@ -1,6 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'dart:io'; import 'package:didvan/services/storage/storage.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart' as parser; import 'package:http_parser/http_parser.dart' as parser;
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
@ -164,11 +164,14 @@ class RequestService {
} }
} }
Future<void> download() async { Future<void> download(String fileName, String subDirectory) async {
Permission.manageExternalStorage.request(); Permission.storage.request();
final response = await http.get(Uri.parse(url)); final response = await http.get(Uri.parse(url));
final file = await File('/storage/emulated/0/Download/file.mp3').create(); StorageService.createFile(
await file.writeAsBytes(response.bodyBytes); bytes: response.bodyBytes,
subDirectory: subDirectory,
name: fileName,
);
} }
void _handleResponse(http.Response? response) { void _handleResponse(http.Response? response) {

View File

@ -1,3 +1,6 @@
import 'dart:typed_data';
import 'dart:io' as io;
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:universal_html/html.dart'; import 'package:universal_html/html.dart';
@ -6,6 +9,21 @@ class StorageService {
static late String appTempsDir; static late String appTempsDir;
static const FlutterSecureStorage _storage = FlutterSecureStorage(); static const FlutterSecureStorage _storage = FlutterSecureStorage();
static Future<void> createFile({
required Uint8List bytes,
required String subDirectory,
required String name,
}) async {
final dir = io.Directory(appDocsDir + '/$subDirectory');
if (!await dir.exists()) {
await dir.create(recursive: true);
}
final file = await io.File(
appDocsDir + '/$subDirectory/podcast-$name.mp3',
).create(recursive: true);
await file.writeAsBytes(bytes);
}
static Future<void> setValue({ static Future<void> setValue({
required String key, required String key,
required dynamic value, required dynamic value,

View File

@ -59,6 +59,7 @@ class _CommentsState extends State<Comments> {
child: Stack( child: Stack(
children: [ children: [
DidvanScaffold( DidvanScaffold(
physics: const BouncingScrollPhysics(),
backgroundColor: Theme.of(context).colorScheme.surface, backgroundColor: Theme.of(context).colorScheme.surface,
appBarData: _isPage appBarData: _isPage
? AppBarData( ? AppBarData(
@ -77,6 +78,7 @@ class _CommentsState extends State<Comments> {
itemPadding: const EdgeInsets.symmetric(vertical: 16), itemPadding: const EdgeInsets.symmetric(vertical: 16),
childCount: state.comments.length, childCount: state.comments.length,
placeholder: const _CommentPlaceholder(), placeholder: const _CommentPlaceholder(),
centerEmptyState: _isPage,
enableEmptyState: state.comments.isEmpty, enableEmptyState: state.comments.isEmpty,
emptyState: EmptyState( emptyState: EmptyState(
asset: Assets.emptyChat, asset: Assets.emptyChat,

View File

@ -4,6 +4,7 @@ import 'package:didvan/models/enums.dart';
import 'package:didvan/models/message_data/message_data.dart'; import 'package:didvan/models/message_data/message_data.dart';
import 'package:didvan/models/message_data/radar_attachment.dart'; import 'package:didvan/models/message_data/radar_attachment.dart';
import 'package:didvan/providers/core_provider.dart'; import 'package:didvan/providers/core_provider.dart';
import 'package:didvan/services/media/media.dart';
import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart'; import 'package:didvan/services/network/request_helper.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -46,6 +47,7 @@ class DirectState extends CoreProvier {
} }
Future<void> startRecording() async { Future<void> startRecording() async {
text = null;
await _recorder.hasPermission(); await _recorder.hasPermission();
if (!kIsWeb) { if (!kIsWeb) {
Vibrate.feedback(FeedbackType.medium); Vibrate.feedback(FeedbackType.medium);
@ -88,6 +90,7 @@ class DirectState extends CoreProvier {
Future<void> sendMessage() async { Future<void> sendMessage() async {
if ((text == null || text!.isEmpty) && recordedFile == null) return; if ((text == null || text!.isEmpty) && recordedFile == null) return;
MediaService.audioPlayer.stop();
messages.insert( messages.insert(
0, 0,
MessageData( MessageData(

View File

@ -1,15 +1,22 @@
import 'dart:io'; import 'dart:io';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/services/media/media.dart'; import 'package:didvan/services/media/media.dart';
import 'package:didvan/views/home/widgets/audio/audio_slider.dart'; import 'package:didvan/views/home/widgets/audio/audio_slider.dart';
import 'package:didvan/views/home/widgets/player_controller_button.dart'; import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class AudioWidget extends StatelessWidget { class AudioWidget extends StatelessWidget {
final String? audioUrl; final String? audioUrl;
final File? audioFile; final File? audioFile;
const AudioWidget({Key? key, this.audioUrl, this.audioFile}) final int id;
: super(key: key); const AudioWidget({
Key? key,
this.audioUrl,
this.audioFile,
required this.id,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -20,12 +27,13 @@ class AudioWidget extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: AudioSlider( child: AudioSlider(
tag: audioUrl ?? audioFile!.path, tag: 'message-$id',
), ),
), ),
AudioControllerButton( _AudioControllerButton(
audioFile: audioFile, audioFile: audioFile,
audioUrl: audioUrl, audioUrl: audioUrl,
id: id,
), ),
], ],
); );
@ -33,3 +41,33 @@ class AudioWidget extends StatelessWidget {
); );
} }
} }
class _AudioControllerButton extends StatelessWidget {
final String? audioUrl;
final File? audioFile;
final int id;
const _AudioControllerButton(
{Key? key, this.audioUrl, this.audioFile, required this.id})
: super(key: key);
bool get _nowPlaying => MediaService.audioPlayerTag == 'message-$id';
@override
Widget build(BuildContext context) {
return DidvanIconButton(
icon: MediaService.audioPlayer.playing == true && _nowPlaying
? DidvanIcons.pause_circle_solid
: DidvanIcons.play_circle_solid,
color: Theme.of(context).colorScheme.focusedBorder,
onPressed: () {
MediaService.handleAudioPlayback(
audioSource: audioFile?.path ?? audioUrl,
id: id,
isNetworkAudio: audioFile == null,
isVoiceMessage: true,
);
},
);
}
}

View File

@ -65,6 +65,7 @@ class Message extends StatelessWidget {
AudioWidget( AudioWidget(
audioFile: message.audioFile, audioFile: message.audioFile,
audioUrl: message.audio, audioUrl: message.audio,
id: message.id,
), ),
if (message.radar != null) const DidvanDivider(), if (message.radar != null) const DidvanDivider(),
if (message.radar != null) const SizedBox(height: 4), if (message.radar != null) const SizedBox(height: 4),

View File

@ -211,7 +211,10 @@ class _RecordChecking extends StatelessWidget {
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: AudioWidget(audioFile: state.recordedFile!), child: AudioWidget(
audioFile: state.recordedFile!,
id: 0,
),
), ),
), ),
DidvanIconButton( DidvanIconButton(

View File

@ -9,7 +9,6 @@ import 'package:didvan/views/home/studio/studio_details/widgets/studio_details_w
import 'package:didvan/views/home/widgets/bookmark_button.dart'; import 'package:didvan/views/home/widgets/bookmark_button.dart';
import 'package:didvan/views/widgets/didvan/scaffold.dart'; import 'package:didvan/views/widgets/didvan/scaffold.dart';
import 'package:didvan/views/widgets/state_handlers/state_handler.dart'; import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';

View File

@ -1,4 +1,3 @@
import 'dart:io';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/design_config.dart';

View File

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:didvan/models/enums.dart'; import 'package:didvan/models/enums.dart';
import 'package:didvan/models/overview_data.dart'; import 'package:didvan/models/overview_data.dart';
@ -8,6 +9,7 @@ import 'package:didvan/providers/core_provider.dart';
import 'package:didvan/services/media/media.dart'; import 'package:didvan/services/media/media.dart';
import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart'; import 'package:didvan/services/network/request_helper.dart';
import 'package:didvan/services/storage/storage.dart';
class StudioDetailsState extends CoreProvier { class StudioDetailsState extends CoreProvier {
late StudioDetailsData studio; late StudioDetailsData studio;
@ -17,6 +19,7 @@ class StudioDetailsState extends CoreProvier {
late StudioRequestArgs args; late StudioRequestArgs args;
final List<int> relatedQueue = []; final List<int> relatedQueue = [];
bool _positionListenerActivated = false; bool _positionListenerActivated = false;
final List<int> downloadedFileIds = [];
int _selectedDetailsIndex = 0; int _selectedDetailsIndex = 0;
Timer? timer; Timer? timer;
@ -42,6 +45,7 @@ class StudioDetailsState extends CoreProvier {
if (MediaService.currentPodcast?.id == id && this.args.type == 'podcast') { if (MediaService.currentPodcast?.id == id && this.args.type == 'podcast') {
return; return;
} }
_getDownloadsList();
_selectedDetailsIndex = 0; _selectedDetailsIndex = 0;
if (isForward != null) { if (isForward != null) {
if (isForward) { if (isForward) {
@ -87,9 +91,14 @@ class StudioDetailsState extends CoreProvier {
if (args.type == 'podcast') { if (args.type == 'podcast') {
MediaService.currentPodcast = studio; MediaService.currentPodcast = studio;
MediaService.podcastPlaylistArgs = args; MediaService.podcastPlaylistArgs = args;
final downloaded = downloadedFileIds.contains(studio.id);
await MediaService.handleAudioPlayback( await MediaService.handleAudioPlayback(
audioSource: studio.media, audioSource: downloaded
? StorageService.appDocsDir + '/podcasts/podcast-${studio.id}.mp3'
: studio.media,
id: studio.id,
isVoiceMessage: false, isVoiceMessage: false,
isNetworkAudio: !downloaded,
); );
if (nextStudio != null && !_positionListenerActivated) { if (nextStudio != null && !_positionListenerActivated) {
_positionListenerActivated = true; _positionListenerActivated = true;
@ -104,6 +113,25 @@ class StudioDetailsState extends CoreProvier {
} }
} }
Future<void> _getDownloadsList() async {
downloadedFileIds.clear();
final dir = Directory(
StorageService.appDocsDir + ('/${args.type}s'),
);
if (!await dir.exists()) {
await dir.create();
}
dir.list(recursive: false).listen(
(event) {
downloadedFileIds.add(
int.parse(
event.path.split('/').last.split('-').last.split('.').first,
),
);
},
);
}
Future<void> getRelatedContents() async { Future<void> getRelatedContents() async {
if (studio.relatedContents.isNotEmpty) return; if (studio.relatedContents.isNotEmpty) return;
relatedQueue.add(studio.id); relatedQueue.add(studio.id);

View File

@ -41,7 +41,7 @@ class StudioDetailsWidget extends StatelessWidget {
isVideo: _isVideo, isVideo: _isVideo,
onCommentsTabSelected: onCommentsTabSelected ?? () {}, onCommentsTabSelected: onCommentsTabSelected ?? () {},
), ),
if (state.selectedDetailsIndex != 1) const SizedBox(height: 16), const SizedBox(height: 16),
StateHandler<StudioDetailsState>( StateHandler<StudioDetailsState>(
onRetry: () {}, onRetry: () {},
state: state, state: state,
@ -93,7 +93,7 @@ class StudioDetailsWidget extends StatelessWidget {
child: SizedBox( child: SizedBox(
height: ds.height - height: ds.height -
ds.width * 9 / 16 - ds.width * 9 / 16 -
128 - 144 -
MediaQuery.of(context).padding.top, MediaQuery.of(context).padding.top,
child: Comments( child: Comments(
pageData: { pageData: {

View File

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:didvan/models/enums.dart'; import 'package:didvan/models/enums.dart';
import 'package:didvan/models/overview_data.dart'; import 'package:didvan/models/overview_data.dart';
@ -8,10 +9,12 @@ import 'package:didvan/providers/core_provider.dart';
import 'package:didvan/providers/user_provider.dart'; import 'package:didvan/providers/user_provider.dart';
import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart'; import 'package:didvan/services/network/request_helper.dart';
import 'package:didvan/services/storage/storage.dart';
class StudioState extends CoreProvier { class StudioState extends CoreProvier {
final List<OverviewData> studios = []; final List<OverviewData> studios = [];
final List<SliderData> sliders = []; final List<SliderData> sliders = [];
final List<int> downloadedFileIds = [];
String search = ''; String search = '';
String lastSearch = ''; String lastSearch = '';
@ -29,10 +32,31 @@ class StudioState extends CoreProvier {
set videosSelected(bool value) { set videosSelected(bool value) {
if (_videosSelected == value) return; if (_videosSelected == value) return;
_videosSelected = value; _videosSelected = value;
selectedSortTypeIndex = 0;
_getSliders(); _getSliders();
getDownloadsList();
getStudios(page: page); getStudios(page: page);
} }
Future<void> getDownloadsList() async {
downloadedFileIds.clear();
final dir = Directory(
StorageService.appDocsDir + (videosSelected ? '/videos' : '/podcasts'),
);
if (!await dir.exists()) {
await dir.create();
}
dir.list(recursive: false).listen(
(event) {
downloadedFileIds.add(
int.parse(
event.path.split('/').last.split('-').last.split('.').first,
),
);
},
);
}
String get order { String get order {
if (selectedSortTypeIndex == 0 || selectedSortTypeIndex == 1) return 'date'; if (selectedSortTypeIndex == 0 || selectedSortTypeIndex == 1) return 'date';
if (selectedSortTypeIndex == 2) return 'view'; if (selectedSortTypeIndex == 2) return 'view';
@ -56,6 +80,7 @@ class StudioState extends CoreProvier {
lastSearch = ''; lastSearch = '';
_videosSelected = true; _videosSelected = true;
selectedSortTypeIndex = 0; selectedSortTypeIndex = 0;
getDownloadsList();
Future.delayed(Duration.zero, () { Future.delayed(Duration.zero, () {
_getSliders(); _getSliders();
getStudios(page: 1); getStudios(page: 1);
@ -94,7 +119,6 @@ class StudioState extends CoreProvier {
), ),
), ),
); );
await service.httpGet(); await service.httpGet();
if (service.isSuccess) { if (service.isSuccess) {
if (page == 1) { if (page == 1) {
@ -122,8 +146,9 @@ class StudioState extends CoreProvier {
notifyListeners(); notifyListeners();
} }
void download(String url) { Future<void> download(String url, String fileName) async {
final service = RequestService(url); final service = RequestService(url);
service.download(); await service.download(fileName, videosSelected ? 'videos' : 'podcasts');
notifyListeners();
} }
} }

View File

@ -57,7 +57,7 @@ class AudioPlayerWidget extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: AudioSlider( child: AudioSlider(
tag: podcast.media, tag: 'podcast-${podcast.id}',
showTimer: true, showTimer: true,
duration: podcast.duration, duration: podcast.duration,
), ),
@ -117,6 +117,7 @@ class AudioPlayerWidget extends StatelessWidget {
builder: (context, snapshot) { builder: (context, snapshot) {
return _PlayPouseAnimatedIcon( return _PlayPouseAnimatedIcon(
audioSource: podcast.media, audioSource: podcast.media,
id: podcast.id,
); );
}, },
), ),
@ -239,7 +240,9 @@ class AudioPlayerWidget extends StatelessWidget {
class _PlayPouseAnimatedIcon extends StatefulWidget { class _PlayPouseAnimatedIcon extends StatefulWidget {
final String audioSource; final String audioSource;
const _PlayPouseAnimatedIcon({Key? key, required this.audioSource}) final int id;
const _PlayPouseAnimatedIcon(
{Key? key, required this.audioSource, required this.id})
: super(key: key); : super(key: key);
@override @override
@ -281,6 +284,11 @@ class __PlayPouseAnimatedIconState extends State<_PlayPouseAnimatedIcon>
MediaService.handleAudioPlayback( MediaService.handleAudioPlayback(
audioSource: widget.audioSource, audioSource: widget.audioSource,
isVoiceMessage: false, isVoiceMessage: false,
id: widget.id,
isNetworkAudio: !context
.read<StudioDetailsState>()
.downloadedFileIds
.contains(widget.id),
); );
_handleAnimation(); _handleAnimation();
}, },

View File

@ -22,7 +22,7 @@ class AudioSlider extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return IgnorePointer( return IgnorePointer(
ignoring: MediaService.audioPlayerTag != tag, ignoring: !_isPlaying,
child: Directionality( child: Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: StreamBuilder<Duration>( child: StreamBuilder<Duration>(

View File

@ -1,15 +1,19 @@
import 'package:didvan/config/theme_data.dart'; import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/overview_data.dart'; import 'package:didvan/models/overview_data.dart';
import 'package:didvan/models/requests/studio.dart'; import 'package:didvan/models/requests/studio.dart';
import 'package:didvan/utils/date_time.dart'; import 'package:didvan/utils/date_time.dart';
import 'package:didvan/views/home/studio/studio_details/studio_details_state.dart'; import 'package:didvan/views/home/studio/studio_details/studio_details_state.dart';
import 'package:didvan/views/home/studio/studio_state.dart';
import 'package:didvan/views/home/widgets/bookmark_button.dart'; import 'package:didvan/views/home/widgets/bookmark_button.dart';
import 'package:didvan/views/home/widgets/duration_widget.dart'; import 'package:didvan/views/home/widgets/duration_widget.dart';
import 'package:didvan/views/widgets/didvan/card.dart'; import 'package:didvan/views/widgets/didvan/card.dart';
import 'package:didvan/views/widgets/didvan/divider.dart'; import 'package:didvan/views/widgets/didvan/divider.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/shimmer_placeholder.dart'; import 'package:didvan/views/widgets/shimmer_placeholder.dart';
import 'package:didvan/views/widgets/skeleton_image.dart'; import 'package:didvan/views/widgets/skeleton_image.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -28,6 +32,7 @@ class PodcastOverview extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final state = context.read<StudioState>();
return DidvanCard( return DidvanCard(
onTap: () { onTap: () {
context context
@ -75,13 +80,22 @@ class PodcastOverview extends StatelessWidget {
children: [ children: [
DurationWidget(duration: podcast.duration!), DurationWidget(duration: podcast.duration!),
const Spacer(), const Spacer(),
// DidvanIconButton( if (!kIsWeb) ...[
// gestureSize: 28, DidvanIconButton(
// icon: DidvanIcons.download_regular, gestureSize: 28,
// onPressed: () => color: _isDownloaded(state)
// context.read<StudioState>().download(podcast.media!), ? Theme.of(context).colorScheme.primary
// ), : null,
// const SizedBox(width: 16), icon: _isDownloaded(state)
? DidvanIcons.download_solid
: DidvanIcons.download_regular,
onPressed: _isDownloaded(state)
? () {}
: () =>
state.download(podcast.media!, podcast.id.toString()),
),
const SizedBox(width: 16),
],
BookmarkButton( BookmarkButton(
askForConfirmation: hasUnmarkConfirmation, askForConfirmation: hasUnmarkConfirmation,
gestureSize: 32, gestureSize: 32,
@ -95,6 +109,10 @@ class PodcastOverview extends StatelessWidget {
); );
} }
bool _isDownloaded(state) {
return state.downloadedFileIds.contains(podcast.id);
}
static Widget get placeholder => DidvanCard( static Widget get placeholder => DidvanCard(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -1,34 +0,0 @@
import 'dart:io';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/services/media/media.dart';
import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:flutter/material.dart';
class AudioControllerButton extends StatelessWidget {
final String? audioUrl;
final File? audioFile;
const AudioControllerButton({Key? key, this.audioUrl, this.audioFile})
: super(key: key);
bool get _nowPlaying =>
MediaService.audioPlayerTag == audioUrl ||
audioFile != null && MediaService.audioPlayerTag == audioFile!.path;
@override
Widget build(BuildContext context) {
return DidvanIconButton(
icon: MediaService.audioPlayer.playing == true && _nowPlaying
? DidvanIcons.pause_circle_solid
: DidvanIcons.play_circle_solid,
color: Theme.of(context).colorScheme.focusedBorder,
onPressed: () {
MediaService.handleAudioPlayback(
audioSource: audioFile ?? audioUrl,
);
},
);
}
}

View File

@ -24,10 +24,11 @@ class DidvanBNB extends StatelessWidget {
: super(key: key); : super(key: key);
bool get _enablePlayerController => bool get _enablePlayerController =>
MediaService.currentPodcast != null || MediaService.audioPlayer.playing; MediaService.currentPodcast != null && MediaService.audioPlayer.playing;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final state = context.read<StudioDetailsState>();
return StreamBuilder<bool>( return StreamBuilder<bool>(
stream: MediaService.audioPlayer.playingStream, stream: MediaService.audioPlayer.playingStream,
builder: (context, snapshot) { builder: (context, snapshot) {
@ -108,7 +109,8 @@ class DidvanBNB extends StatelessWidget {
: DidvanIcons.play_solid, : DidvanIcons.play_solid,
onPressed: () { onPressed: () {
MediaService.handleAudioPlayback( MediaService.handleAudioPlayback(
audioSource: MediaService.audioPlayerTag, audioSource: state.studio.media,
id: state.studio.id,
); );
}, },
), ),

View File

@ -9,6 +9,7 @@ class DidvanScaffold extends StatefulWidget {
final EdgeInsets padding; final EdgeInsets padding;
final Color? backgroundColor; final Color? backgroundColor;
final bool reverse; final bool reverse;
final ScrollPhysics? physics;
final ScrollController? scrollController; final ScrollController? scrollController;
final bool showSliversFirst; final bool showSliversFirst;
@ -17,6 +18,7 @@ class DidvanScaffold extends StatefulWidget {
this.slivers, this.slivers,
required this.appBarData, required this.appBarData,
this.children, this.children,
this.physics,
this.padding = const EdgeInsets.symmetric(horizontal: 16), this.padding = const EdgeInsets.symmetric(horizontal: 16),
this.backgroundColor, this.backgroundColor,
this.reverse = false, this.reverse = false,
@ -49,6 +51,7 @@ class _DidvanScaffoldState extends State<DidvanScaffold> {
child: Stack( child: Stack(
children: [ children: [
CustomScrollView( CustomScrollView(
physics: widget.physics,
controller: _scrollController, controller: _scrollController,
reverse: widget.reverse, reverse: widget.reverse,
slivers: [ slivers: [