From ef35b74bc9cbced21fa3103404ac3adc475599a3 Mon Sep 17 00:00:00 2001 From: kangyuri1114 Date: Thu, 1 Aug 2024 20:46:41 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[feat]:=20UI=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pm/progress/ProgressMeetingFragment.kt | 9 + .../progress/StartProgressMeetingFragment.kt | 166 +++--- .../src/main/res/drawable/progress_bar.xml | 24 + .../fragment_start_progress_meeting.xml | 476 ++++++++++++++---- .../projects/src/main/res/values/strings.xml | 12 +- 5 files changed, 519 insertions(+), 168 deletions(-) create mode 100644 feature/projects/src/main/res/drawable/progress_bar.xml diff --git a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/ProgressMeetingFragment.kt b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/ProgressMeetingFragment.kt index bb630ad..97f0594 100644 --- a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/ProgressMeetingFragment.kt +++ b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/ProgressMeetingFragment.kt @@ -10,6 +10,7 @@ import com.zucchini.ai_members.pm.AiPmViewModel import com.zucchini.domain.model.ai.ProgressMeetingInfo import com.zucchini.domain.model.ai.SetProgressMeeting import com.zucchini.feature.projects.databinding.FragmentProgressMeetingBinding +import com.zucchini.view.hideKeyboard class ProgressMeetingFragment : Fragment() { private var _binding: FragmentProgressMeetingBinding? = null @@ -23,6 +24,7 @@ class ProgressMeetingFragment : Fragment() { savedInstanceState: Bundle?, ): View { _binding = FragmentProgressMeetingBinding.inflate(inflater, container, false) + clickHideKeyboard() return binding.root } @@ -49,6 +51,7 @@ class ProgressMeetingFragment : Fragment() { val meetingTimeInt = if (meetingTime.isEmpty()) 0 else meetingTime.toInt() val participantsInt = if (participants.isEmpty()) 0 else participants.toInt() + val progressMeetingCheckbox = ProgressMeetingInfo( introduceMyself = binding.cbAiPmMeetingProgressIntroduceMyself.isChecked, @@ -69,5 +72,11 @@ class ProgressMeetingFragment : Fragment() { viewModel.updateProgressMeetingCheckbox(setProgressMeetingInfo, progressMeetingCheckbox) } + private fun clickHideKeyboard() { + binding.root.setOnClickListener { + hideKeyboard() + } + } + private fun minuteToMs(minute: Int) = minute * 60000 } diff --git a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt index e60d0af..5c93e71 100644 --- a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt +++ b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt @@ -5,6 +5,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.flowWithLifecycle @@ -21,15 +22,12 @@ class StartProgressMeetingFragment : Fragment() { private val viewModel: AiPmViewModel by activityViewModels() - private var meetingTotalTime = 0 - private var introduce = 0 - private var iceBreaking = 0 - private var brainstorming = 0 - private var topicSelection = 0 - private var sharing = 0 - private var roleDivision = 0 - private var troubleShooting = 0 - private var feedback = 0 + private val meetingList = emptyList() + + data class StartMeeting( + val progressName:String, + val progressTime:Int, + ) override fun onCreateView( inflater: LayoutInflater, @@ -38,66 +36,110 @@ class StartProgressMeetingFragment : Fragment() { ): View { _binding = FragmentStartProgressMeetingBinding.inflate(inflater, container, false) - collectProgressMinutes() - setMeetingIndex() + collectProgressMeetingInfo() + clickStartMeetingProgress() return binding.root } - private fun setMeetingIndex() { - val formattedText = getString( - R.string.tv_meeting_progress, - msToMinuteToString(meetingTotalTime), - msToMinuteToString(introduce), - msToMinuteToString(iceBreaking), - msToMinuteToString(brainstorming), - msToMinuteToString(topicSelection), - msToMinuteToString(sharing), - msToMinuteToString(roleDivision), - msToMinuteToString(troubleShooting), - msToMinuteToString(feedback), - ) - binding.tvMeetingProgress.text = formattedText + private fun collectProgressMeetingInfo() { + viewModel.progressMeetingResultData.flowWithLifecycle(viewLifecycleOwner.lifecycle) + .onEach { + + Log.d("ProgressMeetingFragment", "collectProgressMeetingInfo: $it") + + binding.tvTotalTimeMinute.text = + getString(R.string.minute, msToMinuteToString(viewModel.meetingTotalTime.value)) + + if (it?.introduceMyself!! < 0) { + binding.tvIntroduceMinute.isVisible = false + binding.tvIntroduceTime.isVisible = false + } else { + binding.tvIntroduceMinute.isVisible = true + binding.tvIntroduceTime.isVisible = true + binding.tvIntroduceMinute.text = + getString(R.string.minute, msToMinuteToString(it?.introduceMyself)) + } + + if (it?.iceBreaking!! < 0) { + binding.tvIcebreakingMinute.isVisible = false + binding.tvIcebreakingTime.isVisible = false + } else { + binding.tvIcebreakingMinute.isVisible = true + binding.tvIcebreakingTime.isVisible = true + binding.tvIcebreakingMinute.text = + getString(R.string.minute, msToMinuteToString(it?.iceBreaking)) + } + + if (it?.brainstorming!! < 0) { + binding.tvBrainstormingMinute.isVisible = false + binding.tvBrainstormingTime.isVisible = false + } else { + binding.tvBrainstormingMinute.isVisible = true + binding.tvBrainstormingTime.isVisible = true + binding.tvBrainstormingMinute.text = + getString(R.string.minute, msToMinuteToString(it?.brainstorming)) + } + + if (it?.topicSelection!! < 0) { + binding.tvTopicMinute.isVisible = false + binding.tvTopicTime.isVisible = false + } else { + binding.tvTopicMinute.isVisible = true + binding.tvTopicTime.isVisible = true + binding.tvTopicMinute.text = + getString(R.string.minute, msToMinuteToString(it?.topicSelection)) + } + + if (it?.progressSharing!! < 0) { + binding.tvCurrentProgressMinute.isVisible = false + binding.tvCurrentProgressTime.isVisible = false + } else { + binding.tvCurrentProgressMinute.isVisible = true + binding.tvCurrentProgressTime.isVisible = true + binding.tvCurrentProgressMinute.text = + getString(R.string.minute, msToMinuteToString(it?.progressSharing)) + } + + if (it?.roleDivision!! < 0) { + binding.tvRoleMinute.isVisible = false + binding.tvRoleTime.isVisible = false + } else { + binding.tvRoleMinute.isVisible = true + binding.tvRoleTime.isVisible = true + binding.tvRoleMinute.text = + getString(R.string.minute, msToMinuteToString(it?.roleDivision)) + } + + if (it?.troubleShooting!! < 0) { + binding.tvTroubleShootingMinute.isVisible = false + binding.tvTroubleShootingTime.isVisible = false + } else { + binding.tvTroubleShootingMinute.isVisible = true + binding.tvTroubleShootingTime.isVisible = true + binding.tvTroubleShootingMinute.text = + getString(R.string.minute, msToMinuteToString(it?.troubleShooting)) + } + + if (it?.feedback !!< 0) { + binding.tvFeedbackMinute.isVisible = false + binding.tvFeedbackTime.isVisible = false + } else { + binding.tvFeedbackMinute.isVisible = true + binding.tvFeedbackTime.isVisible = true + binding.tvFeedbackMinute.text = + getString(R.string.minute, msToMinuteToString(it?.feedback)) + } + }.launchIn(viewLifecycleOwner.lifecycleScope) } - private fun collectProgressMinutes() { - viewModel.progressIntroduce.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - introduce = it - }.launchIn(viewLifecycleOwner.lifecycleScope) - - viewModel.progressIceBreaking.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - iceBreaking = it - }.launchIn(viewLifecycleOwner.lifecycleScope) - - viewModel.progressBrainstorming.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - brainstorming = it - }.launchIn(viewLifecycleOwner.lifecycleScope) - - viewModel.progressTopicSelection.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - topicSelection = it - }.launchIn(viewLifecycleOwner.lifecycleScope) + private fun msToMinuteToString(ms: Int?): String = (ms?.div(60000)).toString() - viewModel.progressSharing.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - sharing = it - }.launchIn(viewLifecycleOwner.lifecycleScope) + private fun clickStartMeetingProgress() { + binding.tvStartMeeting.setOnClickListener { - viewModel.progressRoleDivision.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - roleDivision = it - }.launchIn(viewLifecycleOwner.lifecycleScope) - - viewModel.progressTroubleShooting.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - troubleShooting = it - }.launchIn(viewLifecycleOwner.lifecycleScope) - - viewModel.progressFeedback.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - feedback = it - }.launchIn(viewLifecycleOwner.lifecycleScope) - - viewModel.meetingTotalTime.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - Log.d("StartProgressMeetingFragment", "meetingTotalTime: $it") - meetingTotalTime = it - }.launchIn(viewLifecycleOwner.lifecycleScope) + // 타이머 시작 + // 프로그레스바 set + } } - - private fun msToMinuteToString(ms: Int): String = (ms / 60000).toString() } diff --git a/feature/projects/src/main/res/drawable/progress_bar.xml b/feature/projects/src/main/res/drawable/progress_bar.xml new file mode 100644 index 0000000..9e2bbe0 --- /dev/null +++ b/feature/projects/src/main/res/drawable/progress_bar.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml b/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml index 0aece2e..d757e6b 100644 --- a/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml +++ b/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml @@ -1,106 +1,372 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file + xmlns:tools="http://schemas.android.com/tools" + android:layout_height="match_parent" + android:fillViewport="true" + android:layout_width="match_parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/feature/projects/src/main/res/values/strings.xml b/feature/projects/src/main/res/values/strings.xml index 024375c..24d6553 100644 --- a/feature/projects/src/main/res/values/strings.xml +++ b/feature/projects/src/main/res/values/strings.xml @@ -94,7 +94,6 @@ 오늘의 PM을 담당하게된 AI입니다!\n오늘의 회의는 아래와 같이 진행돼요.\n버튼을 클릭 시 제가 말하며 회의를 진행해요.\n각 회의 안건 별로 분배된 시간대로 타이머도 보여드릴게요. 오늘의 회의 목차 00:00 - 전체 회의 시간 : %s분\n팀원 자기소개 진행 : %s분\n아이스브레이킹 : %s분\n브레인스토밍 : %s분\n주제 선정 : %s분\n진행상황 공유 : %s분\n역할 분담 : %s분\n트러블 슈팅 : %s분\n현 프로젝트에 대한 피드백 : %s분 브랜딩 만들기 이미지 생성하기 프로젝트 브랜딩 정하기 @@ -170,4 +169,15 @@ 프로젝트 매니저(PM) AI 팀원은 회의록 요약과 회의 진행을 할 수 있어요. 디자이너 AI 팀원은 프로젝트의 브랜딩과 필요한 이미지 및 캐릭터들을 만들 수 있어요. 개발자 매칭 봇은 원하는 조건의 개발자 또는 프로젝트에 맞는 개발자를 추천해드립니다. + 회의 시작하기↗ + %s분 + - 전체 회의 시간 + - 자기소개 시간 + - 아이스브레이킹 진행 + - 브레인스토밍 진행 + - 주제 선정 + - 진행 상황 공유 + - 트러블 슈팅 + - 프로젝트에 대한 피드백 진행 + 완료! From d80d413b21503dd4f3e9de9d01dad969dc2f4197 Mon Sep 17 00:00:00 2001 From: kangyuri1114 Date: Thu, 1 Aug 2024 22:23:08 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[feat]:=20TTS=20=EC=84=B8=ED=8C=85=20?= =?UTF-8?q?=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=99=84=EB=A3=8C.?= =?UTF-8?q?=20=ED=83=80=EC=9D=B4=EB=A8=B8=20=EA=B5=AC=ED=98=84=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C(=EC=9E=98=EB=AA=BB=EB=90=9C=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=EA=B0=92=20=EB=B0=98=ED=99=98=20=EC=98=A4=EB=A5=98=20=EC=A4=91?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../progress/StartProgressMeetingFragment.kt | 238 ++++++++++++------ .../fragment_start_progress_meeting.xml | 8 +- .../projects/src/main/res/values/strings.xml | 3 +- 3 files changed, 164 insertions(+), 85 deletions(-) diff --git a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt index 5c93e71..20851f7 100644 --- a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt +++ b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt @@ -1,7 +1,8 @@ package com.zucchini.ai_members.pm.progress import android.os.Bundle -import android.util.Log +import android.os.CountDownTimer +import android.speech.tts.TextToSpeech import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -11,10 +12,14 @@ import androidx.fragment.app.activityViewModels import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import com.zucchini.ai_members.pm.AiPmViewModel +import com.zucchini.domain.model.ai.ProgressMeeting import com.zucchini.feature.projects.R import com.zucchini.feature.projects.databinding.FragmentStartProgressMeetingBinding +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch class StartProgressMeetingFragment : Fragment() { private var _binding: FragmentStartProgressMeetingBinding? = null @@ -22,11 +27,14 @@ class StartProgressMeetingFragment : Fragment() { private val viewModel: AiPmViewModel by activityViewModels() - private val meetingList = emptyList() + private val meetingList = mutableListOf() + var ttsObj: TextToSpeech? = null + data class StartMeeting( - val progressName:String, - val progressTime:Int, + val progressName: String, + val progressTime: Int, + val speaking: String = "", ) override fun onCreateView( @@ -38,108 +46,176 @@ class StartProgressMeetingFragment : Fragment() { collectProgressMeetingInfo() clickStartMeetingProgress() + setTTS() return binding.root } + private fun setTTS() { + ttsObj = TextToSpeech(requireContext(), TextToSpeech.OnInitListener { + if (it == TextToSpeech.SUCCESS) { + ttsObj?.language = java.util.Locale.KOREAN + } + }) + } + + private fun startSpeaking(speaking: String) { + ttsObj?.speak(speaking, TextToSpeech.QUEUE_FLUSH, null, null) + } private fun collectProgressMeetingInfo() { viewModel.progressMeetingResultData.flowWithLifecycle(viewLifecycleOwner.lifecycle) .onEach { + setMeetingIndex(it) + }.launchIn(viewLifecycleOwner.lifecycleScope) + } - Log.d("ProgressMeetingFragment", "collectProgressMeetingInfo: $it") + private fun setMeetingIndex(it: ProgressMeeting?) { + binding.tvTotalTimeMinute.text = + getString(R.string.minute, msToMinuteToString(viewModel.meetingTotalTime.value)) - binding.tvTotalTimeMinute.text = - getString(R.string.minute, msToMinuteToString(viewModel.meetingTotalTime.value)) + if (it?.introduceMyself!! < 0) { + binding.tvIntroduceMinute.isVisible = false + binding.tvIntroduceTime.isVisible = false + } else { + binding.tvIntroduceMinute.isVisible = true + binding.tvIntroduceTime.isVisible = true + binding.tvIntroduceMinute.text = + getString(R.string.minute, msToMinuteToString(it.introduceMyself)) - if (it?.introduceMyself!! < 0) { - binding.tvIntroduceMinute.isVisible = false - binding.tvIntroduceTime.isVisible = false - } else { - binding.tvIntroduceMinute.isVisible = true - binding.tvIntroduceTime.isVisible = true - binding.tvIntroduceMinute.text = - getString(R.string.minute, msToMinuteToString(it?.introduceMyself)) - } + meetingList.add(StartMeeting("introduceMyself", it.introduceMyself!!, "자기소개를 진행해주세요.")) + } - if (it?.iceBreaking!! < 0) { - binding.tvIcebreakingMinute.isVisible = false - binding.tvIcebreakingTime.isVisible = false - } else { - binding.tvIcebreakingMinute.isVisible = true - binding.tvIcebreakingTime.isVisible = true - binding.tvIcebreakingMinute.text = - getString(R.string.minute, msToMinuteToString(it?.iceBreaking)) - } + if (it.iceBreaking!! < 0) { + binding.tvIcebreakingMinute.isVisible = false + binding.tvIcebreakingTime.isVisible = false + } else { + binding.tvIcebreakingMinute.isVisible = true + binding.tvIcebreakingTime.isVisible = true + binding.tvIcebreakingMinute.text = + getString(R.string.minute, msToMinuteToString(it.iceBreaking)) + meetingList.add(StartMeeting("iceBreaking", it.iceBreaking!!)) + } - if (it?.brainstorming!! < 0) { - binding.tvBrainstormingMinute.isVisible = false - binding.tvBrainstormingTime.isVisible = false - } else { - binding.tvBrainstormingMinute.isVisible = true - binding.tvBrainstormingTime.isVisible = true - binding.tvBrainstormingMinute.text = - getString(R.string.minute, msToMinuteToString(it?.brainstorming)) - } + if (it.brainstorming!! < 0) { + binding.tvBrainstormingMinute.isVisible = false + binding.tvBrainstormingTime.isVisible = false + } else { + binding.tvBrainstormingMinute.isVisible = true + binding.tvBrainstormingTime.isVisible = true + binding.tvBrainstormingMinute.text = + getString(R.string.minute, msToMinuteToString(it.brainstorming)) + meetingList.add(StartMeeting("brainstorming", it.brainstorming!!)) + } - if (it?.topicSelection!! < 0) { - binding.tvTopicMinute.isVisible = false - binding.tvTopicTime.isVisible = false - } else { - binding.tvTopicMinute.isVisible = true - binding.tvTopicTime.isVisible = true - binding.tvTopicMinute.text = - getString(R.string.minute, msToMinuteToString(it?.topicSelection)) - } + if (it.topicSelection!! < 0) { + binding.tvTopicMinute.isVisible = false + binding.tvTopicTime.isVisible = false + } else { + binding.tvTopicMinute.isVisible = true + binding.tvTopicTime.isVisible = true + binding.tvTopicMinute.text = + getString(R.string.minute, msToMinuteToString(it.topicSelection)) + meetingList.add(StartMeeting("topicSelection", it.topicSelection!!)) + } - if (it?.progressSharing!! < 0) { - binding.tvCurrentProgressMinute.isVisible = false - binding.tvCurrentProgressTime.isVisible = false - } else { - binding.tvCurrentProgressMinute.isVisible = true - binding.tvCurrentProgressTime.isVisible = true - binding.tvCurrentProgressMinute.text = - getString(R.string.minute, msToMinuteToString(it?.progressSharing)) - } + if (it.progressSharing!! < 0) { + binding.tvCurrentProgressMinute.isVisible = false + binding.tvCurrentProgressTime.isVisible = false + } else { + binding.tvCurrentProgressMinute.isVisible = true + binding.tvCurrentProgressTime.isVisible = true + binding.tvCurrentProgressMinute.text = + getString(R.string.minute, msToMinuteToString(it.progressSharing)) + meetingList.add(StartMeeting("progressSharing", it.progressSharing!!)) + } - if (it?.roleDivision!! < 0) { - binding.tvRoleMinute.isVisible = false - binding.tvRoleTime.isVisible = false - } else { - binding.tvRoleMinute.isVisible = true - binding.tvRoleTime.isVisible = true - binding.tvRoleMinute.text = - getString(R.string.minute, msToMinuteToString(it?.roleDivision)) - } + if (it.roleDivision!! < 0) { + binding.tvRoleMinute.isVisible = false + binding.tvRoleTime.isVisible = false + } else { + binding.tvRoleMinute.isVisible = true + binding.tvRoleTime.isVisible = true + binding.tvRoleMinute.text = + getString(R.string.minute, msToMinuteToString(it.roleDivision)) + meetingList.add(StartMeeting("roleDivision", it.roleDivision!!)) + } - if (it?.troubleShooting!! < 0) { - binding.tvTroubleShootingMinute.isVisible = false - binding.tvTroubleShootingTime.isVisible = false - } else { - binding.tvTroubleShootingMinute.isVisible = true - binding.tvTroubleShootingTime.isVisible = true - binding.tvTroubleShootingMinute.text = - getString(R.string.minute, msToMinuteToString(it?.troubleShooting)) - } + if (it.troubleShooting!! < 0) { + binding.tvTroubleShootingMinute.isVisible = false + binding.tvTroubleShootingTime.isVisible = false + } else { + binding.tvTroubleShootingMinute.isVisible = true + binding.tvTroubleShootingTime.isVisible = true + binding.tvTroubleShootingMinute.text = + getString(R.string.minute, msToMinuteToString(it.troubleShooting)) + meetingList.add(StartMeeting("troubleShooting", it.troubleShooting!!)) + } - if (it?.feedback !!< 0) { - binding.tvFeedbackMinute.isVisible = false - binding.tvFeedbackTime.isVisible = false - } else { - binding.tvFeedbackMinute.isVisible = true - binding.tvFeedbackTime.isVisible = true - binding.tvFeedbackMinute.text = - getString(R.string.minute, msToMinuteToString(it?.feedback)) - } - }.launchIn(viewLifecycleOwner.lifecycleScope) + if (it.feedback!! < 0) { + binding.tvFeedbackMinute.isVisible = false + binding.tvFeedbackTime.isVisible = false + } else { + binding.tvFeedbackMinute.isVisible = true + binding.tvFeedbackTime.isVisible = true + binding.tvFeedbackMinute.text = + getString(R.string.minute, msToMinuteToString(it.feedback)) + meetingList.add(StartMeeting("feedback", it.feedback!!)) + } } private fun msToMinuteToString(ms: Int?): String = (ms?.div(60000)).toString() private fun clickStartMeetingProgress() { binding.tvStartMeeting.setOnClickListener { + if (meetingList.isNotEmpty()) { + startMeetingProgress(0) // 첫 번째 항목부터 시작 + } + } + } + + private fun startMeetingProgress(currentIndex: Int) { + if (currentIndex < meetingList.size) { + val currentMeeting = meetingList[currentIndex] + + startSpeaking(meetingList[currentIndex].speaking) + // 현재 회의 항목을 UI에 반영 + binding.tvCurrentMeetingProgress.text = currentMeeting.progressName + binding.pbTimer.max = currentMeeting.progressTime * 1000 // 밀리초 단위로 설정 + binding.pbTimer.progress = 0 // 타이머 시작 - // 프로그레스바 set + viewLifecycleOwner.lifecycleScope.launch { + for (timeRemaining in currentMeeting.progressTime downTo 0) { + if (!isActive) return@launch // 코루틴이 활성 상태인지 확인 + + binding.tvTimer.text = intToTimerString(timeRemaining * 1000) // 밀리초로 변환하여 전달 + binding.pbTimer.progress = (currentMeeting.progressTime - timeRemaining) * 1000 + delay(1000L) // 1초 대기 + } + + startMeetingProgress(currentIndex + 1) // 다음 항목으로 진행 + } + } else { + // 모든 항목이 끝난 후 완료 문구 표시 + binding.tvDone.isVisible = true + binding.tvTimer.text = getString(R.string._00_00) + binding.pbTimer.progress = binding.pbTimer.max + } + } + + private fun intToTimerString(totalTimeMs: Int): String { + val totalSeconds = totalTimeMs / 1000 + val minutes = totalSeconds / 60 + val seconds = totalSeconds % 60 + return String.format("%02d:%02d", minutes, seconds) + } + + override fun onDestroy() { + super.onDestroy() + if(ttsObj!=null){ + ttsObj?.stop() + ttsObj?.shutdown() + ttsObj = null } } } diff --git a/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml b/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml index d757e6b..b7d578c 100644 --- a/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml +++ b/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml @@ -11,8 +11,8 @@ 요약 결과 확인하기 회의록이 요약되지 않았습니다. 음성파일을 다시 업로드 해주세요. 프로젝트 매니저 AI - 오늘의 PM을 담당하게된 AI입니다!\n오늘의 회의는 아래와 같이 진행돼요.\n버튼을 클릭 시 제가 말하며 회의를 진행해요.\n각 회의 안건 별로 분배된 시간대로 타이머도 보여드릴게요. + 오늘의 PM을 담당하게된 AI입니다!\n오늘의 회의는 아래와 같이 진행 돼요.\n버튼을 클릭 시 제가 말하며 회의를 진행 해요. 오늘의 회의 목차 00:00 브랜딩 만들기 @@ -180,4 +180,5 @@ - 트러블 슈팅 - 프로젝트에 대한 피드백 진행 완료! + 00:00 From 357aa09868c7669f79e2a72fdb71dd437ae4adc7 Mon Sep 17 00:00:00 2001 From: kangyuri1114 Date: Tue, 6 Aug 2024 02:21:45 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[feat]:=20=ED=83=80=EC=9D=B4=EB=A8=B8=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95,=20=ED=9A=8C=EC=9D=98?= =?UTF-8?q?=20=EB=AA=A9=EC=B0=A8=EB=8C=80=EB=A1=9C=20TTS=20speak=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../progress/StartProgressMeetingFragment.kt | 132 +++++++++++++----- .../projects/src/main/res/values/strings.xml | 16 +++ 2 files changed, 115 insertions(+), 33 deletions(-) diff --git a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt index 20851f7..0e46520 100644 --- a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt +++ b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt @@ -1,7 +1,6 @@ package com.zucchini.ai_members.pm.progress import android.os.Bundle -import android.os.CountDownTimer import android.speech.tts.TextToSpeech import android.view.LayoutInflater import android.view.View @@ -62,6 +61,7 @@ class StartProgressMeetingFragment : Fragment() { private fun startSpeaking(speaking: String) { ttsObj?.speak(speaking, TextToSpeech.QUEUE_FLUSH, null, null) } + private fun collectProgressMeetingInfo() { viewModel.progressMeetingResultData.flowWithLifecycle(viewLifecycleOwner.lifecycle) .onEach { @@ -70,100 +70,165 @@ class StartProgressMeetingFragment : Fragment() { } private fun setMeetingIndex(it: ProgressMeeting?) { - binding.tvTotalTimeMinute.text = - getString(R.string.minute, msToMinuteToString(viewModel.meetingTotalTime.value)) + val totalTime = msToMinuteToString(viewModel.meetingTotalTime.value) + binding.tvTotalTimeMinute.text = totalTime if (it?.introduceMyself!! < 0) { binding.tvIntroduceMinute.isVisible = false binding.tvIntroduceTime.isVisible = false } else { + val introduceTime = msToMinuteToString(it.introduceMyself) + binding.tvIntroduceMinute.isVisible = true binding.tvIntroduceTime.isVisible = true - binding.tvIntroduceMinute.text = - getString(R.string.minute, msToMinuteToString(it.introduceMyself)) + binding.tvIntroduceMinute.text = introduceTime - meetingList.add(StartMeeting("introduceMyself", it.introduceMyself!!, "자기소개를 진행해주세요.")) + meetingList.add( + StartMeeting( + getString(R.string.introduceTitle), it.introduceMyself!!, + getString(R.string.speakIntroduce, introduceTime) + ) + ) } if (it.iceBreaking!! < 0) { binding.tvIcebreakingMinute.isVisible = false binding.tvIcebreakingTime.isVisible = false } else { + val iceBreakingTime = msToMinuteToString(it.iceBreaking) + binding.tvIcebreakingMinute.isVisible = true binding.tvIcebreakingTime.isVisible = true - binding.tvIcebreakingMinute.text = - getString(R.string.minute, msToMinuteToString(it.iceBreaking)) - meetingList.add(StartMeeting("iceBreaking", it.iceBreaking!!)) + binding.tvIcebreakingMinute.text = iceBreakingTime + + meetingList.add( + StartMeeting( + getString(R.string.iceBreakingTitle), + it.iceBreaking!!, + getString(R.string.speakIceBreaking, iceBreakingTime) + ) + ) } if (it.brainstorming!! < 0) { binding.tvBrainstormingMinute.isVisible = false binding.tvBrainstormingTime.isVisible = false } else { + val brainstormingTime = msToMinuteToString(it.brainstorming) + binding.tvBrainstormingMinute.isVisible = true binding.tvBrainstormingTime.isVisible = true - binding.tvBrainstormingMinute.text = - getString(R.string.minute, msToMinuteToString(it.brainstorming)) - meetingList.add(StartMeeting("brainstorming", it.brainstorming!!)) + binding.tvBrainstormingMinute.text = brainstormingTime + + meetingList.add( + StartMeeting( + getString(R.string.brainstormingTitle), + it.brainstorming!!, + getString(R.string.speakBrainstorming, brainstormingTime) + ) + ) } if (it.topicSelection!! < 0) { binding.tvTopicMinute.isVisible = false binding.tvTopicTime.isVisible = false } else { + val topicTime = msToMinuteToString(it.topicSelection) + binding.tvTopicMinute.isVisible = true binding.tvTopicTime.isVisible = true - binding.tvTopicMinute.text = - getString(R.string.minute, msToMinuteToString(it.topicSelection)) - meetingList.add(StartMeeting("topicSelection", it.topicSelection!!)) + binding.tvTopicMinute.text = topicTime + + meetingList.add( + StartMeeting( + getString(R.string.topicTitle), + it.topicSelection!!, + getString(R.string.speakTopic, topicTime) + ) + ) } if (it.progressSharing!! < 0) { binding.tvCurrentProgressMinute.isVisible = false binding.tvCurrentProgressTime.isVisible = false } else { + val progressSharingTime = msToMinuteToString(it.progressSharing) + binding.tvCurrentProgressMinute.isVisible = true binding.tvCurrentProgressTime.isVisible = true - binding.tvCurrentProgressMinute.text = - getString(R.string.minute, msToMinuteToString(it.progressSharing)) - meetingList.add(StartMeeting("progressSharing", it.progressSharing!!)) + binding.tvCurrentProgressMinute.text = progressSharingTime + + meetingList.add( + StartMeeting( + getString(R.string.currentProgressTitle), + it.progressSharing!!, + getString(R.string.speakCurrentProgress, progressSharingTime) + ) + ) } if (it.roleDivision!! < 0) { binding.tvRoleMinute.isVisible = false binding.tvRoleTime.isVisible = false } else { + val roleDivisionTime = msToMinuteToString(it.roleDivision) + binding.tvRoleMinute.isVisible = true binding.tvRoleTime.isVisible = true - binding.tvRoleMinute.text = - getString(R.string.minute, msToMinuteToString(it.roleDivision)) - meetingList.add(StartMeeting("roleDivision", it.roleDivision!!)) + binding.tvRoleMinute.text = roleDivisionTime + + meetingList.add( + StartMeeting( + getString(R.string.roleDivisionTitle), + it.roleDivision!!, + getString(R.string.speakRoleDivision, roleDivisionTime) + ) + ) } if (it.troubleShooting!! < 0) { binding.tvTroubleShootingMinute.isVisible = false binding.tvTroubleShootingTime.isVisible = false } else { + val troubleShootingTime = msToMinuteToString(it.troubleShooting) + binding.tvTroubleShootingMinute.isVisible = true binding.tvTroubleShootingTime.isVisible = true - binding.tvTroubleShootingMinute.text = - getString(R.string.minute, msToMinuteToString(it.troubleShooting)) - meetingList.add(StartMeeting("troubleShooting", it.troubleShooting!!)) + binding.tvTroubleShootingMinute.text = troubleShootingTime + + meetingList.add( + StartMeeting( + getString(R.string.troubleShootingTitle), + it.troubleShooting!!, + getString(R.string.speakTroubleShooting, troubleShootingTime) + ) + ) } if (it.feedback!! < 0) { binding.tvFeedbackMinute.isVisible = false binding.tvFeedbackTime.isVisible = false } else { + val feedbackTime = msToMinuteToString(it.feedback) + binding.tvFeedbackMinute.isVisible = true binding.tvFeedbackTime.isVisible = true - binding.tvFeedbackMinute.text = - getString(R.string.minute, msToMinuteToString(it.feedback)) - meetingList.add(StartMeeting("feedback", it.feedback!!)) + binding.tvFeedbackMinute.text = feedbackTime + meetingList.add( + StartMeeting( + getString(R.string.feedbackTitle), + it.feedback!!, + getString(R.string.speakFeedback, feedbackTime) + ) + ) } } - private fun msToMinuteToString(ms: Int?): String = (ms?.div(60000)).toString() + private fun msToMinuteToString(ms: Int?): String { + if (ms == null) return "0분" + val minutes = (ms / 60000) + return String.format("%02d분", minutes) + } private fun clickStartMeetingProgress() { binding.tvStartMeeting.setOnClickListener { @@ -180,16 +245,17 @@ class StartProgressMeetingFragment : Fragment() { startSpeaking(meetingList[currentIndex].speaking) // 현재 회의 항목을 UI에 반영 binding.tvCurrentMeetingProgress.text = currentMeeting.progressName - binding.pbTimer.max = currentMeeting.progressTime * 1000 // 밀리초 단위로 설정 + binding.pbTimer.max = currentMeeting.progressTime // 밀리초 단위로 설정 binding.pbTimer.progress = 0 // 타이머 시작 viewLifecycleOwner.lifecycleScope.launch { - for (timeRemaining in currentMeeting.progressTime downTo 0) { + for (timeRemaining in currentMeeting.progressTime / 1000 downTo 0) { if (!isActive) return@launch // 코루틴이 활성 상태인지 확인 - binding.tvTimer.text = intToTimerString(timeRemaining * 1000) // 밀리초로 변환하여 전달 - binding.pbTimer.progress = (currentMeeting.progressTime - timeRemaining) * 1000 + val timeRemainingMs = timeRemaining * 1000 + binding.tvTimer.text = intToTimerString(timeRemainingMs) + binding.pbTimer.progress = currentMeeting.progressTime - timeRemainingMs delay(1000L) // 1초 대기 } @@ -212,7 +278,7 @@ class StartProgressMeetingFragment : Fragment() { override fun onDestroy() { super.onDestroy() - if(ttsObj!=null){ + if (ttsObj != null) { ttsObj?.stop() ttsObj?.shutdown() ttsObj = null diff --git a/feature/projects/src/main/res/values/strings.xml b/feature/projects/src/main/res/values/strings.xml index cff1330..a223556 100644 --- a/feature/projects/src/main/res/values/strings.xml +++ b/feature/projects/src/main/res/values/strings.xml @@ -181,4 +181,20 @@ - 프로젝트에 대한 피드백 진행 완료! 00:00 + 지금부터 %1$s 동안 자기소개를 진행해주세요. + 자기소개 진행 + 아이스브레이킹 진행 + 지금부터 %1$s 동안 아이스브레이킹을 진행해주세요. + 브레인스토밍 진행 + 지금부터 %1$s 동안 브레인스토밍을 진행해주세요. + 주제 선정 진행 + 지금부터 %1$s 동안 주제 선정을 진행해주세요. + 진행 상황 공유 진행 + 지금부터 %1$s 동안 진행 상황 공유를 진행해주세요. + 트러블 슈팅 진행 + 지금부터 %1$s 동안 트러블 슈팅을 진행해주세요. + 프로젝트에 대한 피드백 진행 + 지금부터 %1$s 동안 프로젝트에 대한 피드백을 진행해주세요. + 역할 분담 진행 + 지금부터 %1$s 동안 역할 분담을 진행해주세요. From 6bb35d68cfb5fdf82cb8133014cc4ff2b42ed2a3 Mon Sep 17 00:00:00 2001 From: kangyuri1114 Date: Tue, 6 Aug 2024 03:24:03 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[feat]:=20UI=20State=20=EB=A1=9C=EB=94=A9?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zucchini/ai_members/pm/AiPmActivity.kt | 37 +++++++++++++++++++ .../zucchini/ai_members/pm/AiPmViewModel.kt | 7 +++- .../progress/StartProgressMeetingFragment.kt | 16 +++++++- .../pm/summary/MeetingSummaryFragment.kt | 14 +++++-- .../zucchini/uistate/AiPmLoadingFragment.kt | 27 ++++++++++++++ .../res/layout/fragment_ai_pm_loading.xml | 34 +++++++++++++++++ .../res/layout/fragment_matching_loading.xml | 2 +- .../res/layout/fragment_meeting_summary.xml | 37 +++++++++++++++++++ .../fragment_start_progress_meeting.xml | 3 -- .../projects/src/main/res/values/strings.xml | 1 + 10 files changed, 168 insertions(+), 10 deletions(-) create mode 100644 feature/projects/src/main/java/com/zucchini/uistate/AiPmLoadingFragment.kt create mode 100644 feature/projects/src/main/res/layout/fragment_ai_pm_loading.xml diff --git a/feature/projects/src/main/java/com/zucchini/ai_members/pm/AiPmActivity.kt b/feature/projects/src/main/java/com/zucchini/ai_members/pm/AiPmActivity.kt index bd762ae..097aaf9 100644 --- a/feature/projects/src/main/java/com/zucchini/ai_members/pm/AiPmActivity.kt +++ b/feature/projects/src/main/java/com/zucchini/ai_members/pm/AiPmActivity.kt @@ -4,12 +4,19 @@ import android.os.Bundle import android.util.Log import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import com.google.android.material.tabs.TabLayout +import com.zucchini.ai_members.matching.MatchingResultFragment import com.zucchini.ai_members.pm.progress.ProgressMeetingFragment import com.zucchini.ai_members.pm.progress.StartProgressMeetingFragment import com.zucchini.ai_members.pm.summary.MeetingSummaryFragment +import com.zucchini.feature.projects.R import com.zucchini.feature.projects.databinding.ActivityAiPmBinding +import com.zucchini.uistate.AiPmLoadingFragment +import com.zucchini.uistate.MatchingLoadingFragment +import com.zucchini.uistate.UiState +import com.zucchini.view.showShortToast import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -31,6 +38,7 @@ class AiPmActivity : AppCompatActivity() { clickTabListner() resultSummarySuccess() + collectMatchingResult() } private fun clickTabListner() { @@ -89,4 +97,33 @@ class AiPmActivity : AppCompatActivity() { .replace(binding.vpAiPm.id, StartProgressMeetingFragment()) .commit() } + + private fun collectMatchingResult() { + viewModel.progressMeetingResultData.flowWithLifecycle(lifecycle).onEach { uiState -> + when (uiState) { + is UiState.Initial -> { + // 초기 화면 + } + is UiState.Loading -> { + // 로딩 화면 + supportFragmentManager + .beginTransaction() + .replace(binding.vpAiPm.id, AiPmLoadingFragment()) + .commit() + } + is UiState.Success -> { + // 매칭 결과 화면 + supportFragmentManager + .beginTransaction() + .replace(binding.vpAiPm.id, StartProgressMeetingFragment()) + .commit() + } + is UiState.Failure -> { + showShortToast(getString(R.string.fail_to_progress)) + } + } + + + }.launchIn(lifecycleScope) + } } diff --git a/feature/projects/src/main/java/com/zucchini/ai_members/pm/AiPmViewModel.kt b/feature/projects/src/main/java/com/zucchini/ai_members/pm/AiPmViewModel.kt index 2d7728d..659974d 100644 --- a/feature/projects/src/main/java/com/zucchini/ai_members/pm/AiPmViewModel.kt +++ b/feature/projects/src/main/java/com/zucchini/ai_members/pm/AiPmViewModel.kt @@ -25,7 +25,7 @@ constructor( private val _progressMeetingCheckbox = MutableStateFlow(ProgressMeetingInfo()) - private val _progressMeetingResultData = MutableStateFlow(null) + private val _progressMeetingResultData = MutableStateFlow(UiState.Initial as UiState) val progressMeetingResultData = _progressMeetingResultData.asStateFlow() private val _meetingTotalTime = MutableStateFlow(0) @@ -73,12 +73,14 @@ constructor( fun sendProgressMeetingInfo() { viewModelScope.launch { + _progressMeetingResultData.value = UiState.Loading + aiPmRepository .getProgressMeetingData( _progressMeetingInfo.value, _progressMeetingCheckbox.value, ).onSuccess { - _progressMeetingResultData.value = it + _progressMeetingResultData.value = UiState.Success(it) _summarySuccess.value = true Log.d("AiPmViewModel", "progressMeetingResultData: $it, progressIntroduce: ${it.introduceMyself}") @@ -94,6 +96,7 @@ constructor( }.onFailure { Timber.d(it) _summarySuccess.value = false + UiState.Failure(it.message ?: "Error") } } } diff --git a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt index 0e46520..46ef699 100644 --- a/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt +++ b/feature/projects/src/main/java/com/zucchini/ai_members/pm/progress/StartProgressMeetingFragment.kt @@ -14,6 +14,7 @@ import com.zucchini.ai_members.pm.AiPmViewModel import com.zucchini.domain.model.ai.ProgressMeeting import com.zucchini.feature.projects.R import com.zucchini.feature.projects.databinding.FragmentStartProgressMeetingBinding +import com.zucchini.uistate.UiState import kotlinx.coroutines.delay import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -65,7 +66,20 @@ class StartProgressMeetingFragment : Fragment() { private fun collectProgressMeetingInfo() { viewModel.progressMeetingResultData.flowWithLifecycle(viewLifecycleOwner.lifecycle) .onEach { - setMeetingIndex(it) + when (it) { + is UiState.Initial -> { + // 초기 화면 + } + is UiState.Loading -> { + // 로딩 화면 + } + is UiState.Success -> { + setMeetingIndex(it.data) + } + is UiState.Failure -> { + // 에러 화면 + } + } }.launchIn(viewLifecycleOwner.lifecycleScope) } diff --git a/feature/projects/src/main/java/com/zucchini/ai_members/pm/summary/MeetingSummaryFragment.kt b/feature/projects/src/main/java/com/zucchini/ai_members/pm/summary/MeetingSummaryFragment.kt index f5a46bc..9b2d7e8 100644 --- a/feature/projects/src/main/java/com/zucchini/ai_members/pm/summary/MeetingSummaryFragment.kt +++ b/feature/projects/src/main/java/com/zucchini/ai_members/pm/summary/MeetingSummaryFragment.kt @@ -17,6 +17,7 @@ import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.flowWithLifecycle @@ -25,6 +26,7 @@ import com.zucchini.ai_members.pm.AiPmViewModel import com.zucchini.feature.projects.R import com.zucchini.feature.projects.databinding.FragmentMeetingSummaryBinding import com.zucchini.uistate.UiState +import com.zucchini.view.showShortToast import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import java.io.File @@ -163,16 +165,22 @@ class MeetingSummaryFragment : Fragment() { .onEach { uiState -> when (uiState) { is UiState.Loading -> { - // 로딩 중인 경우 로딩 화면 표시 - // delay(10000) + binding.clAiPmLoading.isVisible = true } is UiState.Success -> { + binding.clAiPmLoading.isVisible = false binding.aiPmSummaryMeetingResult.text = uiState.data } - else -> { + is UiState.Failure -> { + binding.clAiPmLoading.isVisible = false binding.aiPmSummaryMeetingResult.text = getString(R.string.fail_to_summary) + showShortToast(uiState.errorMessage) + } + + else -> { + binding.clAiPmLoading.isVisible = false } } }.launchIn(lifecycleScope) diff --git a/feature/projects/src/main/java/com/zucchini/uistate/AiPmLoadingFragment.kt b/feature/projects/src/main/java/com/zucchini/uistate/AiPmLoadingFragment.kt new file mode 100644 index 0000000..e47cbe5 --- /dev/null +++ b/feature/projects/src/main/java/com/zucchini/uistate/AiPmLoadingFragment.kt @@ -0,0 +1,27 @@ +package com.zucchini.uistate + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.zucchini.feature.projects.R +import com.zucchini.feature.projects.databinding.FragmentAiPmLoadingBinding +import com.zucchini.feature.projects.databinding.FragmentMatchingLoadingBinding +import com.zucchini.feature.projects.databinding.FragmentMatchingResultBinding +import com.zucchini.feature.projects.databinding.FragmentSubmitProjectBinding + +class AiPmLoadingFragment : Fragment() { + + private var _binding: FragmentAiPmLoadingBinding? = null + private val binding: FragmentAiPmLoadingBinding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentAiPmLoadingBinding.inflate(inflater, container, false) + return binding.root + } + +} \ No newline at end of file diff --git a/feature/projects/src/main/res/layout/fragment_ai_pm_loading.xml b/feature/projects/src/main/res/layout/fragment_ai_pm_loading.xml new file mode 100644 index 0000000..3adbb42 --- /dev/null +++ b/feature/projects/src/main/res/layout/fragment_ai_pm_loading.xml @@ -0,0 +1,34 @@ + + + + + + + + + \ No newline at end of file diff --git a/feature/projects/src/main/res/layout/fragment_matching_loading.xml b/feature/projects/src/main/res/layout/fragment_matching_loading.xml index 3de0f86..e2d3038 100644 --- a/feature/projects/src/main/res/layout/fragment_matching_loading.xml +++ b/feature/projects/src/main/res/layout/fragment_matching_loading.xml @@ -19,7 +19,7 @@ android:id="@+id/tv_loading" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="개발자 추천 매칭 중..." + android:text="프로젝트에 적합한 개발자를 생각 중이에요..." android:textSize="20sp" android:layout_marginTop="20dp" app:layout_constraintStart_toStartOf="parent" diff --git a/feature/projects/src/main/res/layout/fragment_meeting_summary.xml b/feature/projects/src/main/res/layout/fragment_meeting_summary.xml index 3a39e32..d58037b 100644 --- a/feature/projects/src/main/res/layout/fragment_meeting_summary.xml +++ b/feature/projects/src/main/res/layout/fragment_meeting_summary.xml @@ -114,4 +114,41 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/ai_pm_summary_meeting_result_title" /> + + + + + + \ No newline at end of file diff --git a/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml b/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml index b7d578c..a6fa402 100644 --- a/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml +++ b/feature/projects/src/main/res/layout/fragment_start_progress_meeting.xml @@ -363,12 +363,9 @@ android:text="@string/done" android:textColor="@color/main_olive" android:textSize="18dp" - android:layout_marginBottom="30dp" android:visibility="gone" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/pb_timer" /> - \ No newline at end of file diff --git a/feature/projects/src/main/res/values/strings.xml b/feature/projects/src/main/res/values/strings.xml index a223556..3a3a583 100644 --- a/feature/projects/src/main/res/values/strings.xml +++ b/feature/projects/src/main/res/values/strings.xml @@ -197,4 +197,5 @@ 지금부터 %1$s 동안 프로젝트에 대한 피드백을 진행해주세요. 역할 분담 진행 지금부터 %1$s 동안 역할 분담을 진행해주세요. + 회의 진행에 문제가 생겼어요. 다시 시도해주세요.