feat: mvp viode
This commit is contained in:
@@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../core/core.dart';
|
||||
import 'voice_mode_overlay.dart';
|
||||
import 'voice_session_controller.dart';
|
||||
|
||||
class InteractionScreen extends ConsumerStatefulWidget {
|
||||
final String characterId;
|
||||
@@ -20,6 +21,7 @@ class _InteractionScreenState extends ConsumerState<InteractionScreen> {
|
||||
List<ChatMessage> _messages = [];
|
||||
final TextEditingController _controller = TextEditingController();
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
VoiceSessionController? _voiceController;
|
||||
bool _isVoiceMode = false;
|
||||
bool _isLoading = false;
|
||||
bool _isTyping = false;
|
||||
@@ -31,8 +33,10 @@ class _InteractionScreenState extends ConsumerState<InteractionScreen> {
|
||||
_loadCharacterAndMessages();
|
||||
}
|
||||
|
||||
@override
|
||||
@override
|
||||
void dispose() {
|
||||
_voiceController?.dispose();
|
||||
_controller.dispose();
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
@@ -81,6 +85,38 @@ class _InteractionScreenState extends ConsumerState<InteractionScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
void _enterVoiceMode() {
|
||||
FocusScope.of(context).unfocus();
|
||||
_voiceController = VoiceSessionController(
|
||||
character: _character!,
|
||||
onUserMessage: (text) {
|
||||
if (!mounted) return;
|
||||
final userMsg = ChatMessage.user(text);
|
||||
setState(() {
|
||||
_messages = [..._messages, userMsg];
|
||||
});
|
||||
ChatStorageService.addMessage(widget.characterId, userMsg);
|
||||
_scrollToBottom();
|
||||
},
|
||||
onAiMessage: (msg) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_messages = [..._messages, msg];
|
||||
});
|
||||
ChatStorageService.addMessage(widget.characterId, msg);
|
||||
_scrollToBottom();
|
||||
},
|
||||
);
|
||||
|
||||
setState(() => _isVoiceMode = true);
|
||||
}
|
||||
|
||||
void _exitVoiceMode() {
|
||||
_voiceController?.dispose();
|
||||
_voiceController = null;
|
||||
setState(() => _isVoiceMode = false);
|
||||
}
|
||||
|
||||
Future<void> _sendMessage() async {
|
||||
if (_controller.text.trim().isEmpty || _character == null || _isLoading) return;
|
||||
|
||||
@@ -273,10 +309,11 @@ class _InteractionScreenState extends ConsumerState<InteractionScreen> {
|
||||
),
|
||||
|
||||
|
||||
if (_isVoiceMode && _character != null)
|
||||
if (_isVoiceMode && _character != null && _voiceController != null)
|
||||
VoiceModeOverlay(
|
||||
character: _character!,
|
||||
onClose: () => setState(() => _isVoiceMode = false),
|
||||
controller: _voiceController!,
|
||||
onClose: _exitVoiceMode,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -405,10 +442,7 @@ class _InteractionScreenState extends ConsumerState<InteractionScreen> {
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
setState(() => _isVoiceMode = true);
|
||||
},
|
||||
onTap: _enterVoiceMode,
|
||||
child: Container(
|
||||
width: 44,
|
||||
height: 44,
|
||||
|
||||
Reference in New Issue
Block a user