252 lines
7.8 KiB
Dart
252 lines
7.8 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:device_info_plus/device_info_plus.dart';
|
|
import 'package:didvan/constants/assets.dart';
|
|
import 'package:didvan/models/requests/studio.dart';
|
|
import 'package:didvan/models/studio_details_data.dart';
|
|
import 'package:didvan/models/view/action_sheet_data.dart';
|
|
import 'package:didvan/providers/media.dart';
|
|
import 'package:didvan/services/network/request.dart';
|
|
import 'package:didvan/services/network/request_helper.dart';
|
|
import 'package:didvan/services/storage/storage.dart';
|
|
import 'package:didvan/utils/action_sheet.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_downloader/flutter_downloader.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:image_picker/image_picker.dart';
|
|
import 'package:just_audio/just_audio.dart';
|
|
import 'package:path/path.dart' as p;
|
|
import 'package:file_picker/file_picker.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import 'package:universal_html/html.dart' as html;
|
|
|
|
class MediaService {
|
|
static final audioPlayer = AudioPlayer();
|
|
static String? audioPlayerTag;
|
|
static StudioDetailsData? currentPodcast;
|
|
static StudioRequestArgs? podcastPlaylistArgs;
|
|
static int maxSizeInBytes = 15 * 1024 * 1024;
|
|
static bool isPlayingFromFeaturedCard = false;
|
|
|
|
static Duration? get duration => audioPlayer.duration;
|
|
|
|
static Future<void> handleAudioPlayback({
|
|
required dynamic audioSource,
|
|
required int id,
|
|
bool isNetworkAudio = true,
|
|
bool isVoiceMessage = true,
|
|
bool isBlob = false,
|
|
void Function(bool isNext)? onTrackChanged,
|
|
}) async {
|
|
try {
|
|
String tag;
|
|
tag =
|
|
'${currentPodcast?.description == 'radar' ? 'radar' : isVoiceMessage ? 'message' : 'podcast'}-$id';
|
|
if (!isVoiceMessage && MediaProvider.downloadedItemIds.contains(id)) {
|
|
audioSource = '${StorageService.appDocsDir}/podcasts/podcast-$id.mp3';
|
|
isNetworkAudio = false;
|
|
}
|
|
if (audioPlayerTag == tag) {
|
|
if (audioPlayer.playing) {
|
|
await audioPlayer.pause();
|
|
} else {
|
|
await audioPlayer.play();
|
|
}
|
|
|
|
return;
|
|
}
|
|
await audioPlayer.stop();
|
|
audioPlayerTag = tag;
|
|
String source;
|
|
if (isNetworkAudio) {
|
|
if (isVoiceMessage) {
|
|
source =
|
|
'${RequestHelper.baseUrl + audioSource}?accessToken=${RequestService.token}';
|
|
} else {
|
|
source = audioSource;
|
|
}
|
|
audioPlayer.setUrl(
|
|
source,
|
|
tag: isVoiceMessage
|
|
? null
|
|
: {
|
|
"artist": 'استودیو دیدوان',
|
|
"title": currentPodcast?.title ?? '',
|
|
},
|
|
);
|
|
} else {
|
|
if (isBlob) {
|
|
audioPlayer.setAudioSource(AudioSource.uri(Uri.parse(audioSource)));
|
|
} else {
|
|
audioPlayer.setFilePath(
|
|
audioSource,
|
|
tag: isVoiceMessage
|
|
? null
|
|
: {
|
|
"artist": 'استودیو دیدوان',
|
|
"title": currentPodcast?.title ?? '',
|
|
},
|
|
);
|
|
}
|
|
}
|
|
await audioPlayer.play();
|
|
} catch (e) {
|
|
// rethrow;
|
|
}
|
|
}
|
|
|
|
static Future<void> resetAudioPlayer() async {
|
|
audioPlayerTag = null;
|
|
currentPodcast = null;
|
|
podcastPlaylistArgs = null;
|
|
isPlayingFromFeaturedCard = false;
|
|
await MediaService.audioPlayer.stop();
|
|
}
|
|
|
|
static Future<XFile?> pickImage({required ImageSource source}) async {
|
|
try {
|
|
final imagePicker = ImagePicker();
|
|
final XFile? pickedFile = await imagePicker.pickImage(source: source);
|
|
return pickedFile;
|
|
} catch (e) {
|
|
e.printError(info: 'Pick Image Fail');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static Future<FilePickerResult?> pickPdfFile() async {
|
|
try {
|
|
final FilePickerResult? result = await FilePicker.platform.pickFiles(
|
|
type: FileType.custom,
|
|
allowedExtensions: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'csv'],
|
|
allowMultiple: false,
|
|
);
|
|
return result;
|
|
} catch (e) {
|
|
e.printError(info: 'Pick PDF Fail');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static Future<FilePickerResult?> pickMultiFile() async {
|
|
try {
|
|
return await FilePicker.platform
|
|
.pickFiles(
|
|
type: FileType.any,
|
|
allowMultiple: true,
|
|
)
|
|
.then((result) {
|
|
if (result != null && result.files.length > 3) {
|
|
return null;
|
|
}
|
|
return result;
|
|
});
|
|
} catch (e) {
|
|
e.printError(info: 'Pick Multi File Fail');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static Future<FilePickerResult?> pickAudioFile() async {
|
|
try {
|
|
return await FilePicker.platform.pickFiles(
|
|
type: FileType.audio,
|
|
allowMultiple: false,
|
|
);
|
|
} catch (e) {
|
|
e.printError(info: 'Pick Audio Fail');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static Future<String?> downloadFile(String url, {final String? name}) async {
|
|
debugPrint("Attempting to download file from URL: $url");
|
|
final basename = name ?? p.basename(url).split('?accessToken=').first;
|
|
|
|
PermissionStatus status;
|
|
if (Platform.isAndroid) {
|
|
final androidInfo = await DeviceInfoPlugin().androidInfo;
|
|
if (androidInfo.version.sdkInt >= 33) {
|
|
debugPrint("Android 13+ detected. Requesting Photos permission.");
|
|
status = await Permission.photos.request();
|
|
} else {
|
|
debugPrint("Older Android version detected. Requesting Storage permission.");
|
|
status = await Permission.storage.request();
|
|
}
|
|
} else if (Platform.isIOS) {
|
|
debugPrint("iOS detected. Requesting Photos permission.");
|
|
status = await Permission.photos.request();
|
|
} else {
|
|
status = PermissionStatus.granted;
|
|
}
|
|
|
|
debugPrint("Permission status after request: $status");
|
|
|
|
if (status.isGranted) {
|
|
Directory? dir;
|
|
try {
|
|
if (Platform.isIOS) {
|
|
dir = await getApplicationDocumentsDirectory();
|
|
} else {
|
|
dir = await getExternalStorageDirectory();
|
|
}
|
|
|
|
if (dir == null) {
|
|
debugPrint("Error: Could not determine download directory.");
|
|
return null;
|
|
}
|
|
|
|
final path = dir.path;
|
|
debugPrint("Download directory determined: $path");
|
|
|
|
final taskId = await FlutterDownloader.enqueue(
|
|
url: url,
|
|
savedDir: path,
|
|
fileName: basename,
|
|
showNotification: true,
|
|
openFileFromNotification: true,
|
|
saveInPublicStorage: true,
|
|
);
|
|
debugPrint("Download successfully enqueued with taskId: $taskId");
|
|
return path;
|
|
|
|
} catch (e) {
|
|
debugPrint("Error during download process: $e");
|
|
return null;
|
|
}
|
|
} else if (status.isPermanentlyDenied) {
|
|
debugPrint("Storage permission is permanently denied. Opening app settings.");
|
|
await openAppSettings();
|
|
return null;
|
|
} else {
|
|
debugPrint("Storage permission was denied.");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
static String downloadFileFromWeb(String url) {
|
|
final filename = url.split('/').last.split('?').first;
|
|
html.AnchorElement anchorElement = html.AnchorElement(href: url);
|
|
anchorElement.download = filename;
|
|
anchorElement.click();
|
|
return anchorElement.pathname!;
|
|
}
|
|
|
|
static onLoadingPickFile(BuildContext context) {
|
|
ActionSheetUtils(context).openDialog(
|
|
barrierDismissible: false,
|
|
data: ActionSheetData(
|
|
content: Center(
|
|
child: Image.asset(
|
|
Assets.loadingAnimation,
|
|
width: 60,
|
|
height: 60,
|
|
),
|
|
),
|
|
hasConfirmButton: false,
|
|
hasDismissButton: false,
|
|
));
|
|
}
|
|
} |