From fbb9db51033326a2f81ee28ea06980a48faa5784 Mon Sep 17 00:00:00 2001 From: OkaykOrhmn Date: Tue, 24 Sep 2024 16:14:46 +0330 Subject: [PATCH] little better fix audio 3/07/1403 --- lib/models/ai/chats_model.dart | 56 ++++--- lib/models/ai/files_model.dart | 2 + lib/services/ai/ai_api_service.dart | 6 + lib/services/media/media.dart | 1 - lib/services/media/voice.dart | 11 +- lib/services/network/request.dart | 1 - lib/utils/action_sheet.dart | 2 - lib/views/ai/ai.dart | 179 ++++++++++++++------- lib/views/ai/ai_chat_page.dart | 40 +++-- lib/views/ai/widgets/ai_message_bar.dart | 13 +- lib/views/ai/widgets/audio_wave.dart | 41 +++-- lib/views/ai/widgets/message_bar_btn.dart | 2 - lib/views/direct/widgets/audio_widget.dart | 10 +- lib/views/direct/widgets/message.dart | 35 +++- lib/views/widgets/audio/audio_slider.dart | 1 - pubspec.lock | 8 - pubspec.yaml | 1 - 17 files changed, 271 insertions(+), 138 deletions(-) diff --git a/lib/models/ai/chats_model.dart b/lib/models/ai/chats_model.dart index bda3e33..e9a08d8 100644 --- a/lib/models/ai/chats_model.dart +++ b/lib/models/ai/chats_model.dart @@ -99,20 +99,21 @@ class Prompts { bool? error; bool? audio; FilesModel? fileLocal; + int? duration; - Prompts({ - this.id, - this.chatId, - this.text, - this.file, - this.fileName, - this.role, - this.createdAt, - this.finished, - this.error, - this.fileLocal, - this.audio, - }); + Prompts( + {this.id, + this.chatId, + this.text, + this.file, + this.fileName, + this.role, + this.createdAt, + this.finished, + this.error, + this.fileLocal, + this.audio, + this.duration}); Prompts.fromJson(Map json) { id = json['id']; @@ -123,6 +124,7 @@ class Prompts { role = json['role']; createdAt = json['createdAt']; audio = json['audio']; + duration = json['duration']; } Map toJson() { @@ -135,21 +137,24 @@ class Prompts { data['role'] = role; data['createdAt'] = createdAt; data['audio'] = audio; + data['duration'] = duration; return data; } - Prompts copyWith( - {int? id, - int? chatId, - String? text, - String? file, - String? fileName, - FilesModel? fileLocal, - String? role, - String? createdAt, - bool? finished, - bool? error, - bool? audio}) { + Prompts copyWith({ + int? id, + int? chatId, + String? text, + String? file, + String? fileName, + FilesModel? fileLocal, + String? role, + String? createdAt, + bool? finished, + bool? error, + bool? audio, + int? duration, + }) { return Prompts( id: id ?? this.id, chatId: chatId ?? this.chatId, @@ -162,6 +167,7 @@ class Prompts { finished: finished ?? this.finished, error: error ?? this.error, audio: audio ?? this.audio, + duration: duration ?? this.duration, ); } } diff --git a/lib/models/ai/files_model.dart b/lib/models/ai/files_model.dart index f5949a3..a6781cb 100644 --- a/lib/models/ai/files_model.dart +++ b/lib/models/ai/files_model.dart @@ -14,6 +14,7 @@ class FilesModel { final bool? image; final bool? network; final Uint8List? bytes; + final Duration? duration; FilesModel( this.path, { @@ -23,6 +24,7 @@ class FilesModel { this.image, this.network, this.bytes, + this.duration, }) { basename = name ?? p.basename(path); extname = p.extension(path); diff --git a/lib/services/ai/ai_api_service.dart b/lib/services/ai/ai_api_service.dart index 8a1a9b3..6d8381e 100644 --- a/lib/services/ai/ai_api_service.dart +++ b/lib/services/ai/ai_api_service.dart @@ -33,7 +33,11 @@ class AiApiService { if (edite != null) { request.fields['edit'] = edite.toString().toLowerCase(); } + if (file != null) { + if (file.duration != null) { + request.fields['duration'] = file.duration!.inSeconds.toString(); + } Uint8List bytes; String filename; String mimeType; @@ -45,6 +49,8 @@ class AiApiService { final Uri audioUri = Uri.parse(file.path.replaceAll('%3A', ':')); final http.Response audioResponse = await http.get(audioUri); bytes = audioResponse.bodyBytes; + // final f = File.fromUri(Uri.parse(file.path)); + // bytes = await f.readAsBytes(); // Fetch the blob using JavaScript interop // final blob = await html.window diff --git a/lib/services/media/media.dart b/lib/services/media/media.dart index 9b021b2..bee7087 100644 --- a/lib/services/media/media.dart +++ b/lib/services/media/media.dart @@ -34,7 +34,6 @@ class MediaService { String tag; tag = '${currentPodcast?.description == 'radar' ? 'radar' : isVoiceMessage ? 'message' : 'podcast'}-$id'; - print("tag: $tag"); if (!isVoiceMessage && MediaProvider.downloadedItemIds.contains(id)) { audioSource = '${StorageService.appDocsDir}/podcasts/podcast-$id.mp3'; isNetworkAudio = false; diff --git a/lib/services/media/voice.dart b/lib/services/media/voice.dart index 7ebbca9..d6a1bf4 100644 --- a/lib/services/media/voice.dart +++ b/lib/services/media/voice.dart @@ -1,4 +1,3 @@ -import 'package:didvan/services/media/media.dart'; import 'package:didvan/services/network/request.dart'; import 'package:didvan/services/network/request_helper.dart'; import 'package:flutter/foundation.dart'; @@ -52,13 +51,19 @@ class VoiceService { return duration; } - static Future voiceHelper({required String src}) async { + static Future voiceHelper( + {required String src, + final Duration? duration, + final Function()? startTimer, + final Function()? stopTimer}) async { try { if (VoiceService.src == src) { if (audioPlayer.playing) { await audioPlayer.pause(); + stopTimer?.call(); } else { await audioPlayer.play(); + startTimer?.call(); } return; } @@ -88,6 +93,8 @@ class VoiceService { await audioPlayer.setFilePath(src); } await audioPlayer.play(); + + startTimer?.call(); } catch (e) { resetVoicePlayer(); } diff --git a/lib/services/network/request.dart b/lib/services/network/request.dart index 6a1c596..7982992 100644 --- a/lib/services/network/request.dart +++ b/lib/services/network/request.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'dart:developer'; import 'package:didvan/services/storage/storage.dart'; -import 'package:flutter/foundation.dart'; // ignore: depend_on_referenced_packages import 'package:http/http.dart' as http; diff --git a/lib/utils/action_sheet.dart b/lib/utils/action_sheet.dart index 1ad33dd..dcc4a39 100644 --- a/lib/utils/action_sheet.dart +++ b/lib/utils/action_sheet.dart @@ -348,8 +348,6 @@ class ActionSheetUtils { ), ) : ListView.builder( - padding: - const EdgeInsets.symmetric(vertical: 12), itemCount: state.bots.length, physics: const BouncingScrollPhysics(), shrinkWrap: true, diff --git a/lib/views/ai/ai.dart b/lib/views/ai/ai.dart index 34ee361..e5a2274 100644 --- a/lib/views/ai/ai.dart +++ b/lib/views/ai/ai.dart @@ -1,5 +1,7 @@ // ignore_for_file: library_private_types_in_public_api +import 'dart:math'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; @@ -9,6 +11,7 @@ import 'package:didvan/models/ai/ai_chat_args.dart'; import 'package:didvan/routes/routes.dart'; import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/views/ai/history_ai_chat_state.dart'; +import 'package:didvan/views/ai/widgets/message_bar_btn.dart'; import 'package:didvan/views/home/home.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:flutter/material.dart'; @@ -83,38 +86,66 @@ class _AiState extends State { onTap: () => ActionSheetUtils(context) .botsDialogSelect( context: context, state: state), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(360), + border: Border.all( + width: 1, + color: + Theme.of(context).colorScheme.text)), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, horizontal: 18), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - DidvanIcons.caret_down_solid, - color: - Theme.of(context).colorScheme.title, + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Column( + children: [ + Transform.rotate( + angle: 180 * pi / 180, + child: Icon( + DidvanIcons.caret_down_solid, + color: Theme.of(context) + .colorScheme + .title, + ), + ), + Icon( + DidvanIcons.caret_down_solid, + color: Theme.of(context) + .colorScheme + .title, + ), + ], + ), + const SizedBox( + width: 12, + ), + DidvanText(bot.name.toString(), + color: Theme.of(context) + .colorScheme + .title), + ], ), const SizedBox( width: 12, ), - DidvanText(bot.name.toString(), - color: Theme.of(context) - .colorScheme - .title), + ClipOval( + child: CachedNetworkImage( + width: 46, + height: 46, + imageUrl: bot.image.toString(), + ), + ), ], ), - const SizedBox( - width: 12, - ), - ClipOval( - child: CachedNetworkImage( - width: 46, - height: 46, - imageUrl: bot.image.toString(), - ), - ), - ], + ), ), ), const SizedBox( @@ -161,43 +192,71 @@ class _AiState extends State { arguments: AiChatArgs( bot: bot, )), - child: Container( - decoration: BoxDecoration( - boxShadow: DesignConfig.defaultShadow, - color: Theme.of(context).colorScheme.surface, - border: Border.all( - color: Theme.of(context).colorScheme.border), - borderRadius: DesignConfig.highBorderRadius), - child: Row( - children: [ - const SizedBox( - width: 8, + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + boxShadow: DesignConfig.defaultShadow, + color: Theme.of(context).colorScheme.surface, + border: Border.all( + color: Theme.of(context).colorScheme.border), + borderRadius: DesignConfig.highBorderRadius), + child: Row( + children: [ + const SizedBox( + width: 8, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + child: Form( + child: Row( + children: [ + const MessageBarBtn( + enable: false, + icon: DidvanIcons.mic_regular), + const SizedBox( + width: 8, + ), + Expanded( + child: TextFormField( + textInputAction: + TextInputAction.newline, + style: Theme.of(context) + .textTheme + .bodyMedium, + minLines: 1, + enabled: false, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'بنویسید...', + hintStyle: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: Theme.of(context) + .colorScheme + .disabledText), + ), + ), + ), + ], + )))) + ], + ), ), - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - ), - child: Form( - child: TextFormField( - textInputAction: TextInputAction.newline, - style: Theme.of(context).textTheme.bodyMedium, - minLines: 1, - enabled: false, - decoration: InputDecoration( - border: InputBorder.none, - hintText: 'بنویسید...', - hintStyle: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: Theme.of(context) - .colorScheme - .disabledText), - ), - )))) - ], - ), + ), + const SizedBox( + width: 18, + ), + Icon( + Icons.attach_file_rounded, + color: Theme.of(context).colorScheme.focusedBorder, + ), + ], )), ), ], diff --git a/lib/views/ai/ai_chat_page.dart b/lib/views/ai/ai_chat_page.dart index dce574a..e3f32ea 100644 --- a/lib/views/ai/ai_chat_page.dart +++ b/lib/views/ai/ai_chat_page.dart @@ -232,23 +232,29 @@ class _AiChatPageState extends State { const SizedBox( height: 24, ), - SizedBox( - width: MediaQuery.sizeOf(context).height / 5, - height: MediaQuery.sizeOf(context).height / 5, - child: ClipOval( - child: CachedNetworkImage( - imageUrl: widget.args.bot.image.toString(), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + DidvanText(widget.args.bot.name.toString()), + const SizedBox( + width: 12, ), - ), + ClipOval( + child: CachedNetworkImage( + width: 46, + height: 46, + imageUrl: widget.args.bot.image.toString(), + ), + ), + ], ), const SizedBox( height: 24, ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 20.0), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 20.0), child: Text( - "به هوشان, هوش مصنوعی دیدوان خوش آمدید. \nبرای شروع گفتگو پیام مورد نظر خود را در کادر زیر بنویسید.\n دریافت پاسخ از: ${widget.args.bot.name}", + "به هوشان, هوش مصنوعی دیدوان خوش آمدید. \nبرای شروع گفتگو پیام مورد نظر خود را در کادر زیر بنویسید.", textAlign: TextAlign.center, ), ) @@ -324,7 +330,12 @@ class _AiChatPageState extends State { Widget messageBubble(Prompts message, BuildContext context, AiChatState state, int index, int mIndex) { FilesModel? file = message.fileLocal ?? - (message.file == null ? null : FilesModel(message.file.toString())); + (message.file == null + ? null + : FilesModel(message.file.toString(), + duration: message.duration != null + ? Duration(seconds: message.duration!) + : null)); MarkdownStyleSheet defaultMarkdownStyleSheet = MarkdownStyleSheet( pPadding: const EdgeInsets.all(0.8), @@ -427,7 +438,10 @@ class _AiChatPageState extends State { ? Padding( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8), - child: AudioWave(file: file.path), + child: AudioWave( + file: file.path, + totalDuration: file.duration, + ), ) : file.isImage() ? Padding( diff --git a/lib/views/ai/widgets/ai_message_bar.dart b/lib/views/ai/widgets/ai_message_bar.dart index e53b278..b9bd547 100644 --- a/lib/views/ai/widgets/ai_message_bar.dart +++ b/lib/views/ai/widgets/ai_message_bar.dart @@ -9,6 +9,7 @@ import 'package:didvan/models/ai/chats_model.dart'; import 'package:didvan/models/ai/files_model.dart'; import 'package:didvan/models/ai/messages_model.dart'; import 'package:didvan/services/media/media.dart'; +import 'package:didvan/services/media/voice.dart'; import 'package:didvan/utils/action_sheet.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/ai/ai_chat_state.dart'; @@ -337,13 +338,21 @@ class _AiMessageBarState extends State { path = await record .stop(); + Duration? duration = + await VoiceService + .getDuration( + src: path ?? + ''); + state.file = FilesModel( path.toString(), name: '${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a', isRecorded: true, audio: true, - image: false); + image: false, + duration: + duration); _timer.cancel(); _countTimer.value = 0; state.update(); @@ -371,7 +380,7 @@ class _AiMessageBarState extends State { .hasPermission()) { try { String path = - ''; + '${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a'; // if (!kIsWeb) { Directory? diff --git a/lib/views/ai/widgets/audio_wave.dart b/lib/views/ai/widgets/audio_wave.dart index 3b13a09..2986378 100644 --- a/lib/views/ai/widgets/audio_wave.dart +++ b/lib/views/ai/widgets/audio_wave.dart @@ -6,7 +6,6 @@ import 'package:audio_video_progress_bar/audio_video_progress_bar.dart'; import 'package:didvan/config/design_config.dart'; 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/voice.dart'; import 'package:didvan/views/ai/widgets/message_bar_btn.dart'; import 'package:flutter/foundation.dart'; @@ -17,7 +16,12 @@ import 'package:just_audio/just_audio.dart'; class AudioWave extends StatefulWidget { final String file; final double loadingPaddingSize; - const AudioWave({Key? key, required this.file, this.loadingPaddingSize = 0}) + final Duration? totalDuration; + const AudioWave( + {Key? key, + required this.file, + this.loadingPaddingSize = 0, + this.totalDuration}) : super(key: key); @override @@ -35,14 +39,18 @@ class _AudioWaveState extends State { void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - await VoiceService.getDuration(src: widget.file).then((duration) { - setState(() { - totalDuration = duration; - if (kDebugMode) { - print(totalDuration!.inSeconds); - } + if (widget.totalDuration == null) { + await VoiceService.getDuration(src: widget.file).then((duration) { + setState(() { + totalDuration = duration; + if (kDebugMode) { + print(totalDuration!.inSeconds); + } + }); }); - }); + } else { + totalDuration = widget.totalDuration; + } }); // listeners(); } @@ -63,18 +71,18 @@ class _AudioWaveState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ - StreamBuilder( - stream: VoiceService.audioPlayer.playerStateStream, + StreamBuilder( + stream: VoiceService.audioPlayer.playbackEventStream, builder: (context, snapshot) { if (!snapshot.hasData) { return const SizedBox(); } + if (snapshot.data!.processingState == ProcessingState.completed) { VoiceService.audioPlayer.pause(); VoiceService.audioPlayer.seek(Duration.zero); } - print(snapshot.data); if ((snapshot.data!.processingState == ProcessingState.loading || snapshot.data!.processingState == @@ -91,7 +99,7 @@ class _AudioWaveState extends State { } return MessageBarBtn( enable: true, - icon: snapshot.data!.playing && + icon: VoiceService.audioPlayer.playing && VoiceService.src == widget.file ? DidvanIcons.pause_solid : DidvanIcons.play_solid, @@ -107,7 +115,12 @@ class _AudioWaveState extends State { if (!snapshot.hasData) { return const SizedBox(); } - return totalDuration == null + return totalDuration == null || + (totalDuration != null && + VoiceService.audioPlayer.playing && + VoiceService.audioPlayer.duration!.inSeconds != + totalDuration!.inSeconds && + VoiceService.src == widget.file) ? Padding( padding: EdgeInsets.symmetric( vertical: widget.loadingPaddingSize), diff --git a/lib/views/ai/widgets/message_bar_btn.dart b/lib/views/ai/widgets/message_bar_btn.dart index 38b6d96..02c4ed2 100644 --- a/lib/views/ai/widgets/message_bar_btn.dart +++ b/lib/views/ai/widgets/message_bar_btn.dart @@ -1,5 +1,4 @@ import 'package:didvan/config/theme_data.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; @@ -44,7 +43,6 @@ class MessageBarBtn extends StatelessWidget { child: Padding( padding: EdgeInsets.all(8.0), child: SpinKitCircle( - size: 24, color: Colors.white, ), )) diff --git a/lib/views/direct/widgets/audio_widget.dart b/lib/views/direct/widgets/audio_widget.dart index 91b42a8..67938ec 100644 --- a/lib/views/direct/widgets/audio_widget.dart +++ b/lib/views/direct/widgets/audio_widget.dart @@ -17,12 +17,14 @@ class AudioWidget extends StatelessWidget { final File? audioFile; final int id; final StudioDetailsData? audioMetaData; + final Duration? duration; const AudioWidget({ Key? key, this.audioUrl, this.audioFile, required this.id, this.audioMetaData, + this.duration, }) : super(key: key); @override @@ -43,7 +45,8 @@ class AudioWidget extends StatelessWidget { tag: audioMetaData != null ? '${audioMetaData!.type}-$id' : 'message-$id', - duration: audioMetaData?.duration, + duration: + audioMetaData?.duration ?? duration?.inSeconds, showTimer: true, ), ), @@ -88,6 +91,11 @@ class _AudioControllerButton extends StatelessWidget { return StreamBuilder( stream: MediaService.audioPlayer.playerStateStream, builder: (context, snapshot) { + if (snapshot.hasData && + snapshot.data!.processingState == ProcessingState.completed) { + MediaService.audioPlayer.pause(); + MediaService.audioPlayer.seek(Duration.zero); + } return DidvanIconButton( icon: MediaService.audioPlayer.playing && _nowPlaying ? DidvanIcons.pause_circle_solid diff --git a/lib/views/direct/widgets/message.dart b/lib/views/direct/widgets/message.dart index 7769ed8..5438299 100644 --- a/lib/views/direct/widgets/message.dart +++ b/lib/views/direct/widgets/message.dart @@ -2,6 +2,7 @@ import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/constants/app_icons.dart'; import 'package:didvan/models/message_data/message_data.dart'; +import 'package:didvan/services/media/voice.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/direct/direct_state.dart'; import 'package:didvan/views/direct/widgets/audio_widget.dart'; @@ -9,6 +10,7 @@ import 'package:didvan/views/widgets/didvan/divider.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/skeleton_image.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:provider/provider.dart'; import 'package:persian_number_utility/persian_number_utility.dart'; @@ -84,11 +86,34 @@ class Message extends StatelessWidget { children: [ if (message.text != null) DidvanText(message.text!), if (message.audio != null || message.audioFile != null) - AudioWidget( - audioFile: message.audioFile, - audioUrl: message.audio, - id: message.id, - ), + FutureBuilder( + future: VoiceService.getDuration( + src: message.audioFile == null + ? message.audio! + : message.audioFile!.path), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: List.generate( + 5, + (index) => SpinKitWave( + color: Theme.of(context) + .colorScheme + .primary + .withOpacity(0.4), + size: 32, + itemCount: 10, + ))); + } + return AudioWidget( + audioFile: message.audioFile, + audioUrl: message.audio, + id: message.id, + duration: snapshot.data, + ); + }), if (message.radar != null || message.news != null) const DidvanDivider(), if (message.radar != null || message.news != null) diff --git a/lib/views/widgets/audio/audio_slider.dart b/lib/views/widgets/audio/audio_slider.dart index 2f62b01..8309963 100644 --- a/lib/views/widgets/audio/audio_slider.dart +++ b/lib/views/widgets/audio/audio_slider.dart @@ -21,7 +21,6 @@ class AudioSlider extends StatelessWidget { @override Widget build(BuildContext context) { - print(MediaService.audioPlayerTag); return IgnorePointer( ignoring: !_isPlaying, child: Directionality( diff --git a/pubspec.lock b/pubspec.lock index 3884820..9144e01 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -73,14 +73,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.8.2" - azblob: - dependency: "direct main" - description: - name: azblob - sha256: e9e8689280bd8fa19c1c21a476547de80d2a770c81d2da9da68173c7f5479c7b - url: "https://pub.dev" - source: hosted - version: "4.0.0" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6d2e86f..bbb68b9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -95,7 +95,6 @@ dependencies: flutter_local_notifications: ^17.2.2 flutter_background_service: ^5.0.10 js: ^0.6.7 - azblob: ^4.0.0 # url_launcher: ^6.3.0 dev_dependencies: