Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨Feat: 대본학습페이지 통신, 분석페이지 연동 및 수정 #35

Merged
merged 5 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,5 @@ flutter {
}

dependencies {}

apply plugin: 'com.google.gms.google-services'
43 changes: 23 additions & 20 deletions lib/viewModels/script/analyze_viewmodel.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import 'package:flutter/foundation.dart';

import 'package:flutter_sound/flutter_sound.dart';
import 'package:http/http.dart' as http;
import 'dart:convert'; // JSON 데이터를 다루기 위해 필요
class AnalyzeViewModel with ChangeNotifier {
List<String> userWord = [];
List<String> userSenten = [];
List<int> wrongWordIndexes = [];
List<double> wrongFastIndexes = [];

final List<String> userWord = [
"가", "나", "다", "어쩌구", "저쩌구", "입니다", "나는", "매일", "조깅을", "합니다",
"플러터로", "앱", "개발을", "배우고", "있어요", "이것은", "더미", "텍스트입니다",
"데이터를", "시각화하는", "것은", "중요합니다"
];
final List<String> userSenten = [
"가 나 다 어쩌구 저쩌구 입니다.",
"나는 매일 조깅을 합니다.",
"플러터로 앱 개발을 배우고 있어요.",
"이것은 더미 텍스트입니다.",
"데이터를 시각화하는 것은 중요합니다.",
];
final List<int> wrongWordIndexes = [2, 14]; // "다", "앱"을 가리킴
final List<int> wrongFastIndexes = [1, 3]; // 두 번째와 네 번째 문장을 가리킴
void updateData(Map<String, dynamic> data) {
userWord = List<String>.from(data['user_word'] as List<dynamic>? ?? []);
userSenten = List<String>.from(data['user_sentence'] as List<dynamic>? ?? []);
wrongWordIndexes = List<int>.from(data['wrong'] as List<dynamic>? ?? []);
wrongFastIndexes = (data['speed'] as List<dynamic>? ?? []).map((e) {

// ViewModel 초기화
AnalyzeViewModel() {
// 필요한 초기화 로직 추가
if (e is double) {
return e;
} else if (e is int) {
return e.toDouble();
} else {
// 로그 출력 또는 오류 처리
print("Warning: Invalid type in 'speed' list, defaulting to 0.0");
return 0.0; // 기본값
}
}).toList();
notifyListeners(); // 데이터가 업데이트되면 리스너들에게 알립니다.
}

// 여기에 필요한 기능을 추가하세요.
}
38 changes: 25 additions & 13 deletions lib/viewModels/script/create_script_viewmodel.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:speech_to_text/speech_to_text.dart' as stt;
Expand All @@ -8,6 +10,8 @@ import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:earlips/views/script/analyze_screen.dart';
import 'package:earlips/viewModels/script/analyze_viewmodel.dart';


class CreateScriptViewModel extends ChangeNotifier {
bool isRecording = false;
Expand All @@ -28,6 +32,7 @@ class CreateScriptViewModel extends ChangeNotifier {
}

void _init() async {
Get.put(AnalyzeViewModel());
await requestPermission();
speechToText.initialize(
onError: (val) => print('Error: $val'),
Expand Down Expand Up @@ -73,33 +78,42 @@ class CreateScriptViewModel extends ChangeNotifier {


Future<void> sendTextAndAudio() async {
String url = 'https://heheds.free.beeceptor.com';
String url = 'https://962554f7-5348-4141-a3df-1a50c06b79b5-00-15gg2xcmiy7a0.sisko.replit.dev/upload';
String textToSend = writedTextController.text;
if (audioFilePath == null) {
if (audioFilePath.isEmpty) {
print('Audio file is not available.');
return;
}

try {
var request = http.MultipartRequest('POST', Uri.parse(url))
..fields['text'] = textToSend // 텍스트 데이터 추가
..files.add(await http.MultipartFile.fromPath(
'audio', // 서버에서 음성 파일을 식별하는 필드명
audioFilePath,
));
..fields['text'] = textToSend
..files.add(await http.MultipartFile.fromPath('audio', audioFilePath));

var response = await request.send();
if (response.statusCode == 200) {
print('Data and audio sent successfully');
final respStr = await response.stream.bytesToString();
final jsonResponse = json.decode(respStr);
print('Server response: $respStr');

if (jsonResponse != null && jsonResponse['data'] != null) {
final analyzeViewModel = Get.find<AnalyzeViewModel>();
analyzeViewModel.updateData(jsonResponse['data']);
Get.to(() => AnalyzeScreen()); // AnalyzeScreen으로 이동
} else {
print('Received null or invalid data from the server.');
}
} else {
print('Failed to send data and audio');
print('Failed to send data and audio. Status code: ${response.statusCode}');
}
} catch (e) {
print(e.toString());
}
}




void _handleStatus(String status) {
if (handDone) return;
if (status == 'done') {
Expand Down Expand Up @@ -149,11 +163,9 @@ class CreateScriptViewModel extends ChangeNotifier {
notifyListeners();
}

void complete() {
void complete() async {
print("완료버튼 눌렀습니다.");
sendTextAndAudio(); // 텍스트와 오디오 파일 전송
//스크린을 이동 analyze_screen으로 이동하는 코드
Get.to(() => AnalyzeScreen());
await sendTextAndAudio(); // 비동기 호출로 수정
}


Expand Down
84 changes: 50 additions & 34 deletions lib/views/script/analyze_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,21 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:earlips/viewModels/script/analyze_viewmodel.dart';
import '../../utilities/app_routes.dart';



class AnalyzeScreen extends StatefulWidget {
AnalyzeScreen({Key? key}) : super(key: key);
@override
_AnalyzeScreenState createState() => _AnalyzeScreenState();
}

class _AnalyzeScreenState extends State<AnalyzeScreen> {
late AnalyzeViewModel viewModel;

@override
void initState() {
super.initState();
viewModel = Get.put(AnalyzeViewModel()); // 여기서 viewModel을 등록
print(viewModel.userSenten);
}

@override
Widget build(BuildContext context) {
Expand All @@ -36,13 +43,13 @@ class _AnalyzeScreenState extends State<AnalyzeScreen> {
width: Get.width - 40,
height: Get.height * 0.2,
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(10.0), // 내부 여백을 추가합니다.
padding: EdgeInsets.all(10.0),
decoration: BoxDecoration(
color: Colors.white, // 배경색을 지정합니다.
borderRadius: BorderRadius.circular(15.0), // 테두리 둥글기를 지정합니다.
border: Border.all(color: Colors.white), // 테두리 색상을 지정합니다. 필요에 따라 변경 가능합니다.
color: Colors.white,
borderRadius: BorderRadius.circular(15.0),
border: Border.all(color: Colors.white),
),
child: _TopText(),
child: _TopText(), // 이 부분은 상태를 표시하지 않으므로 그대로 유지합니다.
),
Stack(
children: [
Expand All @@ -51,15 +58,14 @@ class _AnalyzeScreenState extends State<AnalyzeScreen> {
width: Get.width - 40,
height: Get.height * 0.5,
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(10.0), // 내부 여백을 추가합니다.
padding: EdgeInsets.all(10.0),
decoration: BoxDecoration(
color: Colors.white, // 배경색을 지정합니다.
borderRadius: BorderRadius.circular(15.0), // 테두리 둥글기를 지정합니다.
border: Border.all(color: Colors.white), // 테두리 색상을 지정합니다. 필요에 따라 변경 가능합니다.
color: Colors.white,
borderRadius: BorderRadius.circular(15.0),
border: Border.all(color: Colors.white),
),
child: TextStylingWidget(),
child: TextStylingWidget(viewModel: viewModel), // viewModel을 전달합니다.
),

],
),
],
Expand All @@ -68,13 +74,12 @@ class _AnalyzeScreenState extends State<AnalyzeScreen> {
floatingActionButton: Container(
width: Get.width,
alignment: Alignment.bottomCenter,

child: FloatingActionButton(
onPressed: () {
Get.toNamed(Routes.HOME);
},
child: Icon(Icons.home), // 홈 아이콘 사용
tooltip: '홈으로', // 롱 프레스 시 표시되는 텍스트
child: Icon(Icons.home),
tooltip: '홈으로',
),
),
),
Expand All @@ -83,7 +88,9 @@ class _AnalyzeScreenState extends State<AnalyzeScreen> {
}

class TextStylingWidget extends StatelessWidget {
final AnalyzeViewModel model = Get.put(AnalyzeViewModel());
final AnalyzeViewModel viewModel; // viewModel을 받기 위한 생성자 파라미터를 추가합니다.

TextStylingWidget({required this.viewModel}); // 생성자를 통해 viewModel을 초기화합니다.

@override
Widget build(BuildContext context) {
Expand All @@ -98,32 +105,46 @@ class TextStylingWidget extends StatelessWidget {
);
}


List<TextSpan> _buildTextSpans() {
List<TextSpan> spans = [];
int globalWordIndex = 0; // 전체 단어에 대한 인덱스를 추적합니다.
int globalWordIndex = 0;

for (int i = 0; i < model.userSenten.length; i++) {
final List<String> words = model.userSenten[i].split(' ');
for (int i = 0; i < viewModel.userSenten.length; i++) {
final List<String> words = viewModel.userSenten[i].split(' ');
List<TextSpan> wordSpans = [];

for (String word in words) {
final bool isWrongWord = model.wrongWordIndexes.contains(globalWordIndex);
final bool isWrongWord = viewModel.wrongWordIndexes.contains(globalWordIndex);
wordSpans.add(TextSpan(
text: "$word ",
style: TextStyle(
color: isWrongWord ? Colors.red : Colors.black,
),
));
globalWordIndex++; // 각 단어를 처리할 때마다 전체 단어 인덱스를 증가시킵니다.
globalWordIndex++;
}

// `wrongFastIndexes`의 값에 따라 밑줄 색상을 결정합니다.
Color underlineColor = Colors.white; // 기본값은 투명색입니다.
if (viewModel.wrongFastIndexes[i] < 1) {
underlineColor = Colors.purple; // 1미만인 경우 보라색 밑줄
} else if (viewModel.wrongFastIndexes[i] > 1) {
underlineColor = Colors.red; // 1초과인 경우 빨간색 밑줄
}

spans.add(TextSpan(
children: wordSpans,
style: TextStyle(
decoration: model.wrongFastIndexes.contains(i) ? TextDecoration.underline : TextDecoration.none,
decoration: viewModel.wrongFastIndexes[i] != 0 ? TextDecoration.underline : TextDecoration.none,
decorationColor: underlineColor, // 밑줄 색상을 지정합니다.
decorationStyle: TextDecorationStyle.solid,
decorationThickness: 3.0,
//밑줄을 밑으로 내리기 위한 값

),
));
spans.add(TextSpan(text: "\n")); // 문장 사이에 줄바꿈 추가
spans.add(TextSpan(text: "\n"));
}

return spans;
Expand Down Expand Up @@ -166,21 +187,16 @@ class _TopText extends StatelessWidget {
text: TextSpan(
style: TextStyle(fontSize: 16, color: Colors.black),
children: <TextSpan>[
TextSpan(text: '문장의 빠르기가 빠르거나 느리면 밑줄이 표시됩니다. ex)'),
TextSpan(text: '문장이 빠르면 빨강, 느리면 보라색 밑줄로 표시됩니다.'),
// 예시에 적용할 스타일
TextSpan(
text: '강아지는 ',
style: TextStyle(decoration: TextDecoration.underline),
),
TextSpan(
text: '뛴다',
style: TextStyle(decoration: TextDecoration.underline),
),
//들여쓰기
],
),
),
],
),
);
}
}

}

Loading