From a1c3f5ad9bac355352726b89d00f850b109e1868 Mon Sep 17 00:00:00 2001 From: bunju20 Date: Tue, 9 Apr 2024 23:17:07 +0900 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20#53=20?= =?UTF-8?q?=EC=8B=A4=EC=8B=9C=EA=B0=84=20=EB=B0=9C=EC=9D=8C=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81,=20?= =?UTF-8?q?=EB=92=A4=EB=A1=9C=EA=B0=80=EA=B8=B0=20=ED=95=B4=EB=8F=84=20?= =?UTF-8?q?=EC=9E=91=EB=8F=99=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bindings/root_binding.dart | 3 + .../realtime/real_create_viewmodel.dart | 82 +++++++ lib/views/home/home_screen.dart | 2 +- lib/views/home/widget/mid_widget.dart | 2 +- .../realtime/real_create_script_screen.dart | 228 +++++------------- 5 files changed, 144 insertions(+), 173 deletions(-) create mode 100644 lib/viewModels/realtime/real_create_viewmodel.dart diff --git a/lib/bindings/root_binding.dart b/lib/bindings/root_binding.dart index c418df1..7468b6d 100644 --- a/lib/bindings/root_binding.dart +++ b/lib/bindings/root_binding.dart @@ -2,6 +2,7 @@ import 'package:get/get.dart'; import 'package:earlips/viewModels/home/home_viewmodel.dart'; import 'package:earlips/viewModels/root/root_viewmodel.dart'; import 'package:earlips/viewModels/study/study_viewmodel.dart'; +import 'package:earlips/viewModels/realtime/real_create_viewmodel.dart'; class RootBinding extends Bindings { @override @@ -12,5 +13,7 @@ class RootBinding extends Bindings { // ChildViewModel is singleton Get.put(HomeViewModel()); Get.put(StudyViewModel()); + Get.put(RealCreateViewModel()); + } } diff --git a/lib/viewModels/realtime/real_create_viewmodel.dart b/lib/viewModels/realtime/real_create_viewmodel.dart new file mode 100644 index 0000000..83a10bb --- /dev/null +++ b/lib/viewModels/realtime/real_create_viewmodel.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:speech_to_text/speech_to_text.dart' as stt; +import 'package:permission_handler/permission_handler.dart'; + +class RealCreateViewModel extends GetxController { + final speechToText = stt.SpeechToText(); + var isRecording = false.obs; + var handDone = false.obs; // 추가 + var text = ''.obs; + + @override + void onInit() { + super.onInit(); + requestPermission(); + } + + void toggleRecording() { + print("녹음 버튼 클릭" ); + if (isRecording.value) { + print("이제 끌게용"); + handDone.value = true; + stopListening(); + } else { + print("이제 시작할게용"); + handDone.value = false; + isRecording.value = true; + startListening(); + } + } + void startListening() async { + bool available = await speechToText.initialize(onStatus: handleStatus); + if (available) { + speechToText.listen(onResult: (result) { + if (result.finalResult) { + // 기존 텍스트에 이어서 새로 인식된 텍스트를 추가합니다. + text.value += "${result.recognizedWords} "; + } + }, + listenFor: const Duration(minutes: 5), + pauseFor: const Duration(seconds: 3), + ); + isRecording.value = true; + } + } + + void stopListening() { + speechToText.stop(); + isRecording.value = false; + } + + void handleStatus(String status) { + print("현재 상태: $status"); + print("handDone: $handDone"); + print("isRecording: $isRecording"); + if (handDone.value) { + return; + } + if (status == 'done') { + stopListening(); + Future.delayed(Duration(milliseconds: 100), () { + startListening(); + }); + if (status == 'notListening') { + startListening(); + } + } + } + + Future requestPermission() async { + var status = await Permission.microphone.status; + if (!status.isGranted) { + await Permission.microphone.request(); + } + } + + @override + void onClose() { + speechToText.stop(); + super.onClose(); + } +} diff --git a/lib/views/home/home_screen.dart b/lib/views/home/home_screen.dart index 405b64b..7f509ca 100644 --- a/lib/views/home/home_screen.dart +++ b/lib/views/home/home_screen.dart @@ -37,7 +37,7 @@ class HomeScreen extends BaseScreen { isLoggedIn: isLoggedIn, vm: viewModel, ), - const MidWidget(), + MidWidget(), // 로그인 상태에 따라 _Bottom 클래스의 컨테이너 색상을 변경 BottomWidget(isLoggedIn: isLoggedIn), ], diff --git a/lib/views/home/widget/mid_widget.dart b/lib/views/home/widget/mid_widget.dart index 891e2a9..8e90efd 100644 --- a/lib/views/home/widget/mid_widget.dart +++ b/lib/views/home/widget/mid_widget.dart @@ -54,7 +54,7 @@ class MidWidget extends StatelessWidget { InkWell( onTap: () { Get.to(() => - RealCreateScriptPage()); // Adjust the screen name as necessary + RealCreateScriptPage(),preventDuplicates: false); // Adjust the screen name as necessary }, child: Container( margin: const EdgeInsets.only(left: 20.0), diff --git a/lib/views/realtime/real_create_script_screen.dart b/lib/views/realtime/real_create_script_screen.dart index 6281071..7222c28 100644 --- a/lib/views/realtime/real_create_script_screen.dart +++ b/lib/views/realtime/real_create_script_screen.dart @@ -1,189 +1,75 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; -import 'package:speech_to_text/speech_to_text.dart' as stt; -import 'package:permission_handler/permission_handler.dart'; -import 'package:get/get_utils/src/extensions/internacionalization.dart'; - -class RealCreateScriptPage extends StatefulWidget { - const RealCreateScriptPage({super.key}); - - @override - _RealCreateScriptPageState createState() => _RealCreateScriptPageState(); -} +import 'package:get/get.dart'; +import 'package:earlips/viewModels/realtime/real_create_viewmodel.dart'; +import 'package:earlips/views/base/base_screen.dart'; -class _RealCreateScriptPageState extends State { - bool isRecording = false; - bool handDone = false; - TextEditingController textEditingController = TextEditingController(); - stt.SpeechToText speechToText = stt.SpeechToText(); - - @override - void initState() { - super.initState(); - requestPermission(); - speechToText.initialize( - onStatus: (status) { - handleStatus(status); // 상태 처리를 위한 함수 호출 - }, - ); - } - void handleStatus(String status) { - if (handDone) { - return; - } - if (status == 'done') { - stopListening(); - // 잠시 후 다시 시작하기 위해 delay를 사용 - Future.delayed(Duration(milliseconds: 100), () { - startListening(); - }); - if (status == 'notListening') { - startListening(); - } - } - // 필요한 경우 여기에 다른 상태에 대한 처리를 추가할 수 있습니다. - } +class RealCreateScriptPage extends BaseScreen { + const RealCreateScriptPage({Key? key}) : super(key: key); @override - @override - void dispose() { - // SpeechToText 리스닝을 멈춥니다. - speechToText.stop(); - - // SpeechToText 리소스를 정리합니다. - speechToText.cancel(); - // 텍스트 컨트롤러를 정리합니다. - textEditingController.dispose(); - - super.dispose(); - } - - Future requestPermission() async { - var microphoneStatus = await Permission.microphone.status; - if (!microphoneStatus.isGranted) { - await Permission.microphone.request(); - } - } - - void toggleRecording() { - if (isRecording) { - //완전히 끝내겠다고 설정하는 부분. - handDone = true; - stopListening(); - } else { - handDone = false; - startListening(); - } - } + Widget buildBody(BuildContext context) { + final RealCreateViewModel speechController = Get.put(RealCreateViewModel()); - Future startListening() async { - bool available = await speechToText.initialize(onStatus: (status) { - handleStatus(status); - }); - - if (!available) { - return; - } - speechToText.listen( - onResult: (result) { - if (mounted) { - setState(() { - if (result.finalResult) { - // 기존 텍스트에 이어서 새로 인식된 텍스트를 추가합니다. - textEditingController.text += "${result.recognizedWords} "; - } - }); - } - }, - listenFor: const Duration(minutes: 5), - pauseFor: const Duration(seconds: 3), - ); - if (mounted) { - setState(() => isRecording = true); - } - } - - Future stopListening() async { - bool available = await speechToText.initialize(onStatus: (status) { - handleStatus(status); - }); - speechToText.stop(); - if (mounted) { - setState(() => isRecording = false); - } - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - FocusScope.of(context).requestFocus(FocusNode()); - }, - child: Scaffold( - appBar: AppBar( - title: Text('live_script_title'.tr), - centerTitle: true, - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () { - // 뒤로 가기 버튼을 눌렀을 때 텍스트 필드를 초기화합니다. - textEditingController.text = ""; - Navigator.of(context).pop(); - handDone = false; - }, - ), + return Scaffold( + appBar: AppBar( + title: Text('Live Script Title'), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Get.back(), ), - body: Stack( - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(25, 20, 25, 100), - child: TextField( - controller: textEditingController, - expands: true, - maxLines: null, - decoration: InputDecoration( - hintText: 'voice_recognition'.tr, - fillColor: Colors.white, - filled: true, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(15.0), - borderSide: BorderSide.none, - ), + ), + body: Stack( + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(25, 20, 25, 100), + child: Obx(() => TextField( + controller: TextEditingController(text: speechController.text.value), + expands: true, + maxLines: null, + decoration: InputDecoration( + hintText: 'Voice Recognition', + fillColor: Colors.white, + filled: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(15.0), + borderSide: BorderSide.none, ), - textAlignVertical: TextAlignVertical.top, ), - ), - Positioned( - bottom: 20, - left: 0, - right: 0, - child: Align( - alignment: Alignment.bottomCenter, - child: Ink( - decoration: BoxDecoration( - color: isRecording ? Colors.red : Colors.blue, - borderRadius: BorderRadius.circular(40), - ), - child: InkWell( - borderRadius: BorderRadius.circular(40), - onTap: toggleRecording, - child: Padding( - padding: const EdgeInsets.all(20), - child: Icon( - isRecording ? Icons.stop : Icons.mic, - size: 30, - color: Colors.white, - ), + textAlignVertical: TextAlignVertical.top, + )), + ), + Positioned( + bottom: 20, + left: 0, + right: 0, + child: Align( + alignment: Alignment.bottomCenter, + child: Obx(() => Ink( + decoration: BoxDecoration( + color: speechController.isRecording.value ? Colors.red : Colors.blue, + borderRadius: BorderRadius.circular(40), + ), + child: InkWell( + borderRadius: BorderRadius.circular(40), + onTap: () => speechController.toggleRecording(), + child: Padding( + padding: const EdgeInsets.all(20), + child: Icon( + speechController.isRecording.value ? Icons.stop : Icons.mic, + size: 30, + color: Colors.white, ), ), ), ), + ), ), - ], - ), + ), + ], ), ); } + }