Commit 22908b56 authored by skeyboy's avatar skeyboy

语音播放动画控制

parent 405ae83f
library dash_chat_2; library dash_chat_2;
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:custom_pop_up_menu/custom_pop_up_menu.dart'; import 'package:custom_pop_up_menu/custom_pop_up_menu.dart';
import 'package:clipboard/clipboard.dart'; import 'package:clipboard/clipboard.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_tts/flutter_tts.dart'; import 'package:flutter_tts/flutter_tts.dart';
import 'package:flutter_vibrate/flutter_vibrate.dart';
import 'package:highlight/highlight.dart' show highlight, Node; import 'package:highlight/highlight.dart' show highlight, Node;
import 'package:animated_text_kit/animated_text_kit.dart'; import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:chart/package/markdown/flutter_markdown.dart'; import 'package:chart/package/markdown/flutter_markdown.dart';
...@@ -20,6 +22,7 @@ import 'package:intl/intl.dart' as intl; ...@@ -20,6 +22,7 @@ import 'package:intl/intl.dart' as intl;
import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:vibration/vibration.dart';
import 'package:video_player/video_player.dart' as vp; import 'package:video_player/video_player.dart' as vp;
import '../../pages/home/controller.dart'; import '../../pages/home/controller.dart';
......
...@@ -48,6 +48,9 @@ class ChatMessage { ...@@ -48,6 +48,9 @@ class ChatMessage {
/// Text of the message (optional because you can also just send a media) /// Text of the message (optional because you can also just send a media)
String text; String text;
/// 是否在播放
bool isPlaying = false;
VoidCallback? stopCallback = null;
/// Author of the message /// Author of the message
ChatUser user; ChatUser user;
......
...@@ -9,6 +9,7 @@ class ChartTTS { ...@@ -9,6 +9,7 @@ class ChartTTS {
double pitch; double pitch;
String language = "zh-CN"; String language = "zh-CN";
static ChartTTS tts = ChartTTS(); static ChartTTS tts = ChartTTS();
List<ChatMessage> messages = <ChatMessage>[];
ChartTTS( ChartTTS(
{this.voiceName = "zh", {this.voiceName = "zh",
...@@ -25,15 +26,31 @@ class ChartTTS { ...@@ -25,15 +26,31 @@ class ChartTTS {
FlutterTts get flutterTts => _flutterTts; FlutterTts get flutterTts => _flutterTts;
Future<void> speak(String message, VoidCallback? onFinishedCallback) async { Future<void> speak(
ChatMessage message, VoidCallback? onFinishedCallback) async {
messages.forEach((element) {
element.isPlaying = false;
if (element.stopCallback != null) {
element.stopCallback!();
}
});
messages.add(message);
//先停止 //先停止
await stop(); await stop();
messages.forEach((element) {
element.isPlaying = false;
});
_flutterTts.setCompletionHandler(() { _flutterTts.setCompletionHandler(() {
if (onFinishedCallback != null) { if (onFinishedCallback != null) {
message.isPlaying = false;
messages.forEach((element) {
element.isPlaying = false;
});
onFinishedCallback(); onFinishedCallback();
} }
}); });
var rev = await _flutterTts.speak(message); var rev = await _flutterTts.speak(message.text);
message.isPlaying = true;
} }
Future<void> stop() async { Future<void> stop() async {
......
...@@ -34,6 +34,21 @@ class DefaultMessageText extends StatefulWidget { ...@@ -34,6 +34,21 @@ class DefaultMessageText extends StatefulWidget {
class _DefaultMessageTextState extends State<DefaultMessageText> { class _DefaultMessageTextState extends State<DefaultMessageText> {
CustomPopupMenuController controller = CustomPopupMenuController(); CustomPopupMenuController controller = CustomPopupMenuController();
@override
void initState() {
controller.addListener(() {
if (controller.menuIsShowing) {
Vibrate.feedback(FeedbackType.impact);
}
});
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
...@@ -250,14 +265,14 @@ class _DefaultMessageTextState extends State<DefaultMessageText> { ...@@ -250,14 +265,14 @@ class _DefaultMessageTextState extends State<DefaultMessageText> {
children: <Widget>[ children: <Widget>[
const Icon( const Icon(
Icons.content_copy, Icons.content_copy,
size: 20, size: 12,
color: Colors.white, color: Colors.white,
), ),
Container( Container(
margin: EdgeInsets.only(top: 2), margin: EdgeInsets.only(top: 2),
child: Text( child: Text(
"复制", "复制",
style: TextStyle(color: Colors.white, fontSize: 12), style: TextStyle(color: Colors.white, fontSize: 8),
), ),
), ),
], ],
...@@ -276,14 +291,14 @@ class _DefaultMessageTextState extends State<DefaultMessageText> { ...@@ -276,14 +291,14 @@ class _DefaultMessageTextState extends State<DefaultMessageText> {
children: <Widget>[ children: <Widget>[
const Icon( const Icon(
Icons.share, Icons.share,
size: 20, size: 12,
color: Colors.white, color: Colors.white,
), ),
Container( Container(
margin: EdgeInsets.only(top: 2), margin: EdgeInsets.only(top: 2),
child: const Text( child: const Text(
"分享", "分享",
style: TextStyle(color: Colors.white, fontSize: 12), style: TextStyle(color: Colors.white, fontSize: 8),
), ),
), ),
], ],
...@@ -393,35 +408,47 @@ class MyStyleSheet extends MarkdownStyleSheet { ...@@ -393,35 +408,47 @@ class MyStyleSheet extends MarkdownStyleSheet {
class ChartTTSWave extends StatefulWidget { class ChartTTSWave extends StatefulWidget {
String text; String text;
ChatMessage message;
ChartTTSWave({Key? key, required this.text}) : super(key: key); ChartTTSWave({Key? key, required this.text, required this.message}) : super(key: key);
@override @override
State<ChartTTSWave> createState() => _ChartTTSWaveState(); State<ChartTTSWave> createState() => _ChartTTSWaveState();
} }
class _ChartTTSWaveState extends State<ChartTTSWave> { class _ChartTTSWaveState extends State<ChartTTSWave> {
var isPlaying = false;
void stopCallback() {
setState(() {
widget.message.isPlaying = false;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
widget.message.stopCallback = stopCallback;
return GestureDetector( return GestureDetector(
onTap: () async { onTap: () async {
ChartTTS.tts.speak(widget.text, () { ChartTTS.tts.speak(widget.message, () {
setState(() { setState(() {
isPlaying = false; // widget.message.isPlaying = false;
}); });
}); });
setState(() { setState(() {
isPlaying = true; widget.message.isPlaying = true;
}); });
}, },
child: isPlaying child: widget.message.isPlaying
? LoadingAnimationWidget.staggeredDotsWave( ? LoadingAnimationWidget.staggeredDotsWave(
color: Colors.white, color: Colors.white,
size: 20, size: 12,
) )
: Icon(Icons.record_voice_over_sharp), : CircleAvatar(
child: Icon(
Icons.record_voice_over_sharp,
size: 24,
),
backgroundColor: Colors.black54,
),
); );
} }
} }
...@@ -168,8 +168,9 @@ class MessageRow extends StatelessWidget { ...@@ -168,8 +168,9 @@ class MessageRow extends StatelessWidget {
messageOptions.messageTextBuilder, messageOptions.messageTextBuilder,
)), )),
Padding( Padding(
key: ValueKey(message.hashCode),
padding: EdgeInsets.only(left: 10, top: 15), padding: EdgeInsets.only(left: 10, top: 15),
child: ChartTTSWave(text: message.text)), child: ChartTTSWave(text: message.text, message: message,)),
], ],
)), )),
if (message.medias != null && if (message.medias != null &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment