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: 음소 교정 연동 및 구현 #27

Merged
merged 6 commits into from
Feb 18, 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
21 changes: 21 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,13 @@ PODS:
- nanopb (< 2.30910.0, >= 2.30908.0)
- FirebaseSharedSwift (10.21.0)
- Flutter (1.0.0)
- flutter_inappwebview (0.0.1):
- Flutter
- flutter_inappwebview/Core (= 0.0.1)
- OrderedSet (~> 5.0)
- flutter_inappwebview/Core (0.0.1):
- Flutter
- OrderedSet (~> 5.0)
- flutter_localization (0.0.1):
- Flutter
- flutter_native_splash (0.0.1):
Expand Down Expand Up @@ -813,6 +820,7 @@ PODS:
- nanopb/encode (= 2.30909.1)
- nanopb/decode (2.30909.1)
- nanopb/encode (2.30909.1)
- OrderedSet (5.0.0)
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
Expand All @@ -827,13 +835,17 @@ PODS:
- Flutter
- Try
- Try (2.1.1)
- video_player_avfoundation (0.0.1):
- Flutter
- FlutterMacOS

DEPENDENCIES:
- cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`)
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_database (from `.symlinks/plugins/firebase_database/ios`)
- Flutter (from `Flutter`)
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
- flutter_localization (from `.symlinks/plugins/flutter_localization/ios`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
Expand All @@ -843,6 +855,7 @@ DEPENDENCIES:
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- speech_to_text (from `.symlinks/plugins/speech_to_text/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)

SPEC REPOS:
trunk:
Expand All @@ -868,6 +881,7 @@ SPEC REPOS:
- GTMSessionFetcher
- leveldb-library
- nanopb
- OrderedSet
- PromisesObjC
- RecaptchaInterop
- Try
Expand All @@ -883,6 +897,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/firebase_database/ios"
Flutter:
:path: Flutter
flutter_inappwebview:
:path: ".symlinks/plugins/flutter_inappwebview/ios"
flutter_localization:
:path: ".symlinks/plugins/flutter_localization/ios"
flutter_native_splash:
Expand All @@ -901,6 +917,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
speech_to_text:
:path: ".symlinks/plugins/speech_to_text/ios"
video_player_avfoundation:
:path: ".symlinks/plugins/video_player_avfoundation/darwin"

SPEC CHECKSUMS:
abseil: 926fb7a82dc6d2b8e1f2ed7f3a718bce691d1e46
Expand All @@ -921,6 +939,7 @@ SPEC CHECKSUMS:
FirebaseFirestoreInternal: 7ac1e0c5b4e75aeb898dfe4b1d6d77abbac9eca3
FirebaseSharedSwift: 19b3f709993d6fa1d84941d41c01e3c4c11eab93
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_inappwebview: 3d32228f1304635e7c028b0d4252937730bbc6cf
flutter_localization: f43b18844a2b3d2c71fd64f04ffd6b1e64dd54d4
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
Expand All @@ -935,13 +954,15 @@ SPEC CHECKSUMS:
GTMSessionFetcher: 8a1b34ad97ebe6f909fb8b9b77fba99943007556
leveldb-library: e74c27d8fbd22854db7cb467968a0b8aa1db7126
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
speech_to_text: b43a7d99aef037bd758ed8e45d79bbac035d2dfe
Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96
video_player_avfoundation: 02011213dab73ae3687df27ce441fbbcc82b5579

PODFILE CHECKSUM: 0b2c97823421f8b156b8e4753a469ac167670df8

Expand Down
Empty file removed lib/models/temp
Empty file.
27 changes: 27 additions & 0 deletions lib/models/user_word_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class UserWord {
final int wordId;
final bool isDone;
final String? doneDate;

UserWord({
required this.wordId,
required this.isDone,
this.doneDate,
});

Map<String, dynamic> toMap() {
return {
'wordId': wordId,
'isDone': isDone,
'doneDate': doneDate,
};
}

factory UserWord.fromDocument(Map<String, dynamic> doc) {
return UserWord(
wordId: doc['wordId'],
isDone: doc['isDone'],
doneDate: doc['doneDate'],
);
}
}
47 changes: 47 additions & 0 deletions lib/models/word_card_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class WordCard {
final int id;
final String word;
final String speaker;
final String video;

WordCard({
required this.id,
required this.word,
required this.speaker,
required this.video,
});

Map<String, dynamic> toMap() {
return {
'id': id,
'word': word,
'speaker': speaker,
'video': video,
};
}

factory WordCard.fromDocument(Map<String, dynamic> doc) {
return WordCard(
id: doc['id'],
word: doc['word'],
speaker: doc['speaker'],
video: doc['video'],
);
}

WordCard copyWith({
int? id,
String? word,
String? speaker,
bool? isDone,
String? doneDate,
String? video,
}) {
return WordCard(
id: id ?? this.id,
word: word ?? this.word,
speaker: speaker ?? this.speaker,
video: video ?? this.video,
);
}
}
12 changes: 12 additions & 0 deletions lib/models/word_data_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:earlips/models/user_word_model.dart';
import 'package:earlips/models/word_card_model.dart';

class WordData {
final WordCard wordCard;
final UserWord? userWord;

WordData({
required this.wordCard,
this.userWord,
});
}
1 change: 1 addition & 0 deletions lib/services/auth/auth_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class AuthService {

// 사용자 데이터
final userData = {
'uid': userCredential.user!.uid,
'systemLanguage': 'kr',
'learningLanguage': 'kr',
'nickname': extractNickname(googleUser!.email), // @ 앞까지만 추출
Expand Down
3 changes: 1 addition & 2 deletions lib/viewModels/auth/email_signup_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:earlips/utilities/validators/auth_validators.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:get/get.dart';

class EmailSignupViewModel extends GetxController {
final formKey = GlobalKey<FormState>();
final emailController = TextEditingController();
final passwordController = TextEditingController();
final FlutterSecureStorage _storage = const FlutterSecureStorage();

// Email Validator
String? emailValidator(String? value) {
Expand Down Expand Up @@ -44,6 +42,7 @@ class EmailSignupViewModel extends GetxController {

// 사용자 데이터
final userData = {
'uid': userCredential.user!.uid,
'systemLanguage': 'kr',
'learningLanguage': 'kr',
'nickname': extractNickname(emailController.text.trim()),
Expand Down
43 changes: 43 additions & 0 deletions lib/viewModels/user/user_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,40 @@ class UserViewModel extends GetxController {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final storage = const FlutterSecureStorage(); // Instance for secure storage

// final List<WordCard> wordList = [
// WordCard(
// id: 1,
// word: "강",
// speaker: "가-앙",
// video: "https://www.youtube.com/watch?v=OzHrIz-wMLA"),
// WordCard(
// id: 2,
// word: "서",
// speaker: "가-앙",
// video: "https://www.youtube.com/watch?v=OzHrIz-wMLA"),
// WordCard(
// id: 3,
// word: "희",
// speaker: "가-앙",
// video: "https://www.youtube.com/watch?v=OzHrIz-wMLA"),
// WordCard(
// id: 4,
// word: "찬",
// speaker: "차-안",
// video: "https://www.youtube.com/watch?v=OzHrIz-wMLA"),
// WordCard(
// id: 5,
// word: "캬",
// speaker: "캬",
// video: "https://www.youtube.com/watch?v=OzHrIz-wMLA"),
// ];

// for (final word in wordList) {
// await FirebaseFirestore.instance
// .collection('words')
// .doc(word.id.toString())
// .set(word.toMap());
// }
// User Profile Data
final Rx<User?> _firebaseUser = Rx<User?>(null);
String? get uid => _firebaseUser.value?.uid;
Expand All @@ -31,6 +65,15 @@ class UserViewModel extends GetxController {

Future<void> getUserData() async {
if (uid != null) {
// // users 컬렉션의 하위 컬렉션에 단어 완료 정보 삽입
// for (final word in wordList) {
// await FirebaseFirestore.instance
// .collection('users')
// .doc(uid)
// .collection('words')
// .doc(word.id.toString())
// .set(UserWord(wordId: word.id, isDone: false).toMap());
// }
final doc = await _firestore.collection('users').doc(uid).get();
userData.value = doc.data() ?? {};
nickname.value = userData.value['nickname'] ?? '';
Expand Down
94 changes: 94 additions & 0 deletions lib/viewModels/word/word_viewmodel.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:earlips/models/user_word_model.dart';
import 'package:earlips/models/word_card_model.dart';
import 'package:earlips/models/word_data_model.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';

class WordViewModel extends GetxController {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final FirebaseAuth _auth = FirebaseAuth.instance;

RxList<WordData> wordList = RxList<WordData>([]);
RxInt currentIndex = 0.obs;

@override
void onInit() {
super.onInit();
fetchWords();
fetchWords();
wordList.refresh();
}

void updateCurrentIndex(int index) {
currentIndex.value = index;
}

// 단어 데이터 가져오기
Future<void> fetchWords() async {
final uid = _auth.currentUser?.uid;
if (uid != null) {
// 모든 단어 데이터 가져오기
final wordsQuery = await _firestore.collection('words').get();
final allWords = wordsQuery.docs
.map((doc) => WordCard.fromDocument(doc.data()))
.toList();

// 현재 사용자의 단어 데이터 가져오기
final userWordsQuery = await _firestore
.collection('users')
.doc(uid)
.collection('words')
.get();
final userWords = userWordsQuery.docs
.map((doc) => UserWord.fromDocument(doc.data()))
.toList();

// 모든 단어 데이터에 사용자의 단어 데이터를 추가
wordList.value = allWords.map((word) {
final matchingUserWord = userWords
.firstWhereOrNull((userWord) => userWord.wordId == word.id);

return WordData(
wordCard: word,
userWord: matchingUserWord,
);
}).toList();
update();
}
}

// 단어 완료 처리
Future<void> markWordAsDone(WordCard word) async {
final uid = _auth.currentUser?.uid;
if (uid != null) {
// Add or update data in the user's 'words' subcollection in Firestore
await _firestore
.collection('users')
.doc(uid)
.collection('words')
.doc(word.id.toString())
.set({
'wordId': word.id,
'isDone': true,
'doneDate': DateFormat('yyyy/MM/dd').format(DateTime.now()),
});

final index =
wordList.indexWhere((element) => element.wordCard.id == word.id);
if (index != -1) {
// Handle the scenario where we don't find the card locally.
wordList[index] = WordData(
wordCard: word,
userWord: UserWord(
wordId: word.id,
isDone: true,
doneDate: DateFormat('yyyy/MM/dd').format(DateTime.now()),
),
);
wordList.refresh();
}
}
}
}
Loading
Loading