offline podcasts + code cleaning + bug fixes
This commit is contained in:
parent
658d74b9ed
commit
9369dffc03
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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: {
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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>(
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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: [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue