From eab8e2bc13f736402b6ccde48766febb4d8d60fc Mon Sep 17 00:00:00 2001 From: dkyuuum Date: Tue, 20 Feb 2024 18:08:00 +0900 Subject: [PATCH 1/3] =?UTF-8?q?Feat:=20=ED=96=A5=ED=9B=84=EA=B3=84?= =?UTF-8?q?=ED=9A=8D/=EC=8B=9C=EA=B0=84=ED=91=9C=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/deploymentTargetDropDown.xml | 17 - .../data/model/plan/CertificateResponse.kt | 13 + .../project/data/model/plan/DeleteLicense.kt | 14 + .../data/model/plan/TimeInfoResponse.kt | 7 + .../project/data/model/plan/UpTimeResponse.kt | 16 + .../project/data/network/api/PlanApi.kt | 21 +- .../mobile/project/ui/home/HomeFragment.kt | 6 +- .../project/ui/plan/PlanRecyclerAdapter.kt | 6 +- .../project/ui/plan/PlanSettingFragment.kt | 21 +- .../mobile/project/ui/plan/PlanTimeAdapter.kt | 31 +- .../project/ui/plan/PlanTimeFragment.kt | 7 +- .../project/ui/plan/PlanTimetableFragment.kt | 174 ++-- .../mobile/project/ui/plan/PlanViewModel.kt | 782 +++++++++++------- .../project/ui/plan/PlanlicenseFragment.kt | 28 +- .../main/res/layout/fragment_planlicense.xml | 88 +- app/src/main/res/layout/plan_time_main.xml | 309 ++++--- .../main/res/layout/plan_time_tab_main.xml | 11 + .../main/res/navigation/mobile_navigation.xml | 13 +- app/src/main/res/values/strings.xml | 11 + 19 files changed, 928 insertions(+), 647 deletions(-) delete mode 100644 .idea/deploymentTargetDropDown.xml create mode 100644 app/src/main/java/umc/com/mobile/project/data/model/plan/CertificateResponse.kt create mode 100644 app/src/main/java/umc/com/mobile/project/data/model/plan/DeleteLicense.kt create mode 100644 app/src/main/java/umc/com/mobile/project/data/model/plan/TimeInfoResponse.kt create mode 100644 app/src/main/java/umc/com/mobile/project/data/model/plan/UpTimeResponse.kt diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml deleted file mode 100644 index e65faff1..00000000 --- a/.idea/deploymentTargetDropDown.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/umc/com/mobile/project/data/model/plan/CertificateResponse.kt b/app/src/main/java/umc/com/mobile/project/data/model/plan/CertificateResponse.kt new file mode 100644 index 00000000..3b8857e3 --- /dev/null +++ b/app/src/main/java/umc/com/mobile/project/data/model/plan/CertificateResponse.kt @@ -0,0 +1,13 @@ +package umc.com.mobile.project.data.model.plan + +data class CertificateResponse( + val isSuccess: Boolean, + val code: String, + val message: String, + val result: List +) + +data class CertificateUpdateInfo( + val certificateId: Long, + val updatedAt: String +) diff --git a/app/src/main/java/umc/com/mobile/project/data/model/plan/DeleteLicense.kt b/app/src/main/java/umc/com/mobile/project/data/model/plan/DeleteLicense.kt new file mode 100644 index 00000000..efd8410c --- /dev/null +++ b/app/src/main/java/umc/com/mobile/project/data/model/plan/DeleteLicense.kt @@ -0,0 +1,14 @@ +package umc.com.mobile.project.data.model + +data class DeleteLicense( + val isSuccess: Boolean, + val code: String, + val message: String, + val result: List +) + +data class DeleteItem( + val certificateId: Long, + val name: String, + val date: String +) diff --git a/app/src/main/java/umc/com/mobile/project/data/model/plan/TimeInfoResponse.kt b/app/src/main/java/umc/com/mobile/project/data/model/plan/TimeInfoResponse.kt new file mode 100644 index 00000000..c0bbf970 --- /dev/null +++ b/app/src/main/java/umc/com/mobile/project/data/model/plan/TimeInfoResponse.kt @@ -0,0 +1,7 @@ +package umc.com.mobile.project.data.model.plan + +data class TimeInfoResponse( + val type: String, + val name: String, + val credit:String, +) diff --git a/app/src/main/java/umc/com/mobile/project/data/model/plan/UpTimeResponse.kt b/app/src/main/java/umc/com/mobile/project/data/model/plan/UpTimeResponse.kt new file mode 100644 index 00000000..832cd3c3 --- /dev/null +++ b/app/src/main/java/umc/com/mobile/project/data/model/plan/UpTimeResponse.kt @@ -0,0 +1,16 @@ +package umc.com.mobile.project.data.model.plan + +data class UpTimeResponse( + val isSuccess: Boolean, + val code: String, + val message: String, + val result: List, +) + +data class upTimeResult( + val subjectId: Long, + val type: String, + val name: String, + val credit: Long, +) + diff --git a/app/src/main/java/umc/com/mobile/project/data/network/api/PlanApi.kt b/app/src/main/java/umc/com/mobile/project/data/network/api/PlanApi.kt index 614f3748..6c8157c9 100644 --- a/app/src/main/java/umc/com/mobile/project/data/network/api/PlanApi.kt +++ b/app/src/main/java/umc/com/mobile/project/data/network/api/PlanApi.kt @@ -3,12 +3,17 @@ package umc.com.mobile.project.data.network.api import retrofit2.http.GET import retrofit2.Call import retrofit2.http.Body +import retrofit2.http.DELETE import retrofit2.http.PATCH import retrofit2.http.POST +import retrofit2.http.Path import retrofit2.http.Query +import umc.com.mobile.project.data.model.DeleteLicense import umc.com.mobile.project.data.model.plan.AddTimeRequest import umc.com.mobile.project.data.model.plan.AddTimeResponse import umc.com.mobile.project.data.model.plan.BringlicenseResponse +import umc.com.mobile.project.data.model.plan.CertificateLicenseRequest +import umc.com.mobile.project.data.model.plan.CertificateResponse import umc.com.mobile.project.data.model.plan.ListTimeResponse import umc.com.mobile.project.data.model.plan.PlanFreeRequest import umc.com.mobile.project.data.model.plan.PlanFreeResponse @@ -17,19 +22,16 @@ import umc.com.mobile.project.data.model.plan.SaveInfo import umc.com.mobile.project.data.model.plan.SemesterTimeResponse import umc.com.mobile.project.data.model.plan.UPlicenseResponse import umc.com.mobile.project.data.model.plan.EditMemoRequest +import umc.com.mobile.project.data.model.plan.UpTimeResponse interface PlanApi { @GET("plans/certifications") fun getUPlicense(): Call - @POST("plans/certifications") fun saveLicense(@Body request: List): Call - - - @GET("/plans/timetable/searchSubject") fun getListTime(@Query("hakki") hakki:String, @Query("track") track : String) : Call @@ -48,12 +50,15 @@ interface PlanApi { @POST("/plans/memo") fun postFreeMemo(@Body request: PlanFreeRequest): Call + @GET("/plans/timetable") + fun getUptime(@Query("grade") grade:Int, @Query("semseter") semester : Int):Call + @PATCH("/plans/memo") fun editMemo(@Body editMemoRequest: EditMemoRequest) : Call + @PATCH("/plans/certifications") + fun certificateLicense(@Body request: CertificateLicenseRequest) : Call - - - - + @DELETE("/plans/certifications") + fun deleteLicense(@Query("certificateId") certificateId: Long): Call } \ No newline at end of file diff --git a/app/src/main/java/umc/com/mobile/project/ui/home/HomeFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/home/HomeFragment.kt index 6987dc85..46dee1e4 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/home/HomeFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/home/HomeFragment.kt @@ -56,13 +56,13 @@ class HomeFragment : Fragment() { // 페이지 이동 private fun navigateFragment() { binding.btnCheeringWordMove.setOnClickListener { - navigate(R.id.action_fragment_home_to_fragment_date) + navigate(R.id.action_fragment_home_to_planTimetableFragment) } binding.layoutNextPlan.setOnClickListener { - navigate(R.id.action_fragment_home_to_planSettingFragment) + navigate(R.id.action_fragment_home_to_planTimetableFragment) } binding.constraintLayout3.setOnClickListener { - navigate(R.id.action_fragment_home_to_planSettingFragment) + navigate(R.id.action_fragment_home_to_planTimetableFragment) } } diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanRecyclerAdapter.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanRecyclerAdapter.kt index 57440ad9..8c72eeb0 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanRecyclerAdapter.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanRecyclerAdapter.kt @@ -4,10 +4,8 @@ import android.text.Editable import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import umc.com.mobile.project.data.model.career.PointDtoList -import umc.com.mobile.project.data.model.career.Result +import umc.com.mobile.project.data.model.plan.TimeInfoResponse import umc.com.mobile.project.data.model.plan.TimeResult -import umc.com.mobile.project.databinding.ItemCertificateBinding import umc.com.mobile.project.databinding.ItemTimeSubjectBinding class PlanRecyclerAdapter( @@ -27,7 +25,7 @@ class PlanRecyclerAdapter( override fun getItemCount(): Int = timeList.size - fun updateTimeList(newTimeList: List) { + fun updateTimeList(newTimeList: List) { this.timeList = newTimeList notifyDataSetChanged() // 데이터가 변경되었음을 알리고 UI를 갱신 } diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanSettingFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanSettingFragment.kt index 6750ae59..4a6c9995 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanSettingFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanSettingFragment.kt @@ -1,26 +1,16 @@ package umc.com.mobile.project.ui.plan import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController -import androidx.viewpager.widget.ViewPager import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator -import umc.com.mobile.project.R -import umc.com.mobile.project.databinding.FragmentSettingBinding -import umc.com.mobile.project.databinding.PlanSubjectListBinding import umc.com.mobile.project.databinding.PlanTimeTabMainBinding -import umc.com.mobile.project.databinding.SemesterChooseBinding -import umc.com.mobile.project.ui.gradInfo.adapter.GradInfoVPAdapter -import umc.com.mobile.project.ui.gradInfo.viewmodel.GradInfoViewModel class PlanSettingFragment : Fragment() { private var _binding: PlanTimeTabMainBinding? = null @@ -39,14 +29,23 @@ class PlanSettingFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View { + // PlanTimeTabMainBinding을 인플레이트하여 루트 뷰를 가져옴 _binding = PlanTimeTabMainBinding.inflate(inflater, container, false) val view = binding.root + + // 탭 레이아웃 및 뷰페이저 초기화 initTabLayout() initViewPager() + binding.planSettingBackButton.setOnClickListener { + findNavController().navigateUp() + } + return view + + } @@ -54,9 +53,11 @@ class PlanSettingFragment : Fragment() { val tabTitle = arrayOf("시간표", "자격증", "자유") + viewPager = binding.viewPagerTimeTabMain tabLayout = binding.tabLayoutPlanTime + val adapter = PlanVPAdapter(this) adapter.addFragment(PlanTimeFragment()) diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimeAdapter.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimeAdapter.kt index 6b143b95..93f3e3ce 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimeAdapter.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimeAdapter.kt @@ -1,19 +1,21 @@ +package umc.com.mobile.project.ui.plan + import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import umc.com.mobile.project.data.model.plan.TimeResult +import umc.com.mobile.project.data.model.plan.TimeInfoResponse import umc.com.mobile.project.databinding.ItemPlanTimeBinding -class PlanTimeAdapter : ListAdapter(TimeResultDiffCallback()) { +class PlanTimeAdapter(private var addnewtime: List = ArrayList()): ListAdapter(UpTimeResultDiffCallback()) { - // ViewHolder 클래스는 그대로 유지합니다. class ViewHolder(private val binding: ItemPlanTimeBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(item: TimeResult) { - binding.timeKindTitle.text = item.searchType - binding.timeClassTitle.text = item.searchName - binding.timeGradeTitle.text = item.searchCredit.toString() // toString() 추가, 학점을 문자열로 표시 + fun bind(item: TimeInfoResponse) { + binding.timeKindTitle.text = item.type + binding.timeClassTitle.text = item.name + // 학점을 문자열로 변환하여 표시 + binding.timeGradeTitle.text = item.credit.toString() } } @@ -27,17 +29,18 @@ class PlanTimeAdapter : ListAdapter(Time holder.bind(item) } - // 현재 데이터 리스트를 가져오는 편의 메서드를 추가합니다. - fun getCurrentData(): List { - return currentList + fun updateTimeList(addnewtime: ArrayList) { + submitList(addnewtime) } - class TimeResultDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: TimeResult, newItem: TimeResult): Boolean { - return oldItem.searchName == newItem.searchName + class UpTimeResultDiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: TimeInfoResponse, newItem: TimeInfoResponse): Boolean { + // subjectId를 비교하여 동일한 아이템인지 판별 + return oldItem.name== newItem.name } - override fun areContentsTheSame(oldItem: TimeResult, newItem: TimeResult): Boolean { + override fun areContentsTheSame(oldItem: TimeInfoResponse, newItem: TimeInfoResponse): Boolean { + // 내용이 동일한지 비교 return oldItem == newItem } } diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimeFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimeFragment.kt index 06982e7a..ac6c2a8c 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimeFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimeFragment.kt @@ -10,6 +10,7 @@ import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager import umc.com.mobile.project.R +import umc.com.mobile.project.data.model.plan.TimeInfoResponse import umc.com.mobile.project.databinding.PlanSubjectListBinding import umc.com.mobile.project.ui.common.NavigationUtil.navigate @@ -38,7 +39,7 @@ class PlanTimeFragment : Fragment() { val adapter = PlanRecyclerAdapter(emptyList(), onAddButtonClicked = { timeResult -> if (timeResult != null) { - viewModel.setSelectedTimeResult(timeResult) + viewModel.setSelectedTimeResult(timeResult = TimeInfoResponse(timeResult.searchType,timeResult.searchName,timeResult.searchCredit)) } @@ -67,9 +68,7 @@ class PlanTimeFragment : Fragment() { } private fun setupNavigation() { - binding.planTimeMoveTimetable.setOnClickListener { - navigate(R.id.action_planSettingFragment_to_planTimetableFragment) - } + binding.planSubjectListSemester.setOnClickListener { navigate(R.id.action_planSettingFragment_to_planSemesterFragment) diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt index ce079f10..a4135379 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt @@ -1,20 +1,19 @@ package umc.com.mobile.project.ui.plan -import PlanTimeAdapter import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter import android.widget.Toast import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels -import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager +import umc.com.mobile.project.R import umc.com.mobile.project.databinding.PlanTimeMainBinding -import umc.com.mobile.project.data.model.plan.AddTimeRequest -import umc.com.mobile.project.data.model.plan.SemesterDto -import umc.com.mobile.project.data.model.plan.SubjectDtoList +import umc.com.mobile.project.ui.common.NavigationUtil.navigate + class PlanTimetableFragment : Fragment() { @@ -35,61 +34,140 @@ class PlanTimetableFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupRecyclerView() - setupSaveButton() - observeAddTimeResponse() + observeSelectedTimeResults() - binding.planTimetableBackButton.setOnClickListener { - findNavController().navigateUp() - } - } - private fun setupRecyclerView() { - adapter = PlanTimeAdapter() - binding.recyclerView.layoutManager = LinearLayoutManager(context) - binding.recyclerView.adapter = adapter + val spinner = binding.spinnerPlanTimeTrackSemester + val adapter = ArrayAdapter.createFromResource( + requireContext(), + R.array.semester_options, + android.R.layout.simple_spinner_item + ) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + spinner.adapter = adapter + + // 선택한 항목 리스너 추가 (필요한 경우) + + spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { + val selectedItem = parent?.getItemAtPosition(position).toString() + when (selectedItem) { + "1학년 1학기" -> { + viewModel.setGradeAndSemester(1, 1) +// viewModel.getTimeInfo(1, 1) + + + } + + "1학년 2학기" -> { + viewModel.setGradeAndSemester(1, 2) +// viewModel.getTimeInfo(1, 2) + + + } + + "2학년 1학기" -> { + viewModel.setGradeAndSemester(2, 1) +// viewModel.getTimeInfo(2, 1) + + + } + + "2학년 2학기" -> { + viewModel.setGradeAndSemester(2, 2) +// viewModel.getTimeInfo(2, 2) + + + } + + "3학년 1학기" -> { + viewModel.setGradeAndSemester(3, 1) +// viewModel.getTimeInfo(3, 1) + + + } + + "3학년 2학기" -> { + viewModel.setGradeAndSemester(3, 2) +// viewModel.getTimeInfo(3, 2) + + + } + + "4학년 1학기" -> { + viewModel.setGradeAndSemester(4, 1) +// viewModel.getTimeInfo(4, 1) + + + } + + "4학년 2학기" -> { + viewModel.setGradeAndSemester(4, 2) +// viewModel.getTimeInfo(4, 2) + + + } + + } - viewModel.selectedTimeResults.observe(viewLifecycleOwner) { results -> - adapter.submitList(results.toList()) - } - } - private fun setupSaveButton() { - binding.timeStoreButton.setOnClickListener { - val currentDataList = adapter.getCurrentData() - - // 서버로 전송할 데이터 리스트를 기반으로 AddTimeRequest 객체를 생성합니다. - val subjectDtoList = currentDataList.map { - SubjectDtoList( - it.searchType, - it.searchName, - it.searchCredit - ) } - val addTimeRequest = AddTimeRequest( - SemesterDto(grade = 1, semester = 1), - subjectDtoList - ) // 예시값을 사용한 SemesterDto - // ViewModel의 addTime 메서드를 호출하여 서버로 데이터를 전송합니다. - viewModel.addTime(addTimeRequest) + override fun onNothingSelected(parent: AdapterView<*>?) { + // 아무 것도 선택되지 않은 경우의 동작 구현 + } } - } + binding.timeStoreButton.setOnClickListener { + // grade와 semester가 선택되었는지 확인 + val grade = viewModel.grade.value + val semester = viewModel.semester.value - private fun observeAddTimeResponse() { - viewModel.addTimeResponse.observe(viewLifecycleOwner) { response -> - if (response != null && response.isSuccess) { - Toast.makeText(context, "Data saved successfully!", Toast.LENGTH_SHORT).show() - Log.d("PlanTimetableFragment", "Data saved successfully: ${response.message}") + if (grade == null || semester == null) { + // 학년 또는 학기가 선택되지 않았다면 토스트 메시지 표시 + Toast.makeText(context, "학년과 학기를 선택해주세요.", Toast.LENGTH_SHORT).show() } else { - Toast.makeText(context, "Failed to save data.", Toast.LENGTH_SHORT).show() - Log.e("PlanTimetableFragment", "Failed to save data") + // 선택된 경우에만 서버로 데이터 전송 처리 + viewModel.sendAddTimeRequest() + viewModel.getTimeInfo(grade, semester) } } + + + + binding.titleMoveTimetable.setOnClickListener { + navigate(R.id.action_fragment_home_to_planTimetableFragment) + + } + } - override fun onDestroyView() { - super.onDestroyView() - _binding = null + + + + private fun observeSelectedTimeResults() { + viewModel.selectedTimeResults.observe(viewLifecycleOwner) { selectedTimeResults -> + (binding.recyclerView.adapter as PlanTimeAdapter).updateTimeList(selectedTimeResults) } } + // 추가하기 버튼으로 시간표에 과목 업데이트 + private fun setupRecyclerView() { + // 초기 데이터 리스트를 비어 있는 리스트로 설정합니다. + // 데이터가 준비되면, 나중에 observeSelectedTimeResults 함수 내에서 submitList를 통해 업데이트합니다. + adapter = PlanTimeAdapter(emptyList()) + binding.recyclerView.layoutManager = LinearLayoutManager(context) + binding.recyclerView.adapter = adapter + } + + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} + diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanViewModel.kt index fba47fdc..1d9b3853 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanViewModel.kt @@ -1,408 +1,548 @@ -package umc.com.mobile.project.ui.plan - - -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response -import umc.com.mobile.project.data.model.plan.AddTimeRequest -import umc.com.mobile.project.data.model.plan.AddTimeResponse -import umc.com.mobile.project.data.model.plan.BringlicenseResponse -import umc.com.mobile.project.data.model.plan.EditMemoRequest -import umc.com.mobile.project.data.model.plan.ListTimeResponse -import umc.com.mobile.project.data.model.plan.PlanFreeRequest -import umc.com.mobile.project.data.model.plan.PlanFreeResponse -import umc.com.mobile.project.data.model.plan.PlanTrackResponse -import umc.com.mobile.project.data.model.plan.SaveInfo - -import umc.com.mobile.project.data.model.plan.SavelicenseRequest -import umc.com.mobile.project.data.model.plan.SemesterTimeResponse -import umc.com.mobile.project.data.model.plan.SubjectDtoList -import umc.com.mobile.project.data.model.plan.TimeResult - -import umc.com.mobile.project.data.model.plan.UPlicenseResponse -import umc.com.mobile.project.data.network.ApiClient -import umc.com.mobile.project.data.network.api.PlanApi - -class PlanViewModel : ViewModel() { - - - //api - private val planApiService = ApiClient.createService() - - private val _selectedTimeResults = MutableLiveData>() - val selectedTimeResults: LiveData> = _selectedTimeResults - - fun setSelectedTimeResult(timeResult: TimeResult) { - val currentList = _selectedTimeResults.value ?: ArrayList() - currentList.add(timeResult) - _selectedTimeResults.value = currentList - Log.d("PlanTimetable", "setSelectedTimeResult: $timeResult") - } + package umc.com.mobile.project.ui.plan + import android.util.Log + import androidx.lifecycle.LiveData + import androidx.lifecycle.MutableLiveData + import androidx.lifecycle.ViewModel + import retrofit2.Call + import retrofit2.Callback + import retrofit2.Response + import umc.com.mobile.project.data.model.DeleteLicense + import umc.com.mobile.project.data.model.plan.AddTimeRequest + import umc.com.mobile.project.data.model.plan.AddTimeResponse + import umc.com.mobile.project.data.model.plan.BringlicenseResponse + import umc.com.mobile.project.data.model.plan.CertificateLicenseRequest + import umc.com.mobile.project.data.model.plan.CertificateResponse + import umc.com.mobile.project.data.model.plan.EditMemoRequest + import umc.com.mobile.project.data.model.plan.ListTimeResponse + import umc.com.mobile.project.data.model.plan.PlanFreeRequest + import umc.com.mobile.project.data.model.plan.PlanFreeResponse + import umc.com.mobile.project.data.model.plan.PlanTrackResponse + import umc.com.mobile.project.data.model.plan.SaveInfo + import umc.com.mobile.project.data.model.plan.SavelicenseRequest + import umc.com.mobile.project.data.model.plan.SemesterDto + import umc.com.mobile.project.data.model.plan.SemesterTimeResponse + import umc.com.mobile.project.data.model.plan.SubjectDtoList + import umc.com.mobile.project.data.model.plan.TimeInfoResponse + import umc.com.mobile.project.data.model.plan.TimeResult - private val _planFreeInfo: MutableLiveData = MutableLiveData() - val planFreeInfo: LiveData - get() = _planFreeInfo + import umc.com.mobile.project.data.model.plan.UPlicenseResponse + import umc.com.mobile.project.data.model.plan.UpTimeResponse + import umc.com.mobile.project.data.model.plan.upTimeResult + import umc.com.mobile.project.data.network.ApiClient + import umc.com.mobile.project.data.network.api.PlanApi - private val _postMemoResult = MutableLiveData() - val postMemoResult: LiveData - get() = _postMemoResult + class PlanViewModel : ViewModel() { - private val _hakki: MutableLiveData = MutableLiveData() - val hakki: LiveData - get() = _hakki - private val _track: MutableLiveData = MutableLiveData() - val track: LiveData - get() = _track + //api + private val planApiService = ApiClient.createService() + private val _upTimeResponse: MutableLiveData = MutableLiveData() + val upTimeResponse: LiveData + get() = upTimeResponse - private val _planSemesterInfo: MutableLiveData = MutableLiveData() - val planSemesterInfo: LiveData - get() = _planSemesterInfo + private val _grade: MutableLiveData = MutableLiveData() + val grade: LiveData + get() = _grade - private val _planTrackInfo: MutableLiveData = MutableLiveData() - val planTrackInfo: LiveData - get() = _planTrackInfo + private val _semester: MutableLiveData = MutableLiveData() + val semester: LiveData + get() = _semester + fun setGradeAndSemester(grade: Int, semester: Int) { + _grade.value = grade + _semester.value = semester + } - private val _timeTableInfo = MutableLiveData() - val timeTableInfo: LiveData = _timeTableInfo + //viewmodel 에 데이터 저장, 시간표 조회, 과목 검색 + private val _selectedTimeResults = MutableLiveData>() + val selectedTimeResults: LiveData> = _selectedTimeResults + fun setSelectedTimeResult(timeResult:TimeInfoResponse) { + val currentList = _selectedTimeResults.value ?: ArrayList() + currentList.add(timeResult) + _selectedTimeResults.value = currentList + Log.d("PlanTimetable", "setSelectedTimeResult: $timeResult") + } - private val _planTimeStatus: MutableLiveData = MutableLiveData() - val planTimeStatus: LiveData - get() = _planTimeStatus - private val _bringLicenseInfo = MutableLiveData() - private val _listTimeInfo = MutableLiveData() + private val _planFreeInfo: MutableLiveData = MutableLiveData() + val planFreeInfo: LiveData + get() = _planFreeInfo - val listTimeInfo: LiveData - get() = _listTimeInfo + private val _postMemoResult = MutableLiveData() + val postMemoResult: LiveData + get() = _postMemoResult - val bringLicenseInfo: LiveData - get() = _bringLicenseInfo + private val _hakki: MutableLiveData = MutableLiveData() + val hakki: LiveData + get() = _hakki + private val _track: MutableLiveData = MutableLiveData() + val track: LiveData + get() = _track - private val _licenseInfo: MutableLiveData = MutableLiveData() - val licenseInfo: LiveData - get() = _licenseInfo + private val _planSemesterInfo: MutableLiveData = MutableLiveData() + val planSemesterInfo: LiveData + get() = _planSemesterInfo - private val _error: MutableLiveData = MutableLiveData() - val error: LiveData - get() = _error + private val _planTrackInfo: MutableLiveData = MutableLiveData() + val planTrackInfo: LiveData + get() = _planTrackInfo + private val _timeTableInfo = MutableLiveData() + val timeTableInfo: LiveData = _timeTableInfo - private val _savelicenseInfo: MutableLiveData = MutableLiveData() - val savelicenseInfo: LiveData - get() = _savelicenseInfo + private val _planTimeStatus: MutableLiveData = MutableLiveData() + val planTimeStatus: LiveData + get() = _planTimeStatus + private val _bringLicenseInfo = MutableLiveData() - // 기존에 있던 text LiveData - private val _text = MutableLiveData().apply { - value = "This is Plan Fragment" - } - val text: LiveData = _text + private val _listTimeInfo = MutableLiveData() - // 새로 추가된 isFilledAllOptions LiveData - private val _isFilledAllOptions = MutableLiveData().apply { - value = false // 초기값 설정 - } - val isFilledAllOptions: LiveData = _isFilledAllOptions + val listTimeInfo: LiveData + get() = _listTimeInfo - // isFilledAllOptions의 값을 업데이트하는 메서드 - fun updateIsFilledAllOptions(isFilled: Boolean) { - _isFilledAllOptions.value = isFilled - } - fun resetSemesterSelection() { - // 학기 정보 관련 상태 초기화 - _planSemesterInfo.postValue(null) // 학기 정보 초기화 - _hakki.postValue("") // 학기 식별자 초기화 (또는 적절한 초기 값으로 설정) - } + val bringLicenseInfo: LiveData + get() = _bringLicenseInfo - fun resetTrackSelection() { - // 선택된 트랙 정보 초기화 - _track.postValue("") // 트랙 식별자 초기화 (또는 적절한 초기 값으로 설정) - } - fun setHakki(hakki: String) { - _hakki.value = hakki - Log.d("hakki value", "setHakki 호출됨: hakki=$hakki") - } + private val _licenseInfo: MutableLiveData = MutableLiveData() + val licenseInfo: LiveData + get() = _licenseInfo - fun setHakkiAndTrack(hakki: String, trackId: String) { - Log.d("hakkitrackvalue", "setHakkiAndTrack 호출됨: hakki=$hakki, trackId=$trackId") - _hakki.value = hakki - _track.value = trackId - } + private val _error: MutableLiveData = MutableLiveData() + val error: LiveData + get() = _error - private val _addTimeResponse = MutableLiveData() - val addTimeResponse: MutableLiveData = _addTimeResponse - - fun addTime(request: AddTimeRequest) { - planApiService.addTime(request).enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - // 서버로부터 응답을 성공적으로 받았을 때 LiveData 업데이트 - Log.d("TimeTableApi", "getListTimeInfo 성공: ${response.body()}") - _addTimeResponse.postValue(response.body()) - } else { - // 에러 처리: 실패 응답 처리 - Log.e("TimeTableApi", "Error posting memo: ${response.errorBody()?.string()}") - _addTimeResponse.postValue(null) - } - } - override fun onFailure(call: Call, t: Throwable) { - // 네트워크 에러 처리: LiveData 업데이트로 에러 상태 전달 가능 - _addTimeResponse.postValue(null) - } - }) - } + private val _savelicenseInfo: MutableLiveData = MutableLiveData() + val savelicenseInfo: LiveData + get() = _savelicenseInfo + private val _certificateResponse = MutableLiveData() + val certificateResponse: LiveData + get() = _certificateResponse - fun postMemo(memoRequest: PlanFreeRequest) { - planApiService.postFreeMemo(memoRequest).enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - // API 호출 성공 시, 성공 LiveData 업데이트 - _postMemoResult.postValue(true) - } else { - // 실패 시, 실패 LiveData 업데이트 - Log.e("PlanViewModel", "Error posting memo: ${response.errorBody()?.string()}") - _postMemoResult.postValue(false) - } - } + // 기존에 있던 text LiveData + private val _text = MutableLiveData().apply { + value = "This is Plan Fragment" + } + val text: LiveData = _text - override fun onFailure(call: Call, t: Throwable) { - // 네트워크 오류 등으로 호출 실패 시, 실패 LiveData 업데이트 - _postMemoResult.postValue(false) - } - }) - } + // 새로 추가된 isFilledAllOptions LiveData + private val _isFilledAllOptions = MutableLiveData().apply { + value = false // 초기값 설정 + } + val isFilledAllOptions: LiveData = _isFilledAllOptions + + // isFilledAllOptions의 값을 업데이트하는 메서드 + fun updateIsFilledAllOptions(isFilled: Boolean) { + _isFilledAllOptions.value = isFilled + } + fun resetSemesterSelection() { + // 학기 정보 관련 상태 초기화 + _planSemesterInfo.postValue(null) // 학기 정보 초기화 + _hakki.postValue("") // 학기 식별자 초기화 (또는 적절한 초기 값으로 설정) + } + + fun resetTrackSelection() { + // 선택된 트랙 정보 초기화 + _track.postValue("") // 트랙 식별자 초기화 (또는 적절한 초기 값으로 설정) + } + + fun setHakki(hakki: String) { + _hakki.value = hakki + Log.d("hakki value", "setHakki 호출됨: hakki=$hakki") + } + + + fun setHakkiAndTrack(hakki: String, trackId: String) { + Log.d("hakkitrackvalue", "setHakkiAndTrack 호출됨: hakki=$hakki, trackId=$trackId") + _hakki.value = hakki + _track.value = trackId + } + private val _addTimeResponse = MutableLiveData() + val addTimeResponse: MutableLiveData = _addTimeResponse - fun getFreeInfo() { - planApiService.getFreeInfo().enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - if (response.body() != null) { - _planFreeInfo.postValue(response.body()) - Log.d("PlanFree", "${response.body()}") + fun addTime(request: AddTimeRequest) { + Log.d("gradesemester", "Sending AddTimeRequest with grade: ${request.semesterDto.grade}, semester: ${request.semesterDto.semester}") + planApiService.addTime(request).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + // 서버로부터 응답을 성공적으로 받았을 때 LiveData 업데이트 + Log.d("TimeTableApi", "getListTimeInfo 성공: ${response.body()}") + _addTimeResponse.postValue(response.body()) } else { - _error.postValue("서버 응답이 올바르지 않습니다.") - } - } else { - _error.postValue("사용자 정보를 가져오지 못했습니다.") - try { - throw response.errorBody()?.string()?.let { - RuntimeException(it) - } ?: RuntimeException("Unknown error") - } catch (e: Exception) { - Log.e("PlanInfo", "PlanResponse API 오류: ${e.message}") + // 에러 처리: 실패 응답 처리 + Log.e("TimeTableApi", "Error posting memo: ${response.errorBody()?.string()}") + _addTimeResponse.postValue(null) } } - } - override fun onFailure(call: Call, t: Throwable) { - _error.postValue("네트워크 오류: ${t.message}") - Log.d("gradInfo", "completion: ${t.message}") - } - }) - } + override fun onFailure(call: Call, t: Throwable) { + // 네트워크 에러 처리: LiveData 업데이트로 에러 상태 전달 가능 + _addTimeResponse.postValue(null) + } + }) + } + fun sendAddTimeRequest() { + val currentSelectedSubjects = _selectedTimeResults.value ?: return - fun getListTimeInfo(hakki: String, track: String) { - Log.d("PlanViewModel", "getListTimeInfo 호출됨: hakki=$hakki, track=$track") - planApiService.getListTime(hakki, track).enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful && response.body() != null) { - Log.d("PlanViewModel", "getListTimeInfo 성공: ${response.body()}") - _listTimeInfo.postValue(response.body()) - } else { - Log.e("PlanViewModel", "getListTimeInfo 실패: ${response.errorBody()?.string()}") - _error.postValue("리스트 정보를 가져오는데 실패했습니다.") - } - } + val grade = _grade.value + val semester = _semester.value + if (grade == null || semester == null) { - override fun onFailure(call: Call, t: Throwable) { - Log.e("PlanViewModel", "getListTimeInfo 네트워크 오류: ${t.message}") - _error.postValue("네트워크 오류: ${t.message}") + return + } else { + // 로그 출력: grade와 semester 값 로깅 + Log.d("gradesemester1", "Sending AddTimeRequest with grade: $grade, semester: $semester") } - }) - } + + val semesterDto = SemesterDto(grade = grade.toLong(), semester = semester.toLong()) + + val request = AddTimeRequest( + semesterDto = semesterDto, + subjectDtoList = currentSelectedSubjects.map { SubjectDtoList(type = it.type, name = it.name, credit = it.credit) } + ) + + addTime(request) + } - fun getLicenseInfo() { - planApiService.getUPlicense().enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - if (response.body() != null) { - _licenseInfo.postValue(response.body()) - Log.d("Planlicense", "${response.body()}") + + + + fun postMemo(memoRequest: PlanFreeRequest) { + planApiService.postFreeMemo(memoRequest).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + // API 호출 성공 시, 성공 LiveData 업데이트 + _postMemoResult.postValue(true) } else { - _error.postValue("서버 응답이 올바르지 않습니다.") + // 실패 시, 실패 LiveData 업데이트 + Log.e("PlanViewModel", "Error posting memo: ${response.errorBody()?.string()}") + _postMemoResult.postValue(false) } - } else { - _error.postValue("사용자 정보를 가져오지 못했습니다.") - try { - throw response.errorBody()?.string()?.let { - RuntimeException(it) - } ?: RuntimeException("Unknown error") - } catch (e: Exception) { - Log.e("PlanInfo", "PlanResponse API 오류: ${e.message}") + } + + override fun onFailure(call: Call, t: Throwable) { + // 네트워크 오류 등으로 호출 실패 시, 실패 LiveData 업데이트 + _postMemoResult.postValue(false) + } + }) + } + + + fun getFreeInfo() { + planApiService.getFreeInfo().enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + if (response.body() != null) { + _planFreeInfo.postValue(response.body()) + Log.d("PlanFree", "${response.body()}") + } else { + _error.postValue("서버 응답이 올바르지 않습니다.") + } + } else { + _error.postValue("사용자 정보를 가져오지 못했습니다.") + try { + throw response.errorBody()?.string()?.let { + RuntimeException(it) + } ?: RuntimeException("Unknown error") + } catch (e: Exception) { + Log.e("PlanInfo", "PlanResponse API 오류: ${e.message}") + } } } - } - override fun onFailure(call: Call, t: Throwable) { - _error.postValue("네트워크 오류: ${t.message}") - Log.d("gradInfo", "completion: ${t.message}") - } - }) - } + override fun onFailure(call: Call, t: Throwable) { + _error.postValue("네트워크 오류: ${t.message}") + Log.d("gradInfo", "completion: ${t.message}") + } + }) + } - fun saveLicense(request: List) { - - planApiService.saveLicense(request).enqueue(object : Callback { - override fun onResponse( - call: Call, response: Response - ) { - if (response.isSuccessful) { - _bringLicenseInfo.postValue(response.body()) - Log.d("PlanViewModel", "License saved successfully: ${response.body()}") - } else { - _error.postValue("자격증 정보 저장 실패: ${response.errorBody()?.string()}") - Log.e( - "PlanViewModel", - "Error saving license: ${response.errorBody()?.string()}" - ) + fun getListTimeInfo(hakki: String, track: String) { + Log.d("PlanViewModel", "getListTimeInfo 호출됨: hakki=$hakki, track=$track") + planApiService.getListTime(hakki, track).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful && response.body() != null) { + Log.d("PlanViewModel", "getListTimeInfo 성공: ${response.body()}") + _listTimeInfo.postValue(response.body()) + } else { + Log.e("PlanViewModel", "getListTimeInfo 실패: ${response.errorBody()?.string()}") + _error.postValue("리스트 정보를 가져오는데 실패했습니다.") + } } - } - override fun onFailure(call: Call, t: Throwable) { - _error.postValue("네트워크 오류: ${t.message}") - Log.e("PlanViewModel", "Network error: ${t.message}") - } - }) - } + override fun onFailure(call: Call, t: Throwable) { + Log.e("PlanViewModel", "getListTimeInfo 네트워크 오류: ${t.message}") + _error.postValue("네트워크 오류: ${t.message}") + } + }) + } + + + + fun getLicenseInfo() { + planApiService.getUPlicense().enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + if (response.body() != null) { + _licenseInfo.postValue(response.body()) + Log.d("Planlicense", "${response.body()}") + } else { + _error.postValue("서버 응답이 올바르지 않습니다.") + } + } else { + _error.postValue("사용자 정보를 가져오지 못했습니다.") + try { + throw response.errorBody()?.string()?.let { + RuntimeException(it) + } ?: RuntimeException("Unknown error") + } catch (e: Exception) { + Log.e("PlanInfo", "PlanResponse API 오류: ${e.message}") + } + } + } + + override fun onFailure(call: Call, t: Throwable) { + _error.postValue("네트워크 오류: ${t.message}") + Log.d("gradInfo", "completion: ${t.message}") + } + }) + } - fun getSemesterInfo() { - planApiService.getSemesterInfo().enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - if (response.body() != null) { - _planSemesterInfo.postValue(response.body()) - Log.d("PlanSemester", "${response.body()}") + fun saveLicense(request: List) { + + planApiService.saveLicense(request).enqueue(object : Callback { + override fun onResponse( + call: Call, response: Response + ) { + if (response.isSuccessful) { + _bringLicenseInfo.postValue(response.body()) + Log.d("PlanLicenseSave", "License saved successfully: ${response.body()}") } else { - _error.postValue("서버 응답이 올바르지 않습니다.") - } - } else { - _error.postValue("사용자 정보를 가져오지 못했습니다.") - try { - throw response.errorBody()?.string()?.let { - RuntimeException(it) - } ?: RuntimeException("Unknown error") - } catch (e: Exception) { - Log.e("PlanInfo", "PlanResponse API 오류: ${e.message}") + _error.postValue("자격증 정보 저장 실패: ${response.errorBody()?.string()}") + Log.e( + "PlanLicenseSave", + "Error saving license: ${response.errorBody()?.string()}" + ) } } - } - override fun onFailure(call: Call, t: Throwable) { - _error.postValue("네트워크 오류: ${t.message}") - Log.d("gradInfo", "completion: ${t.message}") - } - }) - } + override fun onFailure(call: Call, t: Throwable) { + _error.postValue("네트워크 오류: ${t.message}") + Log.e("PlanViewModel", "Network error: ${t.message}") + } + }) + } + + + fun getSemesterInfo() { + planApiService.getSemesterInfo().enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + if (response.body() != null) { + _planSemesterInfo.postValue(response.body()) + Log.d("PlanSemester", "${response.body()}") + } else { + _error.postValue("서버 응답이 올바르지 않습니다.") + } + } else { + _error.postValue("사용자 정보를 가져오지 못했습니다.") + try { + throw response.errorBody()?.string()?.let { + RuntimeException(it) + } ?: RuntimeException("Unknown error") + } catch (e: Exception) { + Log.e("PlanInfo", "PlanResponse API 오류: ${e.message}") + } + } + } + override fun onFailure(call: Call, t: Throwable) { + _error.postValue("네트워크 오류: ${t.message}") + Log.d("gradInfo", "completion: ${t.message}") + } + }) + } + + + fun getTrackInfo(hakki: String) { + planApiService.getTrackInfo(hakki).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + if (response.body() != null) { + _planTrackInfo.postValue(response.body()) + Log.d("PlanTrackInfo", "${response.body()}") + } else { + _error.postValue("서버 응답이 올바르지 않습니다.") + } + } else { + _error.postValue("사용자 정보를 가져오지 못했습니다.") + try { + throw response.errorBody()?.string()?.let { + RuntimeException(it) + } ?: RuntimeException("Unknown error") + } catch (e: Exception) { + Log.e("PlanInfo", "PlanResponse API 오류: ${e.message}") + } + } + } - fun getTrackInfo(hakki: String) { - planApiService.getTrackInfo(hakki).enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - if (response.body() != null) { - _planTrackInfo.postValue(response.body()) - Log.d("PlanTrackInfo", "${response.body()}") + override fun onFailure(call: Call, t: Throwable) { + _error.postValue("네트워크 오류: ${t.message}") + Log.d("gradInfo", "completion: ${t.message}") + } + }) + } + + + fun editMemo(memo: String) { + val editMemoRequest = EditMemoRequest(memo = memo) + planApiService.editMemo(editMemoRequest).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + Log.d("PlanMemoEdit", "Memo successfully edited: ${response.body()}") + // 필요한 경우, UI 업데이트를 위한 LiveData 업데이트 로직을 여기에 추가하세요. } else { - _error.postValue("서버 응답이 올바르지 않습니다.") + Log.e("PlanMemoEdit", "Failed to edit memo: ${response.errorBody()?.string()}") } - } else { - _error.postValue("사용자 정보를 가져오지 못했습니다.") - try { - throw response.errorBody()?.string()?.let { - RuntimeException(it) - } ?: RuntimeException("Unknown error") - } catch (e: Exception) { - Log.e("PlanInfo", "PlanResponse API 오류: ${e.message}") + } + + override fun onFailure(call: Call, t: Throwable) { + Log.e("PlanMemoEdit", "Network error on edit memo: ${t.message}") + } + }) + } + + fun certificateLicense(request: CertificateLicenseRequest) { + planApiService.certificateLicense(request).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + // 서버로부터 응답을 성공적으로 받았을 때 LiveData 업데이트 + _certificateResponse.postValue(response.body()) + Log.d("PlanViewModel", "Certificate License update success: ${response.body()}") + } else { + // 에러 처리: 실패 응답 처리 + _certificateResponse.postValue(null) + Log.e("PlanViewModel", "Failed to update certificate license: ${response.errorBody()?.string()}") } } - } - override fun onFailure(call: Call, t: Throwable) { - _error.postValue("네트워크 오류: ${t.message}") - Log.d("gradInfo", "completion: ${t.message}") - } - }) - } + override fun onFailure(call: Call, t: Throwable) { + // 네트워크 에러 처리: LiveData 업데이트로 에러 상태 전달 가능 + _certificateResponse.postValue(null) + Log.e("PlanViewModel", "Network error on certificate license update: ${t.message}") + } + }) + } + + + fun getTimeInfo(grade:Int,semester:Int) { + planApiService.getUptime(grade,semester).enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + if (response.body() != null) { + var timeList = response.body()!!.result + var itemList = ArrayList() + timeList.forEach{ + + itemList.add(TimeInfoResponse(it.type,it.name,it.credit.toString())) + } + _selectedTimeResults.postValue(itemList) + + Log.d("PlanUpTime", "${response.body()}") + } else { + _error.postValue("서버 응답이 올바르지 않습니다.") + } + } else { + _error.postValue("사용자 정보를 가져오지 못했습니다.") + try { + throw response.errorBody()?.string()?.let { + RuntimeException(it) + } ?: RuntimeException("Unknown error") + } catch (e: Exception) { + Log.e("PlanUpTime", "PlanResponse API 오류: ${e.message}") + } + } + } + override fun onFailure(call: Call, t: Throwable) { + _error.postValue("네트워크 오류: ${t.message}") + Log.d("gradInfo", "completion: ${t.message}") + } + }) + } + + fun deleteLicense(certificateId: Long) { + planApiService.deleteLicense(certificateId).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + // 삭제 요청이 성공적으로 처리된 경우 + Log.d("DeleteLicense", "License deleted successfully") + // 여기에 필요한 처리를 추가하세요. + } else { + // 삭제 요청이 실패한 경우 + val errorMessage = response.errorBody()?.string() ?: "Unknown error" + Log.e("DeleteLicense", "Failed to delete license: $errorMessage") + // 여기에 필요한 처리를 추가하세요. + } + } - fun editMemo(memo: String) { - val editMemoRequest = EditMemoRequest(memo = memo) - planApiService.editMemo(editMemoRequest).enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - Log.d("PlanMemoEdit", "Memo successfully edited: ${response.body()}") - // 필요한 경우, UI 업데이트를 위한 LiveData 업데이트 로직을 여기에 추가하세요. - } else { - Log.e("PlanMemoEdit", "Failed to edit memo: ${response.errorBody()?.string()}") + override fun onFailure(call: Call, t: Throwable) { + // 네트워크 오류 등으로 요청이 실패한 경우 + Log.e("DeleteLicense", "Network error: ${t.message}") + // 여기에 필요한 처리를 추가하세요. } - } + }) + } - override fun onFailure(call: Call, t: Throwable) { - Log.e("PlanMemoEdit", "Network error on edit memo: ${t.message}") - } - }) - } -} + + } diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanlicenseFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanlicenseFragment.kt index 0a8dde84..662b3f8e 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanlicenseFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanlicenseFragment.kt @@ -27,13 +27,8 @@ class PlanlicenseFragment : Fragment() { ): View { _binding = FragmentPlanlicenseBinding.inflate(inflater, container, false) - - viewModel.getLicenseInfo() // api 연결 - - - // UPlicenseResponse-자격증 정보 불러오기 viewModel.licenseInfo.observe(viewLifecycleOwner) { licenseInfo -> licenseInfo?.result?.let { resultList -> @@ -64,10 +59,10 @@ class PlanlicenseFragment : Fragment() { } } - return binding.root } + private fun submitData() { val name = binding.planLicenseName.text.toString() @@ -78,14 +73,13 @@ class PlanlicenseFragment : Fragment() { // SavelicenseRequest 객체 생성 - // API 호출 viewModel.saveLicense(saveInfoList) } - private fun setupEditTextListener(){ + private fun setupEditTextListener() { val textWatcher = object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { // 필요 없음 @@ -112,9 +106,6 @@ class PlanlicenseFragment : Fragment() { val colorResId = if (isAnyFieldFilled) R.color.skyBlue else R.color.gray val color = ContextCompat.getColor(requireContext(), colorResId) binding.licenseButtonStore.backgroundTintList = ColorStateList.valueOf(color) - - - } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -124,16 +115,21 @@ class PlanlicenseFragment : Fragment() { binding.licenseButtonStore.setOnClickListener { submitData() // 사용자 입력을 기반으로 API 호출 } + binding.licenseDeleteButton.setOnClickListener { + deleteLicense() // 삭제 API 호출 + } + } + private fun deleteLicense() { + // 삭제할 자격증 ID + val certificateId = 1 // 예시로 1을 사용하였습니다. 실제로는 삭제할 자격증의 ID를 전달해야 합니다. - - - + // API 호출 +// viewModel.deleteLicense(certificateId) } override fun onDestroyView() { super.onDestroyView() _binding = null } -} - +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_planlicense.xml b/app/src/main/res/layout/fragment_planlicense.xml index 00568ddb..2135eaa0 100644 --- a/app/src/main/res/layout/fragment_planlicense.xml +++ b/app/src/main/res/layout/fragment_planlicense.xml @@ -5,10 +5,12 @@ xmlns:tools="http://schemas.android.com/tools"> + + @@ -17,15 +19,15 @@ android:id="@+id/license_const_layout" android:layout_width="322dp" android:layout_height="223dp" + android:layout_marginTop="29dp" android:background="@drawable/rectangle_4257" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - android:paddingTop="10dp" android:paddingLeft="8dp" + android:paddingTop="10dp" android:paddingRight="9dp" android:paddingBottom="10dp" - android:layout_marginTop="29dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" > @@ -36,10 +38,10 @@ android:background="@drawable/edittext_rounded_line" android:padding="16dp" app:columnCount="2" - app:rowCount="5" - app:layout_constraintTop_toTopOf="@id/license_const_layout" - app:layout_constraintStart_toStartOf="@id/license_const_layout" app:layout_constraintEnd_toEndOf="@id/license_const_layout" + app:layout_constraintStart_toStartOf="@id/license_const_layout" + app:layout_constraintTop_toTopOf="@id/license_const_layout" + app:rowCount="5" tools:layout_editor_absoluteX="11dp" tools:layout_editor_absoluteY="4dp"> @@ -66,106 +68,103 @@ android:text="시험 일정" app:layout_columnWeight="1" app:layout_gravity="fill" - app:layout_rowWeight="1" - /> + app:layout_rowWeight="1" /> + app:layout_rowWeight="1" /> + app:layout_rowWeight="1" /> + app:layout_rowWeight="1" /> + app:layout_rowWeight="1" /> + app:layout_rowWeight="1" /> + app:layout_rowWeight="1" /> + app:layout_rowWeight="1" /> + app:layout_rowWeight="1" /> @@ -173,14 +172,27 @@ + + - - - - - - - - - - - - - - - + + + + android:layout_marginTop="54dp" + android:layout_marginBottom="40dp" + style="@style/BoldFont.20" + android:textColor="@color/black" - - - - + /> + - - - - + app:layout_constraintTop_toTopOf="parent" + /> - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/app/src/main/res/layout/plan_time_tab_main.xml b/app/src/main/res/layout/plan_time_tab_main.xml index e93e983c..7de324cd 100644 --- a/app/src/main/res/layout/plan_time_tab_main.xml +++ b/app/src/main/res/layout/plan_time_tab_main.xml @@ -18,6 +18,17 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + android:id="@+id/action_fragment_home_to_planTimetableFragment" + app:destination="@id/planTimetableFragment" /> - + android:label="PlanTimetableFragment" > + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 82b382c3..d66f3e2a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,6 +15,17 @@ 자격증 이름 + + 1학년 1학기 + 1학년 2학기 + 2학년 1학기 + 2학년 2학기 + 3학년 1학기 + 3학년 2학기 + 4학년 1학기 + 4학년 2학기 + + 졸업 예정일 0000년 00월 00일 From b404f7a5be624b2a70d4b1190fecff82993142f3 Mon Sep 17 00:00:00 2001 From: dkyuuum Date: Tue, 20 Feb 2024 18:15:19 +0900 Subject: [PATCH 2/3] =?UTF-8?q?Fix:=20=ED=96=A5=ED=9B=84=EA=B3=84=ED=9A=8D?= =?UTF-8?q?/=EC=8B=9C=EA=B0=84=ED=91=9C=20=ED=83=AD=20=EC=A0=84=ED=99=98?= =?UTF-8?q?=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/ui/plan/PlanTimetableFragment.kt | 208 +++++++++--------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt index a4135379..8db4a10f 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt @@ -17,157 +17,157 @@ import umc.com.mobile.project.ui.common.NavigationUtil.navigate class PlanTimetableFragment : Fragment() { - private var _binding: PlanTimeMainBinding? = null - private val binding get() = _binding!! - private val viewModel: PlanViewModel by activityViewModels() - private lateinit var adapter: PlanTimeAdapter - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = PlanTimeMainBinding.inflate(inflater, container, false) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setupRecyclerView() - observeSelectedTimeResults() - - - val spinner = binding.spinnerPlanTimeTrackSemester - val adapter = ArrayAdapter.createFromResource( - requireContext(), - R.array.semester_options, - android.R.layout.simple_spinner_item - ) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = adapter - - // 선택한 항목 리스너 추가 (필요한 경우) - - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected( - parent: AdapterView<*>?, - view: View?, - position: Int, - id: Long - ) { - val selectedItem = parent?.getItemAtPosition(position).toString() - when (selectedItem) { - "1학년 1학기" -> { - viewModel.setGradeAndSemester(1, 1) + private var _binding: PlanTimeMainBinding? = null + private val binding get() = _binding!! + private val viewModel: PlanViewModel by activityViewModels() + private lateinit var adapter: PlanTimeAdapter + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = PlanTimeMainBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupRecyclerView() + observeSelectedTimeResults() + + + val spinner = binding.spinnerPlanTimeTrackSemester + val adapter = ArrayAdapter.createFromResource( + requireContext(), + R.array.semester_options, + android.R.layout.simple_spinner_item + ) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + spinner.adapter = adapter + + // 선택한 항목 리스너 추가 (필요한 경우) + + spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { + val selectedItem = parent?.getItemAtPosition(position).toString() + when (selectedItem) { + "1학년 1학기" -> { + viewModel.setGradeAndSemester(1, 1) // viewModel.getTimeInfo(1, 1) - } + } - "1학년 2학기" -> { - viewModel.setGradeAndSemester(1, 2) + "1학년 2학기" -> { + viewModel.setGradeAndSemester(1, 2) // viewModel.getTimeInfo(1, 2) - } + } - "2학년 1학기" -> { - viewModel.setGradeAndSemester(2, 1) + "2학년 1학기" -> { + viewModel.setGradeAndSemester(2, 1) // viewModel.getTimeInfo(2, 1) - } + } - "2학년 2학기" -> { - viewModel.setGradeAndSemester(2, 2) + "2학년 2학기" -> { + viewModel.setGradeAndSemester(2, 2) // viewModel.getTimeInfo(2, 2) - } + } - "3학년 1학기" -> { - viewModel.setGradeAndSemester(3, 1) + "3학년 1학기" -> { + viewModel.setGradeAndSemester(3, 1) // viewModel.getTimeInfo(3, 1) - } + } - "3학년 2학기" -> { - viewModel.setGradeAndSemester(3, 2) + "3학년 2학기" -> { + viewModel.setGradeAndSemester(3, 2) // viewModel.getTimeInfo(3, 2) - } + } - "4학년 1학기" -> { - viewModel.setGradeAndSemester(4, 1) + "4학년 1학기" -> { + viewModel.setGradeAndSemester(4, 1) // viewModel.getTimeInfo(4, 1) - } + } - "4학년 2학기" -> { - viewModel.setGradeAndSemester(4, 2) + "4학년 2학기" -> { + viewModel.setGradeAndSemester(4, 2) // viewModel.getTimeInfo(4, 2) - } + } - } + } - } + } - override fun onNothingSelected(parent: AdapterView<*>?) { - // 아무 것도 선택되지 않은 경우의 동작 구현 - } - } - binding.timeStoreButton.setOnClickListener { - // grade와 semester가 선택되었는지 확인 - val grade = viewModel.grade.value - val semester = viewModel.semester.value + override fun onNothingSelected(parent: AdapterView<*>?) { + // 아무 것도 선택되지 않은 경우의 동작 구현 + } + } + binding.timeStoreButton.setOnClickListener { + // grade와 semester가 선택되었는지 확인 + val grade = viewModel.grade.value + val semester = viewModel.semester.value - if (grade == null || semester == null) { - // 학년 또는 학기가 선택되지 않았다면 토스트 메시지 표시 - Toast.makeText(context, "학년과 학기를 선택해주세요.", Toast.LENGTH_SHORT).show() - } else { - // 선택된 경우에만 서버로 데이터 전송 처리 - viewModel.sendAddTimeRequest() - viewModel.getTimeInfo(grade, semester) - } - } + if (grade == null || semester == null) { + // 학년 또는 학기가 선택되지 않았다면 토스트 메시지 표시 + Toast.makeText(context, "학년과 학기를 선택해주세요.", Toast.LENGTH_SHORT).show() + } else { + // 선택된 경우에만 서버로 데이터 전송 처리 + viewModel.sendAddTimeRequest() + viewModel.getTimeInfo(grade, semester) + } + } - binding.titleMoveTimetable.setOnClickListener { - navigate(R.id.action_fragment_home_to_planTimetableFragment) + binding.titleMoveTimetable.setOnClickListener { + navigate(R.id.action_planTimetableFragment_to_planSettingFragment) - } + } - } + } - private fun observeSelectedTimeResults() { - viewModel.selectedTimeResults.observe(viewLifecycleOwner) { selectedTimeResults -> - (binding.recyclerView.adapter as PlanTimeAdapter).updateTimeList(selectedTimeResults) - } - } + private fun observeSelectedTimeResults() { + viewModel.selectedTimeResults.observe(viewLifecycleOwner) { selectedTimeResults -> + (binding.recyclerView.adapter as PlanTimeAdapter).updateTimeList(selectedTimeResults) + } + } - // 추가하기 버튼으로 시간표에 과목 업데이트 - private fun setupRecyclerView() { - // 초기 데이터 리스트를 비어 있는 리스트로 설정합니다. - // 데이터가 준비되면, 나중에 observeSelectedTimeResults 함수 내에서 submitList를 통해 업데이트합니다. - adapter = PlanTimeAdapter(emptyList()) - binding.recyclerView.layoutManager = LinearLayoutManager(context) - binding.recyclerView.adapter = adapter - } + // 추가하기 버튼으로 시간표에 과목 업데이트 + private fun setupRecyclerView() { + // 초기 데이터 리스트를 비어 있는 리스트로 설정합니다. + // 데이터가 준비되면, 나중에 observeSelectedTimeResults 함수 내에서 submitList를 통해 업데이트합니다. + adapter = PlanTimeAdapter(emptyList()) + binding.recyclerView.layoutManager = LinearLayoutManager(context) + binding.recyclerView.adapter = adapter + } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } From 61315a6a9297f893af7298fd11805672ce211fce Mon Sep 17 00:00:00 2001 From: dkyuuum Date: Tue, 20 Feb 2024 19:57:14 +0900 Subject: [PATCH 3/3] =?UTF-8?q?Fix:=20=ED=96=A5=ED=9B=84=EA=B3=84=ED=9A=8D?= =?UTF-8?q?/=EC=8B=9C=EA=B0=84=ED=91=9C=20=ED=83=AD=20=EC=A0=84=ED=99=98?= =?UTF-8?q?=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/data/network/api/PlanApi.kt | 19 +- .../mobile/project/ui/home/HomeFragment.kt | 2 +- .../project/ui/plan/PlanTimetableFragment.kt | 208 ++++++------- .../mobile/project/ui/plan/PlanViewModel.kt | 30 +- .../project/ui/plan/PlanlicenseFragment.kt | 282 +++++++++++------- .../main/res/layout/fragment_planlicense.xml | 117 ++++---- app/src/main/res/values/strings.xml | 3 + 7 files changed, 373 insertions(+), 288 deletions(-) diff --git a/app/src/main/java/umc/com/mobile/project/data/network/api/PlanApi.kt b/app/src/main/java/umc/com/mobile/project/data/network/api/PlanApi.kt index 6c8157c9..ad4ac32d 100644 --- a/app/src/main/java/umc/com/mobile/project/data/network/api/PlanApi.kt +++ b/app/src/main/java/umc/com/mobile/project/data/network/api/PlanApi.kt @@ -29,9 +29,13 @@ interface PlanApi { @GET("plans/certifications") fun getUPlicense(): Call + @POST("plans/certifications") fun saveLicense(@Body request: List): Call + + + @GET("/plans/timetable/searchSubject") fun getListTime(@Query("hakki") hakki:String, @Query("track") track : String) : Call @@ -51,14 +55,25 @@ interface PlanApi { fun postFreeMemo(@Body request: PlanFreeRequest): Call @GET("/plans/timetable") - fun getUptime(@Query("grade") grade:Int, @Query("semseter") semester : Int):Call + fun getUptime(@Query("grade") grade:Int, @Query("semester") semester : Int):Call @PATCH("/plans/memo") fun editMemo(@Body editMemoRequest: EditMemoRequest) : Call @PATCH("/plans/certifications") - fun certificateLicense(@Body request: CertificateLicenseRequest) : Call + fun certificateLicense(@Body request: List) : Call @DELETE("/plans/certifications") fun deleteLicense(@Query("certificateId") certificateId: Long): Call + + + + + + + + + + + } \ No newline at end of file diff --git a/app/src/main/java/umc/com/mobile/project/ui/home/HomeFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/home/HomeFragment.kt index 46dee1e4..bf637b67 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/home/HomeFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/home/HomeFragment.kt @@ -56,7 +56,7 @@ class HomeFragment : Fragment() { // 페이지 이동 private fun navigateFragment() { binding.btnCheeringWordMove.setOnClickListener { - navigate(R.id.action_fragment_home_to_planTimetableFragment) + navigate(R.id.action_fragment_home_to_fragment_date) } binding.layoutNextPlan.setOnClickListener { navigate(R.id.action_fragment_home_to_planTimetableFragment) diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt index 8db4a10f..88c97d42 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanTimetableFragment.kt @@ -1,6 +1,7 @@ package umc.com.mobile.project.ui.plan import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -17,157 +18,158 @@ import umc.com.mobile.project.ui.common.NavigationUtil.navigate class PlanTimetableFragment : Fragment() { - private var _binding: PlanTimeMainBinding? = null - private val binding get() = _binding!! - private val viewModel: PlanViewModel by activityViewModels() - private lateinit var adapter: PlanTimeAdapter + private var _binding: PlanTimeMainBinding? = null + private val binding get() = _binding!! + private val viewModel: PlanViewModel by activityViewModels() + private lateinit var adapter: PlanTimeAdapter - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = PlanTimeMainBinding.inflate(inflater, container, false) - return binding.root - } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = PlanTimeMainBinding.inflate(inflater, container, false) + return binding.root + } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setupRecyclerView() - observeSelectedTimeResults() + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupRecyclerView() + observeSelectedTimeResults() - val spinner = binding.spinnerPlanTimeTrackSemester - val adapter = ArrayAdapter.createFromResource( - requireContext(), - R.array.semester_options, - android.R.layout.simple_spinner_item - ) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = adapter + val spinner = binding.spinnerPlanTimeTrackSemester + val adapter = ArrayAdapter.createFromResource( + requireContext(), + R.array.semester_options, + android.R.layout.simple_spinner_item + ) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + spinner.adapter = adapter - // 선택한 항목 리스너 추가 (필요한 경우) + // 선택한 항목 리스너 추가 (필요한 경우) - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected( - parent: AdapterView<*>?, - view: View?, - position: Int, - id: Long - ) { - val selectedItem = parent?.getItemAtPosition(position).toString() - when (selectedItem) { - "1학년 1학기" -> { - viewModel.setGradeAndSemester(1, 1) -// viewModel.getTimeInfo(1, 1) + spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>?, + view: View?, + position: Int, + id: Long + ) { + val selectedItem = parent?.getItemAtPosition(position).toString() + when (selectedItem) { + "1학년 1학기" -> { + viewModel.setGradeAndSemester(1, 1) + viewModel.getTimeInfo(1, 1) + Log.d("selected Item",selectedItem) - } + } - "1학년 2학기" -> { - viewModel.setGradeAndSemester(1, 2) -// viewModel.getTimeInfo(1, 2) + "1학년 2학기" -> { + viewModel.setGradeAndSemester(1, 2) + viewModel.getTimeInfo(1, 2) - } + } - "2학년 1학기" -> { - viewModel.setGradeAndSemester(2, 1) -// viewModel.getTimeInfo(2, 1) + "2학년 1학기" -> { + viewModel.setGradeAndSemester(2, 1) + viewModel.getTimeInfo(2, 1) - } + } - "2학년 2학기" -> { - viewModel.setGradeAndSemester(2, 2) -// viewModel.getTimeInfo(2, 2) + "2학년 2학기" -> { + viewModel.setGradeAndSemester(2, 2) + viewModel.getTimeInfo(2, 2) - } + } - "3학년 1학기" -> { - viewModel.setGradeAndSemester(3, 1) -// viewModel.getTimeInfo(3, 1) + "3학년 1학기" -> { + viewModel.setGradeAndSemester(3, 1) + viewModel.getTimeInfo(3, 1) - } + } - "3학년 2학기" -> { - viewModel.setGradeAndSemester(3, 2) + "3학년 2학기" -> { + viewModel.setGradeAndSemester(3, 2) // viewModel.getTimeInfo(3, 2) - } + } - "4학년 1학기" -> { - viewModel.setGradeAndSemester(4, 1) + "4학년 1학기" -> { + viewModel.setGradeAndSemester(4, 1) // viewModel.getTimeInfo(4, 1) - } + } - "4학년 2학기" -> { - viewModel.setGradeAndSemester(4, 2) + "4학년 2학기" -> { + viewModel.setGradeAndSemester(4, 2) // viewModel.getTimeInfo(4, 2) - } + } - } + } - } + } - override fun onNothingSelected(parent: AdapterView<*>?) { - // 아무 것도 선택되지 않은 경우의 동작 구현 - } - } - binding.timeStoreButton.setOnClickListener { - // grade와 semester가 선택되었는지 확인 - val grade = viewModel.grade.value - val semester = viewModel.semester.value + override fun onNothingSelected(parent: AdapterView<*>?) { + // 아무 것도 선택되지 않은 경우의 동작 구현 + } + } + binding.timeStoreButton.setOnClickListener { + // grade와 semester가 선택되었는지 확인 + val grade = viewModel.grade.value + val semester = viewModel.semester.value - if (grade == null || semester == null) { - // 학년 또는 학기가 선택되지 않았다면 토스트 메시지 표시 - Toast.makeText(context, "학년과 학기를 선택해주세요.", Toast.LENGTH_SHORT).show() - } else { - // 선택된 경우에만 서버로 데이터 전송 처리 - viewModel.sendAddTimeRequest() - viewModel.getTimeInfo(grade, semester) - } - } + if (grade == null || semester == null) { + // 학년 또는 학기가 선택되지 않았다면 토스트 메시지 표시 + Toast.makeText(context, "학년과 학기를 선택해주세요.", Toast.LENGTH_SHORT).show() + } else { + // 선택된 경우에만 서버로 데이터 전송 처리 + viewModel.sendAddTimeRequest() + viewModel.getTimeInfo(grade, semester) + } + } - binding.titleMoveTimetable.setOnClickListener { - navigate(R.id.action_planTimetableFragment_to_planSettingFragment) + binding.titleMoveTimetable.setOnClickListener { + navigate(R.id.action_planTimetableFragment_to_planSettingFragment) - } + } - } + } - private fun observeSelectedTimeResults() { - viewModel.selectedTimeResults.observe(viewLifecycleOwner) { selectedTimeResults -> - (binding.recyclerView.adapter as PlanTimeAdapter).updateTimeList(selectedTimeResults) - } - } + private fun observeSelectedTimeResults() { + viewModel.selectedTimeResults.observe(viewLifecycleOwner) { selectedTimeResults -> + (binding.recyclerView.adapter as PlanTimeAdapter).updateTimeList(selectedTimeResults) + } + } - // 추가하기 버튼으로 시간표에 과목 업데이트 - private fun setupRecyclerView() { - // 초기 데이터 리스트를 비어 있는 리스트로 설정합니다. - // 데이터가 준비되면, 나중에 observeSelectedTimeResults 함수 내에서 submitList를 통해 업데이트합니다. - adapter = PlanTimeAdapter(emptyList()) - binding.recyclerView.layoutManager = LinearLayoutManager(context) - binding.recyclerView.adapter = adapter - } + // 추가하기 버튼으로 시간표에 과목 업데이트 + private fun setupRecyclerView() { + // 초기 데이터 리스트를 비어 있는 리스트로 설정합니다. + // 데이터가 준비되면, 나중에 observeSelectedTimeResults 함수 내에서 submitList를 통해 업데이트합니다. + adapter = PlanTimeAdapter(emptyList()) + binding.recyclerView.layoutManager = LinearLayoutManager(context) + binding.recyclerView.adapter = adapter + } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanViewModel.kt index 1d9b3853..bb40ddd6 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanViewModel.kt @@ -26,11 +26,9 @@ import umc.com.mobile.project.data.model.plan.SemesterTimeResponse import umc.com.mobile.project.data.model.plan.SubjectDtoList import umc.com.mobile.project.data.model.plan.TimeInfoResponse - import umc.com.mobile.project.data.model.plan.TimeResult import umc.com.mobile.project.data.model.plan.UPlicenseResponse import umc.com.mobile.project.data.model.plan.UpTimeResponse - import umc.com.mobile.project.data.model.plan.upTimeResult import umc.com.mobile.project.data.network.ApiClient import umc.com.mobile.project.data.network.api.PlanApi @@ -179,12 +177,13 @@ val addTimeResponse: MutableLiveData = _addTimeResponse fun addTime(request: AddTimeRequest) { - Log.d("gradesemester", "Sending AddTimeRequest with grade: ${request.semesterDto.grade}, semester: ${request.semesterDto.semester}") + planApiService.addTime(request).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { // 서버로부터 응답을 성공적으로 받았을 때 LiveData 업데이트 Log.d("TimeTableApi", "getListTimeInfo 성공: ${response.body()}") + Log.d("gradesemester", "Sending AddTimeRequest with grade: ${request.semesterDto.grade}, semester: ${request.semesterDto.semester}") _addTimeResponse.postValue(response.body()) } else { // 에러 처리: 실패 응답 처리 @@ -340,6 +339,8 @@ } + + fun saveLicense(request: List) { planApiService.saveLicense(request).enqueue(object : Callback { @@ -453,7 +454,7 @@ }) } - fun certificateLicense(request: CertificateLicenseRequest) { + fun certificateLicense(request: List) { planApiService.certificateLicense(request).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { @@ -476,7 +477,8 @@ } - fun getTimeInfo(grade:Int,semester:Int) { + + fun getTimeInfo(grade:Int, semester:Int) { planApiService.getUptime(grade,semester).enqueue(object : Callback { override fun onResponse( call: Call, @@ -484,16 +486,18 @@ ) { if (response.isSuccessful) { if (response.body() != null) { - var timeList = response.body()!!.result - var itemList = ArrayList() - timeList.forEach{ - + val timeList = response.body()!!.result + val itemList = ArrayList() + timeList.forEach { itemList.add(TimeInfoResponse(it.type,it.name,it.credit.toString())) } - _selectedTimeResults.postValue(itemList) + _selectedTimeResults.value = itemList + + Log.d("PlanUpTime1", "TimeInfoResponse: $timeList") Log.d("PlanUpTime", "${response.body()}") } else { + Log.d("PlanUpTime", "${response.body()}") _error.postValue("서버 응답이 올바르지 않습니다.") } } else { @@ -503,18 +507,20 @@ RuntimeException(it) } ?: RuntimeException("Unknown error") } catch (e: Exception) { - Log.e("PlanUpTime", "PlanResponse API 오류: ${e.message}") + Log.e("PlanViewModel", "Failed to get time info: ${response.errorBody()?.string()}") + } } } override fun onFailure(call: Call, t: Throwable) { _error.postValue("네트워크 오류: ${t.message}") - Log.d("gradInfo", "completion: ${t.message}") + Log.d("PlanUpTime12", "Network error: ${t.message}") } }) } + fun deleteLicense(certificateId: Long) { planApiService.deleteLicense(certificateId).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { diff --git a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanlicenseFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanlicenseFragment.kt index 662b3f8e..94602daa 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/plan/PlanlicenseFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/plan/PlanlicenseFragment.kt @@ -13,123 +13,181 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import umc.com.mobile.project.R +import umc.com.mobile.project.data.model.plan.CertificateLicenseRequest import umc.com.mobile.project.databinding.FragmentPlanlicenseBinding class PlanlicenseFragment : Fragment() { - private var _binding: FragmentPlanlicenseBinding? = null - private val viewModel: PlanViewModel by activityViewModels() - private val binding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = FragmentPlanlicenseBinding.inflate(inflater, container, false) - - viewModel.getLicenseInfo() // api 연결 - - // UPlicenseResponse-자격증 정보 불러오기 - viewModel.licenseInfo.observe(viewLifecycleOwner) { licenseInfo -> - licenseInfo?.result?.let { resultList -> - // 첫 번째 Result 객체에 접근하여 데이터 매핑 - resultList.getOrNull(0)?.let { firstResult -> - binding.planLicenseName.setText(firstResult.name) - binding.planLicenseDate.setText(firstResult.date) - } - - // 두 번째 Result 객체에 접근하여 데이터 매핑 - resultList.getOrNull(1)?.let { secondResult -> - binding.planLicenseName2.setText(secondResult.name) - binding.planLicenseDate2.setText(secondResult.date) - - } - - resultList.getOrNull(2)?.let { thirdResult -> - binding.planLicenseName3.setText(thirdResult.name) - binding.planLicenseDate3.setText(thirdResult.date) - - - } - - resultList.getOrNull(3)?.let { fourthResult -> - binding.planLicenseName4.setText(fourthResult.name) - binding.planLicenseDate4.setText(fourthResult.date) - } - } - } - - return binding.root - } - - - private fun submitData() { - - val name = binding.planLicenseName.text.toString() - val date = binding.planLicenseDate.text.toString() - - // SaveInfo 객체 리스트 생성 - val saveInfoList = listOf(SaveInfo(name, date)) - - // SavelicenseRequest 객체 생성 - - // API 호출 - viewModel.saveLicense(saveInfoList) - - } - - - private fun setupEditTextListener() { - val textWatcher = object : TextWatcher { - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { - // 필요 없음 - } - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - // 입력이 변경될 때마다 호출됩니다. - checkIfAnyInputIsFilled() - } - - override fun afterTextChanged(s: Editable?) { - // 필요 없음 - } - } - binding.planLicenseName.addTextChangedListener(textWatcher) - } - - private fun checkIfAnyInputIsFilled() { - val isAnyFieldFilled = binding.planLicenseName.text.trim().isNotEmpty() - //버튼 활성화 업데이트 - binding.licenseButtonStore.isEnabled = isAnyFieldFilled - - // 버튼 색상도 업데이트 - val colorResId = if (isAnyFieldFilled) R.color.skyBlue else R.color.gray - val color = ContextCompat.getColor(requireContext(), colorResId) - binding.licenseButtonStore.backgroundTintList = ColorStateList.valueOf(color) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setupEditTextListener() - checkIfAnyInputIsFilled() // 초기 상태 확인 - binding.licenseButtonStore.setOnClickListener { - submitData() // 사용자 입력을 기반으로 API 호출 - } - binding.licenseDeleteButton.setOnClickListener { - deleteLicense() // 삭제 API 호출 - } - } + private var _binding: FragmentPlanlicenseBinding? = null + private val viewModel: PlanViewModel by activityViewModels() + private val binding get() = _binding!! + private var edit:Boolean=false - private fun deleteLicense() { - // 삭제할 자격증 ID - val certificateId = 1 // 예시로 1을 사용하였습니다. 실제로는 삭제할 자격증의 ID를 전달해야 합니다. + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentPlanlicenseBinding.inflate(inflater, container, false) + binding.licenseCertificateButton.setOnClickListener { + if(edit){ + var licenseList=ArrayList() // 빈 배열만듦 + viewModel.licenseInfo.value?.result?.get(0)?.certificateId?.let { it1 -> + CertificateLicenseRequest( + it1, + binding.planLicenseName.text.toString(),binding.planLicenseDate.text.toString()) + }?.let { it2 -> licenseList.add(it2) } - // API 호출 + viewModel.licenseInfo.value?.result?.get(1)?.certificateId?.let { it1 -> + CertificateLicenseRequest( + it1, + binding.planLicenseName2.text.toString(),binding.planLicenseDate2.text.toString()) + }?.let { it2 -> licenseList.add(it2) } + + + viewModel.licenseInfo.value?.result?.get(2)?.certificateId?.let { it1 -> + CertificateLicenseRequest( + it1, + binding.planLicenseName3.text.toString(),binding.planLicenseDate3.text.toString()) + }?.let { it2 -> licenseList.add(it2) } + + viewModel.licenseInfo.value?.result?.get(3)?.certificateId?.let { it1 -> + CertificateLicenseRequest( + it1, + binding.planLicenseName4.text.toString(),binding.planLicenseDate4.text.toString()) + }?.let { it2 -> licenseList.add(it2) } + + + + + + viewModel.certificateLicense(licenseList) + + + } + } + + + + viewModel.getLicenseInfo() // api 연결 + + + + + // UPlicenseResponse-자격증 정보 불러오기 + viewModel.licenseInfo.observe(viewLifecycleOwner) { licenseInfo -> + licenseInfo?.result?.let { resultList -> + if (resultList.isNotEmpty()) { + resultList.forEachIndexed { index, result -> + when (index) { + 0 -> { + binding.planLicenseName.setText(result.name) + binding.planLicenseDate.setText(result.date) + + } + 1 -> { + binding.planLicenseName2.setText(result.name) + binding.planLicenseDate2.setText(result.date) + + } + 2 -> { + binding.planLicenseName3.setText(result.name) + binding.planLicenseDate3.setText(result.date) + + } + 3 -> { + binding.planLicenseName4.setText(result.name) + binding.planLicenseDate4.setText(result.date) + + } + } + } + setupEditTextListeners() + } + } + } + + return binding.root + } + + + private fun submitData() { + + val name = binding.planLicenseName.text.toString() + val date = binding.planLicenseDate.text.toString() + + // SaveInfo 객체 리스트 생성 + val saveInfoList = listOf(SaveInfo(name, date)) + + // SavelicenseRequest 객체 생성 + + + // API 호출 + viewModel.saveLicense(saveInfoList) + + } + + + + private fun setupEditTextListeners() { + + binding.planLicenseName.addTextChangedListener(createTextWatcher()) + binding.planLicenseName2.addTextChangedListener(createTextWatcher()) + binding.planLicenseName3.addTextChangedListener(createTextWatcher()) + binding.planLicenseName4.addTextChangedListener(createTextWatcher()) + } + private fun createTextWatcher(): TextWatcher { + return object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + edit=true + + } + override fun afterTextChanged(s: Editable?) {} + } + } + private fun checkIfAnyInputIsFilled() { + val isAnyFieldFilled = binding.planLicenseName.text.trim().isNotEmpty() + //버튼 활성화 업데이트 + binding.licenseButtonStore.isEnabled = isAnyFieldFilled + + // 버튼 색상도 업데이트 + val colorResId = if (isAnyFieldFilled) R.color.skyBlue else R.color.gray + val color = ContextCompat.getColor(requireContext(), colorResId) + binding.licenseButtonStore.backgroundTintList = ColorStateList.valueOf(color) + + + + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupEditTextListeners() + checkIfAnyInputIsFilled() // 초기 상태 확인 + binding.licenseButtonStore.setOnClickListener { + submitData() // 사용자 입력을 기반으로 API 호출 + } + + + + + + + + + + + + } + private fun deleteLicense() { + // 삭제할 자격증 ID + val certificateId = 1 // 예시로 1을 사용하였습니다. 실제로는 삭제할 자격증의 ID를 전달해야 합니다. + + // API 호출 // viewModel.deleteLicense(certificateId) - } + } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_planlicense.xml b/app/src/main/res/layout/fragment_planlicense.xml index 2135eaa0..54274974 100644 --- a/app/src/main/res/layout/fragment_planlicense.xml +++ b/app/src/main/res/layout/fragment_planlicense.xml @@ -5,12 +5,10 @@ xmlns:tools="http://schemas.android.com/tools"> - - @@ -19,15 +17,15 @@ android:id="@+id/license_const_layout" android:layout_width="322dp" android:layout_height="223dp" - android:layout_marginTop="29dp" android:background="@drawable/rectangle_4257" - android:paddingLeft="8dp" - android:paddingTop="10dp" - android:paddingRight="9dp" - android:paddingBottom="10dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" + android:paddingTop="10dp" + android:paddingLeft="8dp" + android:paddingRight="9dp" + android:paddingBottom="10dp" + android:layout_marginTop="29dp" > @@ -38,29 +36,29 @@ android:background="@drawable/edittext_rounded_line" android:padding="16dp" app:columnCount="2" - app:layout_constraintEnd_toEndOf="@id/license_const_layout" - app:layout_constraintStart_toStartOf="@id/license_const_layout" - app:layout_constraintTop_toTopOf="@id/license_const_layout" app:rowCount="5" + app:layout_constraintTop_toTopOf="@id/license_const_layout" + app:layout_constraintStart_toStartOf="@id/license_const_layout" + app:layout_constraintEnd_toEndOf="@id/license_const_layout" tools:layout_editor_absoluteX="11dp" tools:layout_editor_absoluteY="4dp"> + app:layout_rowWeight="1" + /> + app:layout_rowWeight="1" + android:gravity="center" + android:maxLength="9" + android:maxLines="1" + /> + app:layout_rowWeight="1" + android:gravity="center" + + /> + app:layout_rowWeight="1" + android:gravity="center"/> + app:layout_rowWeight="1" + android:gravity="center"/> + app:layout_rowWeight="1" + android:gravity="center"/> + app:layout_rowWeight="1" + android:gravity="center"/> + app:layout_rowWeight="1" + android:gravity="center"/> + app:layout_rowWeight="1" + android:gravity="center"/> @@ -173,42 +177,39 @@ - - + + + /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d66f3e2a..7e8144e9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,6 +26,9 @@ 4학년 2학기 + 저장하기 + 수정하기 + 졸업 예정일 0000년 00월 00일