little better fix audio 3/07/1403
This commit is contained in:
parent
f72228b339
commit
fbb9db5103
|
|
@ -99,9 +99,10 @@ class Prompts {
|
||||||
bool? error;
|
bool? error;
|
||||||
bool? audio;
|
bool? audio;
|
||||||
FilesModel? fileLocal;
|
FilesModel? fileLocal;
|
||||||
|
int? duration;
|
||||||
|
|
||||||
Prompts({
|
Prompts(
|
||||||
this.id,
|
{this.id,
|
||||||
this.chatId,
|
this.chatId,
|
||||||
this.text,
|
this.text,
|
||||||
this.file,
|
this.file,
|
||||||
|
|
@ -112,7 +113,7 @@ class Prompts {
|
||||||
this.error,
|
this.error,
|
||||||
this.fileLocal,
|
this.fileLocal,
|
||||||
this.audio,
|
this.audio,
|
||||||
});
|
this.duration});
|
||||||
|
|
||||||
Prompts.fromJson(Map<String, dynamic> json) {
|
Prompts.fromJson(Map<String, dynamic> json) {
|
||||||
id = json['id'];
|
id = json['id'];
|
||||||
|
|
@ -123,6 +124,7 @@ class Prompts {
|
||||||
role = json['role'];
|
role = json['role'];
|
||||||
createdAt = json['createdAt'];
|
createdAt = json['createdAt'];
|
||||||
audio = json['audio'];
|
audio = json['audio'];
|
||||||
|
duration = json['duration'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
|
|
@ -135,11 +137,12 @@ class Prompts {
|
||||||
data['role'] = role;
|
data['role'] = role;
|
||||||
data['createdAt'] = createdAt;
|
data['createdAt'] = createdAt;
|
||||||
data['audio'] = audio;
|
data['audio'] = audio;
|
||||||
|
data['duration'] = duration;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Prompts copyWith(
|
Prompts copyWith({
|
||||||
{int? id,
|
int? id,
|
||||||
int? chatId,
|
int? chatId,
|
||||||
String? text,
|
String? text,
|
||||||
String? file,
|
String? file,
|
||||||
|
|
@ -149,7 +152,9 @@ class Prompts {
|
||||||
String? createdAt,
|
String? createdAt,
|
||||||
bool? finished,
|
bool? finished,
|
||||||
bool? error,
|
bool? error,
|
||||||
bool? audio}) {
|
bool? audio,
|
||||||
|
int? duration,
|
||||||
|
}) {
|
||||||
return Prompts(
|
return Prompts(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
chatId: chatId ?? this.chatId,
|
chatId: chatId ?? this.chatId,
|
||||||
|
|
@ -162,6 +167,7 @@ class Prompts {
|
||||||
finished: finished ?? this.finished,
|
finished: finished ?? this.finished,
|
||||||
error: error ?? this.error,
|
error: error ?? this.error,
|
||||||
audio: audio ?? this.audio,
|
audio: audio ?? this.audio,
|
||||||
|
duration: duration ?? this.duration,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class FilesModel {
|
||||||
final bool? image;
|
final bool? image;
|
||||||
final bool? network;
|
final bool? network;
|
||||||
final Uint8List? bytes;
|
final Uint8List? bytes;
|
||||||
|
final Duration? duration;
|
||||||
|
|
||||||
FilesModel(
|
FilesModel(
|
||||||
this.path, {
|
this.path, {
|
||||||
|
|
@ -23,6 +24,7 @@ class FilesModel {
|
||||||
this.image,
|
this.image,
|
||||||
this.network,
|
this.network,
|
||||||
this.bytes,
|
this.bytes,
|
||||||
|
this.duration,
|
||||||
}) {
|
}) {
|
||||||
basename = name ?? p.basename(path);
|
basename = name ?? p.basename(path);
|
||||||
extname = p.extension(path);
|
extname = p.extension(path);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,11 @@ class AiApiService {
|
||||||
if (edite != null) {
|
if (edite != null) {
|
||||||
request.fields['edit'] = edite.toString().toLowerCase();
|
request.fields['edit'] = edite.toString().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
|
if (file.duration != null) {
|
||||||
|
request.fields['duration'] = file.duration!.inSeconds.toString();
|
||||||
|
}
|
||||||
Uint8List bytes;
|
Uint8List bytes;
|
||||||
String filename;
|
String filename;
|
||||||
String mimeType;
|
String mimeType;
|
||||||
|
|
@ -45,6 +49,8 @@ class AiApiService {
|
||||||
final Uri audioUri = Uri.parse(file.path.replaceAll('%3A', ':'));
|
final Uri audioUri = Uri.parse(file.path.replaceAll('%3A', ':'));
|
||||||
final http.Response audioResponse = await http.get(audioUri);
|
final http.Response audioResponse = await http.get(audioUri);
|
||||||
bytes = audioResponse.bodyBytes;
|
bytes = audioResponse.bodyBytes;
|
||||||
|
// final f = File.fromUri(Uri.parse(file.path));
|
||||||
|
// bytes = await f.readAsBytes();
|
||||||
|
|
||||||
// Fetch the blob using JavaScript interop
|
// Fetch the blob using JavaScript interop
|
||||||
// final blob = await html.window
|
// final blob = await html.window
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ class MediaService {
|
||||||
String tag;
|
String tag;
|
||||||
tag =
|
tag =
|
||||||
'${currentPodcast?.description == 'radar' ? 'radar' : isVoiceMessage ? 'message' : 'podcast'}-$id';
|
'${currentPodcast?.description == 'radar' ? 'radar' : isVoiceMessage ? 'message' : 'podcast'}-$id';
|
||||||
print("tag: $tag");
|
|
||||||
if (!isVoiceMessage && MediaProvider.downloadedItemIds.contains(id)) {
|
if (!isVoiceMessage && MediaProvider.downloadedItemIds.contains(id)) {
|
||||||
audioSource = '${StorageService.appDocsDir}/podcasts/podcast-$id.mp3';
|
audioSource = '${StorageService.appDocsDir}/podcasts/podcast-$id.mp3';
|
||||||
isNetworkAudio = false;
|
isNetworkAudio = false;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
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';
|
||||||
|
|
@ -52,13 +51,19 @@ class VoiceService {
|
||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> voiceHelper({required String src}) async {
|
static Future<void> voiceHelper(
|
||||||
|
{required String src,
|
||||||
|
final Duration? duration,
|
||||||
|
final Function()? startTimer,
|
||||||
|
final Function()? stopTimer}) async {
|
||||||
try {
|
try {
|
||||||
if (VoiceService.src == src) {
|
if (VoiceService.src == src) {
|
||||||
if (audioPlayer.playing) {
|
if (audioPlayer.playing) {
|
||||||
await audioPlayer.pause();
|
await audioPlayer.pause();
|
||||||
|
stopTimer?.call();
|
||||||
} else {
|
} else {
|
||||||
await audioPlayer.play();
|
await audioPlayer.play();
|
||||||
|
startTimer?.call();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -88,6 +93,8 @@ class VoiceService {
|
||||||
await audioPlayer.setFilePath(src);
|
await audioPlayer.setFilePath(src);
|
||||||
}
|
}
|
||||||
await audioPlayer.play();
|
await audioPlayer.play();
|
||||||
|
|
||||||
|
startTimer?.call();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
resetVoicePlayer();
|
resetVoicePlayer();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'package:didvan/services/storage/storage.dart';
|
import 'package:didvan/services/storage/storage.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
// ignore: depend_on_referenced_packages
|
// ignore: depend_on_referenced_packages
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
|
||||||
|
|
@ -348,8 +348,6 @@ class ActionSheetUtils {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
padding:
|
|
||||||
const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
itemCount: state.bots.length,
|
itemCount: state.bots.length,
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
// ignore_for_file: library_private_types_in_public_api
|
// ignore_for_file: library_private_types_in_public_api
|
||||||
|
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:didvan/config/design_config.dart';
|
import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/config/theme_data.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/routes/routes.dart';
|
||||||
import 'package:didvan/utils/action_sheet.dart';
|
import 'package:didvan/utils/action_sheet.dart';
|
||||||
import 'package:didvan/views/ai/history_ai_chat_state.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/home/home.dart';
|
||||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
@ -83,17 +86,43 @@ class _AiState extends State<Ai> {
|
||||||
onTap: () => ActionSheetUtils(context)
|
onTap: () => ActionSheetUtils(context)
|
||||||
.botsDialogSelect(
|
.botsDialogSelect(
|
||||||
context: context, state: state),
|
context: context, state: state),
|
||||||
|
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(
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Transform.rotate(
|
||||||
|
angle: 180 * pi / 180,
|
||||||
|
child: Icon(
|
||||||
|
DidvanIcons.caret_down_solid,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.title,
|
||||||
|
),
|
||||||
|
),
|
||||||
Icon(
|
Icon(
|
||||||
DidvanIcons.caret_down_solid,
|
DidvanIcons.caret_down_solid,
|
||||||
color:
|
color: Theme.of(context)
|
||||||
Theme.of(context).colorScheme.title,
|
.colorScheme
|
||||||
|
.title,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 12,
|
width: 12,
|
||||||
|
|
@ -117,6 +146,8 @@ class _AiState extends State<Ai> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
|
|
@ -161,6 +192,9 @@ class _AiState extends State<Ai> {
|
||||||
arguments: AiChatArgs(
|
arguments: AiChatArgs(
|
||||||
bot: bot,
|
bot: bot,
|
||||||
)),
|
)),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
boxShadow: DesignConfig.defaultShadow,
|
boxShadow: DesignConfig.defaultShadow,
|
||||||
|
|
@ -179,9 +213,21 @@ class _AiState extends State<Ai> {
|
||||||
horizontal: 8.0,
|
horizontal: 8.0,
|
||||||
),
|
),
|
||||||
child: Form(
|
child: Form(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const MessageBarBtn(
|
||||||
|
enable: false,
|
||||||
|
icon: DidvanIcons.mic_regular),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
textInputAction: TextInputAction.newline,
|
textInputAction:
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
TextInputAction.newline,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium,
|
||||||
minLines: 1,
|
minLines: 1,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
|
@ -195,9 +241,22 @@ class _AiState extends State<Ai> {
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.disabledText),
|
.disabledText),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
))))
|
))))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 18,
|
||||||
|
),
|
||||||
|
Icon(
|
||||||
|
Icons.attach_file_rounded,
|
||||||
|
color: Theme.of(context).colorScheme.focusedBorder,
|
||||||
|
),
|
||||||
|
],
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -232,23 +232,29 @@ class _AiChatPageState extends State<AiChatPage> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
SizedBox(
|
Row(
|
||||||
width: MediaQuery.sizeOf(context).height / 5,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
height: MediaQuery.sizeOf(context).height / 5,
|
children: [
|
||||||
child: ClipOval(
|
DidvanText(widget.args.bot.name.toString()),
|
||||||
|
const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
ClipOval(
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
|
width: 46,
|
||||||
|
height: 46,
|
||||||
imageUrl: widget.args.bot.image.toString(),
|
imageUrl: widget.args.bot.image.toString(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
Padding(
|
const Padding(
|
||||||
padding:
|
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||||
const EdgeInsets.symmetric(horizontal: 20.0),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
"به هوشان, هوش مصنوعی دیدوان خوش آمدید. \nبرای شروع گفتگو پیام مورد نظر خود را در کادر زیر بنویسید.\n دریافت پاسخ از: ${widget.args.bot.name}",
|
"به هوشان, هوش مصنوعی دیدوان خوش آمدید. \nبرای شروع گفتگو پیام مورد نظر خود را در کادر زیر بنویسید.",
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -324,7 +330,12 @@ class _AiChatPageState extends State<AiChatPage> {
|
||||||
Widget messageBubble(Prompts message, BuildContext context, AiChatState state,
|
Widget messageBubble(Prompts message, BuildContext context, AiChatState state,
|
||||||
int index, int mIndex) {
|
int index, int mIndex) {
|
||||||
FilesModel? file = message.fileLocal ??
|
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(
|
MarkdownStyleSheet defaultMarkdownStyleSheet = MarkdownStyleSheet(
|
||||||
pPadding: const EdgeInsets.all(0.8),
|
pPadding: const EdgeInsets.all(0.8),
|
||||||
|
|
@ -427,7 +438,10 @@ class _AiChatPageState extends State<AiChatPage> {
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 16, vertical: 8),
|
horizontal: 16, vertical: 8),
|
||||||
child: AudioWave(file: file.path),
|
child: AudioWave(
|
||||||
|
file: file.path,
|
||||||
|
totalDuration: file.duration,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: file.isImage()
|
: file.isImage()
|
||||||
? Padding(
|
? Padding(
|
||||||
|
|
|
||||||
|
|
@ -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/files_model.dart';
|
||||||
import 'package:didvan/models/ai/messages_model.dart';
|
import 'package:didvan/models/ai/messages_model.dart';
|
||||||
import 'package:didvan/services/media/media.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/action_sheet.dart';
|
||||||
import 'package:didvan/utils/date_time.dart';
|
import 'package:didvan/utils/date_time.dart';
|
||||||
import 'package:didvan/views/ai/ai_chat_state.dart';
|
import 'package:didvan/views/ai/ai_chat_state.dart';
|
||||||
|
|
@ -337,13 +338,21 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
||||||
path = await record
|
path = await record
|
||||||
.stop();
|
.stop();
|
||||||
|
|
||||||
|
Duration? duration =
|
||||||
|
await VoiceService
|
||||||
|
.getDuration(
|
||||||
|
src: path ??
|
||||||
|
'');
|
||||||
|
|
||||||
state.file = FilesModel(
|
state.file = FilesModel(
|
||||||
path.toString(),
|
path.toString(),
|
||||||
name:
|
name:
|
||||||
'${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a',
|
'${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a',
|
||||||
isRecorded: true,
|
isRecorded: true,
|
||||||
audio: true,
|
audio: true,
|
||||||
image: false);
|
image: false,
|
||||||
|
duration:
|
||||||
|
duration);
|
||||||
_timer.cancel();
|
_timer.cancel();
|
||||||
_countTimer.value = 0;
|
_countTimer.value = 0;
|
||||||
state.update();
|
state.update();
|
||||||
|
|
@ -371,7 +380,7 @@ class _AiMessageBarState extends State<AiMessageBar> {
|
||||||
.hasPermission()) {
|
.hasPermission()) {
|
||||||
try {
|
try {
|
||||||
String path =
|
String path =
|
||||||
'';
|
'${DateTime.now().millisecondsSinceEpoch ~/ 1000}.m4a';
|
||||||
//
|
//
|
||||||
if (!kIsWeb) {
|
if (!kIsWeb) {
|
||||||
Directory?
|
Directory?
|
||||||
|
|
|
||||||
|
|
@ -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/design_config.dart';
|
||||||
import 'package:didvan/config/theme_data.dart';
|
import 'package:didvan/config/theme_data.dart';
|
||||||
import 'package:didvan/constants/app_icons.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/services/media/voice.dart';
|
||||||
import 'package:didvan/views/ai/widgets/message_bar_btn.dart';
|
import 'package:didvan/views/ai/widgets/message_bar_btn.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
@ -17,7 +16,12 @@ import 'package:just_audio/just_audio.dart';
|
||||||
class AudioWave extends StatefulWidget {
|
class AudioWave extends StatefulWidget {
|
||||||
final String file;
|
final String file;
|
||||||
final double loadingPaddingSize;
|
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);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -35,6 +39,7 @@ class _AudioWaveState extends State<AudioWave> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
if (widget.totalDuration == null) {
|
||||||
await VoiceService.getDuration(src: widget.file).then((duration) {
|
await VoiceService.getDuration(src: widget.file).then((duration) {
|
||||||
setState(() {
|
setState(() {
|
||||||
totalDuration = duration;
|
totalDuration = duration;
|
||||||
|
|
@ -43,6 +48,9 @@ class _AudioWaveState extends State<AudioWave> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
totalDuration = widget.totalDuration;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// listeners();
|
// listeners();
|
||||||
}
|
}
|
||||||
|
|
@ -63,18 +71,18 @@ class _AudioWaveState extends State<AudioWave> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
StreamBuilder<PlayerState>(
|
StreamBuilder<PlaybackEvent>(
|
||||||
stream: VoiceService.audioPlayer.playerStateStream,
|
stream: VoiceService.audioPlayer.playbackEventStream,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (!snapshot.hasData) {
|
if (!snapshot.hasData) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snapshot.data!.processingState ==
|
if (snapshot.data!.processingState ==
|
||||||
ProcessingState.completed) {
|
ProcessingState.completed) {
|
||||||
VoiceService.audioPlayer.pause();
|
VoiceService.audioPlayer.pause();
|
||||||
VoiceService.audioPlayer.seek(Duration.zero);
|
VoiceService.audioPlayer.seek(Duration.zero);
|
||||||
}
|
}
|
||||||
print(snapshot.data);
|
|
||||||
if ((snapshot.data!.processingState ==
|
if ((snapshot.data!.processingState ==
|
||||||
ProcessingState.loading ||
|
ProcessingState.loading ||
|
||||||
snapshot.data!.processingState ==
|
snapshot.data!.processingState ==
|
||||||
|
|
@ -91,7 +99,7 @@ class _AudioWaveState extends State<AudioWave> {
|
||||||
}
|
}
|
||||||
return MessageBarBtn(
|
return MessageBarBtn(
|
||||||
enable: true,
|
enable: true,
|
||||||
icon: snapshot.data!.playing &&
|
icon: VoiceService.audioPlayer.playing &&
|
||||||
VoiceService.src == widget.file
|
VoiceService.src == widget.file
|
||||||
? DidvanIcons.pause_solid
|
? DidvanIcons.pause_solid
|
||||||
: DidvanIcons.play_solid,
|
: DidvanIcons.play_solid,
|
||||||
|
|
@ -107,7 +115,12 @@ class _AudioWaveState extends State<AudioWave> {
|
||||||
if (!snapshot.hasData) {
|
if (!snapshot.hasData) {
|
||||||
return const SizedBox();
|
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(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
vertical: widget.loadingPaddingSize),
|
vertical: widget.loadingPaddingSize),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:didvan/config/theme_data.dart';
|
import 'package:didvan/config/theme_data.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
|
||||||
|
|
@ -44,7 +43,6 @@ class MessageBarBtn extends StatelessWidget {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
child: SpinKitCircle(
|
child: SpinKitCircle(
|
||||||
size: 24,
|
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,14 @@ class AudioWidget extends StatelessWidget {
|
||||||
final File? audioFile;
|
final File? audioFile;
|
||||||
final int id;
|
final int id;
|
||||||
final StudioDetailsData? audioMetaData;
|
final StudioDetailsData? audioMetaData;
|
||||||
|
final Duration? duration;
|
||||||
const AudioWidget({
|
const AudioWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.audioUrl,
|
this.audioUrl,
|
||||||
this.audioFile,
|
this.audioFile,
|
||||||
required this.id,
|
required this.id,
|
||||||
this.audioMetaData,
|
this.audioMetaData,
|
||||||
|
this.duration,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -43,7 +45,8 @@ class AudioWidget extends StatelessWidget {
|
||||||
tag: audioMetaData != null
|
tag: audioMetaData != null
|
||||||
? '${audioMetaData!.type}-$id'
|
? '${audioMetaData!.type}-$id'
|
||||||
: 'message-$id',
|
: 'message-$id',
|
||||||
duration: audioMetaData?.duration,
|
duration:
|
||||||
|
audioMetaData?.duration ?? duration?.inSeconds,
|
||||||
showTimer: true,
|
showTimer: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -88,6 +91,11 @@ class _AudioControllerButton extends StatelessWidget {
|
||||||
return StreamBuilder<PlayerState>(
|
return StreamBuilder<PlayerState>(
|
||||||
stream: MediaService.audioPlayer.playerStateStream,
|
stream: MediaService.audioPlayer.playerStateStream,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData &&
|
||||||
|
snapshot.data!.processingState == ProcessingState.completed) {
|
||||||
|
MediaService.audioPlayer.pause();
|
||||||
|
MediaService.audioPlayer.seek(Duration.zero);
|
||||||
|
}
|
||||||
return DidvanIconButton(
|
return DidvanIconButton(
|
||||||
icon: MediaService.audioPlayer.playing && _nowPlaying
|
icon: MediaService.audioPlayer.playing && _nowPlaying
|
||||||
? DidvanIcons.pause_circle_solid
|
? DidvanIcons.pause_circle_solid
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'package:didvan/config/design_config.dart';
|
||||||
import 'package:didvan/config/theme_data.dart';
|
import 'package:didvan/config/theme_data.dart';
|
||||||
import 'package:didvan/constants/app_icons.dart';
|
import 'package:didvan/constants/app_icons.dart';
|
||||||
import 'package:didvan/models/message_data/message_data.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/utils/date_time.dart';
|
||||||
import 'package:didvan/views/direct/direct_state.dart';
|
import 'package:didvan/views/direct/direct_state.dart';
|
||||||
import 'package:didvan/views/direct/widgets/audio_widget.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/didvan/text.dart';
|
||||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:persian_number_utility/persian_number_utility.dart';
|
import 'package:persian_number_utility/persian_number_utility.dart';
|
||||||
|
|
||||||
|
|
@ -84,11 +86,34 @@ class Message extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
if (message.text != null) DidvanText(message.text!),
|
if (message.text != null) DidvanText(message.text!),
|
||||||
if (message.audio != null || message.audioFile != null)
|
if (message.audio != null || message.audioFile != null)
|
||||||
AudioWidget(
|
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,
|
audioFile: message.audioFile,
|
||||||
audioUrl: message.audio,
|
audioUrl: message.audio,
|
||||||
id: message.id,
|
id: message.id,
|
||||||
),
|
duration: snapshot.data,
|
||||||
|
);
|
||||||
|
}),
|
||||||
if (message.radar != null || message.news != null)
|
if (message.radar != null || message.news != null)
|
||||||
const DidvanDivider(),
|
const DidvanDivider(),
|
||||||
if (message.radar != null || message.news != null)
|
if (message.radar != null || message.news != null)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ class AudioSlider extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
print(MediaService.audioPlayerTag);
|
|
||||||
return IgnorePointer(
|
return IgnorePointer(
|
||||||
ignoring: !_isPlaying,
|
ignoring: !_isPlaying,
|
||||||
child: Directionality(
|
child: Directionality(
|
||||||
|
|
|
||||||
|
|
@ -73,14 +73,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.2"
|
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:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,6 @@ dependencies:
|
||||||
flutter_local_notifications: ^17.2.2
|
flutter_local_notifications: ^17.2.2
|
||||||
flutter_background_service: ^5.0.10
|
flutter_background_service: ^5.0.10
|
||||||
js: ^0.6.7
|
js: ^0.6.7
|
||||||
azblob: ^4.0.0
|
|
||||||
# url_launcher: ^6.3.0
|
# url_launcher: ^6.3.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue