From 4358ef05d9f6512b3cfe9220838fd9edc77cc845 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Fri, 16 Feb 2024 23:51:49 +0900 Subject: [PATCH 01/14] =?UTF-8?q?Fix:=20=EC=BB=A4=EB=A6=AC=EC=96=B4=20?= =?UTF-8?q?=EB=8D=94=ED=95=98=EA=B8=B0/=EC=88=98=EC=A0=95=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20editText=20=EC=9D=BC=EB=B6=80=20=ED=82=A4=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=EC=95=88=20=EB=9C=A8=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/fragment_career_add_activity.xml | 2 ++ app/src/main/res/layout/fragment_career_add_certificate.xml | 3 +++ app/src/main/res/layout/fragment_career_add_contest.xml | 3 +++ app/src/main/res/layout/fragment_career_add_volunteer.xml | 2 ++ app/src/main/res/layout/fragment_career_edit_activity.xml | 2 ++ app/src/main/res/layout/fragment_career_edit_certificate.xml | 3 +++ app/src/main/res/layout/fragment_career_edit_contest.xml | 3 +++ app/src/main/res/layout/fragment_career_edit_volunteer.xml | 2 ++ 8 files changed, 20 insertions(+) diff --git a/app/src/main/res/layout/fragment_career_add_activity.xml b/app/src/main/res/layout/fragment_career_add_activity.xml index 45dc7b5..c3426ce 100644 --- a/app/src/main/res/layout/fragment_career_add_activity.xml +++ b/app/src/main/res/layout/fragment_career_add_activity.xml @@ -105,6 +105,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_date_ex" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -137,6 +138,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_date_ex" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="10dp" android:paddingBottom="10dp" diff --git a/app/src/main/res/layout/fragment_career_add_certificate.xml b/app/src/main/res/layout/fragment_career_add_certificate.xml index 2f32594..859afc0 100644 --- a/app/src/main/res/layout/fragment_career_add_certificate.xml +++ b/app/src/main/res/layout/fragment_career_add_certificate.xml @@ -72,6 +72,7 @@ android:focusable="false" android:gravity="top" android:hint="실기" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -103,6 +104,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_date_ex" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -135,6 +137,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_date_ex" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="10dp" android:paddingBottom="10dp" diff --git a/app/src/main/res/layout/fragment_career_add_contest.xml b/app/src/main/res/layout/fragment_career_add_contest.xml index 8b5dc37..ec416ca 100644 --- a/app/src/main/res/layout/fragment_career_add_contest.xml +++ b/app/src/main/res/layout/fragment_career_add_contest.xml @@ -72,6 +72,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_choose" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -103,6 +104,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_date_ex" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -135,6 +137,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_date_ex" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="10dp" android:paddingBottom="10dp" diff --git a/app/src/main/res/layout/fragment_career_add_volunteer.xml b/app/src/main/res/layout/fragment_career_add_volunteer.xml index 7f2cfd7..4e969d1 100644 --- a/app/src/main/res/layout/fragment_career_add_volunteer.xml +++ b/app/src/main/res/layout/fragment_career_add_volunteer.xml @@ -104,6 +104,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_date_ex" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -136,6 +137,7 @@ android:focusable="false" android:gravity="top" android:hint="@string/career_date_ex" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="10dp" android:paddingBottom="10dp" diff --git a/app/src/main/res/layout/fragment_career_edit_activity.xml b/app/src/main/res/layout/fragment_career_edit_activity.xml index d45caa2..d92c1fa 100644 --- a/app/src/main/res/layout/fragment_career_edit_activity.xml +++ b/app/src/main/res/layout/fragment_career_edit_activity.xml @@ -174,6 +174,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -206,6 +207,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="10dp" android:paddingBottom="10dp" diff --git a/app/src/main/res/layout/fragment_career_edit_certificate.xml b/app/src/main/res/layout/fragment_career_edit_certificate.xml index b4e2153..aff6d4b 100644 --- a/app/src/main/res/layout/fragment_career_edit_certificate.xml +++ b/app/src/main/res/layout/fragment_career_edit_certificate.xml @@ -128,6 +128,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -159,6 +160,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -191,6 +193,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="10dp" android:paddingBottom="10dp" diff --git a/app/src/main/res/layout/fragment_career_edit_contest.xml b/app/src/main/res/layout/fragment_career_edit_contest.xml index 02f5b41..75bced7 100644 --- a/app/src/main/res/layout/fragment_career_edit_contest.xml +++ b/app/src/main/res/layout/fragment_career_edit_contest.xml @@ -128,6 +128,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -159,6 +160,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -191,6 +193,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="10dp" android:paddingBottom="10dp" diff --git a/app/src/main/res/layout/fragment_career_edit_volunteer.xml b/app/src/main/res/layout/fragment_career_edit_volunteer.xml index 1885dab..5b8b17b 100644 --- a/app/src/main/res/layout/fragment_career_edit_volunteer.xml +++ b/app/src/main/res/layout/fragment_career_edit_volunteer.xml @@ -160,6 +160,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="11dp" android:paddingBottom="10dp" @@ -192,6 +193,7 @@ android:focusable="false" android:gravity="top" android:hint="" + android:inputType="none" android:paddingStart="18dp" android:paddingTop="10dp" android:paddingBottom="10dp" From 92449025dc787eb162ab555e1022698c42fb1617 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:00:43 +0900 Subject: [PATCH 02/14] =?UTF-8?q?Feat:=20=EC=BB=A4=EB=A6=AC=EC=96=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=ED=95=98=EA=B8=B0/=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mobile/project/ui/career/CareerEditActivityFragment.kt | 2 ++ .../mobile/project/ui/career/CareerEditCertificateFragment.kt | 3 +++ .../com/mobile/project/ui/career/CareerEditContestFragment.kt | 3 +++ .../mobile/project/ui/career/CareerEditVolunteerFragment.kt | 3 +++ 4 files changed, 11 insertions(+) diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditActivityFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditActivityFragment.kt index 71944ea..46b08e3 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditActivityFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditActivityFragment.kt @@ -75,6 +75,7 @@ class CareerEditActivityFragment : Fragment() { if (isDeleted) { //삭제 작업이 완료되면 목록 업데이트 navigate(R.id.action_fragment_edit_activity_to_fragment_career_activity) + Toast.makeText(mContext, "삭제되었습니다.", Toast.LENGTH_SHORT).show() } }) } @@ -84,6 +85,7 @@ class CareerEditActivityFragment : Fragment() { if (isUpdated) { //수정 작업이 완료되면 목록 업데이트 navigate(R.id.action_fragment_edit_activity_to_fragment_career_activity) + Toast.makeText(mContext, "수정되었습니다.", Toast.LENGTH_SHORT).show() } }) } diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditCertificateFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditCertificateFragment.kt index 3bb63d0..07e06f0 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditCertificateFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditCertificateFragment.kt @@ -6,6 +6,7 @@ import android.text.Editable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment @@ -64,6 +65,7 @@ class CareerEditCertificateFragment : Fragment() { if (isDeleted) { //삭제 작업이 완료되면 목록 업데이트 navigate(R.id.action_fragment_edit_certificate_to_fragment_career_certificate) + Toast.makeText(mContext, "삭제되었습니다.", Toast.LENGTH_SHORT).show() } }) } @@ -74,6 +76,7 @@ class CareerEditCertificateFragment : Fragment() { if (isUpdated) { //수정 작업이 완료되면 목록 업데이트 navigate(R.id.action_fragment_edit_certificate_to_fragment_career_certificate) + Toast.makeText(mContext, "수정되었습니다.", Toast.LENGTH_SHORT).show() } }) } diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditContestFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditContestFragment.kt index 73220b8..cd46110 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditContestFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditContestFragment.kt @@ -6,6 +6,7 @@ import android.text.Editable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment @@ -72,6 +73,7 @@ class CareerEditContestFragment : Fragment() { if (isDeleted) { //삭제 작업이 완료되면 목록 업데이트 navigate(R.id.action_fragment_edit_contest_to_fragment_career_contest) + Toast.makeText(mContext, "삭제되었습니다.", Toast.LENGTH_SHORT).show() } }) } @@ -81,6 +83,7 @@ class CareerEditContestFragment : Fragment() { if (isUpdated) { //수정 작업이 완료되면 목록 업데이트 navigate(R.id.action_fragment_edit_contest_to_fragment_career_contest) + Toast.makeText(mContext, "수정되었습니다.", Toast.LENGTH_SHORT).show() } }) } diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditVolunteerFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditVolunteerFragment.kt index 7e33779..0cb729f 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditVolunteerFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditVolunteerFragment.kt @@ -6,6 +6,7 @@ import android.text.Editable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment @@ -63,6 +64,7 @@ class CareerEditVolunteerFragment : Fragment() { if (isDeleted) { //삭제 작업이 완료되면 목록 업데이트 navigate(R.id.action_fragment_edit_volunteer_to_fragment_career_volunteer) + Toast.makeText(mContext, "삭제되었습니다.", Toast.LENGTH_SHORT).show() } }) } @@ -72,6 +74,7 @@ class CareerEditVolunteerFragment : Fragment() { if (isUpdated) { //수정 작업이 완료되면 목록 업데이트 navigate(R.id.action_fragment_edit_volunteer_to_fragment_career_volunteer) + Toast.makeText(mContext, "수정되었습니다.", Toast.LENGTH_SHORT).show() } }) } From 0b1303c8cc0def9403f5fbafb2b5677884ce4094 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:18:31 +0900 Subject: [PATCH 03/14] =?UTF-8?q?Fix:=20=EC=BB=A4=EB=A6=AC=EC=96=B4=20?= =?UTF-8?q?=EB=8D=94=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=ED=99=9C?= =?UTF-8?q?=EC=84=B1=ED=99=94=20=EC=A1=B0=EA=B1=B4=EC=97=90=20type=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/career/CareerAddCertificateFragment.kt | 125 --------------- .../career/CareerAddCertificateViewModel.kt | 149 ++++++++++++++++++ .../ui/career/CareerAddContestFragment.kt | 110 ------------- .../ui/career/CareerAddContestViewModel.kt | 147 +++++++++++++++++ 4 files changed, 296 insertions(+), 235 deletions(-) delete mode 100644 app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateFragment.kt create mode 100644 app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateViewModel.kt delete mode 100644 app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestFragment.kt create mode 100644 app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestViewModel.kt diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateFragment.kt deleted file mode 100644 index f16f5b3..0000000 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateFragment.kt +++ /dev/null @@ -1,125 +0,0 @@ -package umc.com.mobile.project.ui.career - -import android.content.Context -import android.os.Bundle -import android.text.Editable -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.activityViewModels -import umc.com.mobile.project.R -import umc.com.mobile.project.databinding.FragmentCareerAddCertificateBinding -import umc.com.mobile.project.ui.career.viewmodel.CareerAddCertificateViewModel -import umc.com.mobile.project.ui.career.viewmodel.CareerAddViewModel -import umc.com.mobile.project.ui.common.NavigationUtil.navigate - -class CareerAddCertificateFragment : Fragment() { - private var _binding: FragmentCareerAddCertificateBinding? = null - private val viewModel: CareerAddCertificateViewModel by activityViewModels() - private val sharedViewModel: CareerAddViewModel by activityViewModels() - private lateinit var mContext: Context - private val binding get() = _binding!! - private var startYear: String? = null - private var startMonth: String? = null - private var startDay: String? = null - private var endYear: String? = null - private var endMonth: String? = null - private var endDay: String? = null - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = FragmentCareerAddCertificateBinding.inflate(inflater, container, false) - binding.vm = viewModel - binding.lifecycleOwner = this - mContext = requireContext() - - _binding!!.etCareerAddCertificateStartDate.setOnClickListener { - val bottomSheet = PeriodBottomFragment(mContext, true, 1) - bottomSheet.setStyle( - DialogFragment.STYLE_NORMAL, - R.style.RoundCornerBottomSheetDialogTheme - ) - bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) - } - _binding!!.etCareerAddCertificateEndDate.setOnClickListener { - val bottomSheet = PeriodBottomFragment(mContext, false, 1) - bottomSheet.setStyle( - DialogFragment.STYLE_NORMAL, - R.style.RoundCornerBottomSheetDialogTheme - ) - bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) - } - _binding!!.etCareerAddCertificateType.setOnClickListener { - val bottomSheet = CertificateTypeBottomFragment(mContext, 1) - bottomSheet.setStyle( - DialogFragment.STYLE_NORMAL, - R.style.RoundCornerBottomSheetDialogTheme - ) - bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) - } - _binding!!.btnCareerAdd.setOnClickListener { - //api 연결 - viewModel.addCareer() - navigate(R.id.action_fragment_career_add_to_fragment_career_confirm) - } - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - viewModel.init() - viewModel.selectedCertificateType.observe(viewLifecycleOwner) { selectedType -> - binding.etCareerAddCertificateType.text = - Editable.Factory.getInstance().newEditable(selectedType) - } - sharedViewModel.selectedStartYear.observe(viewLifecycleOwner) { year -> - startYear = year - updateStartDateEditText() - } - sharedViewModel.selectedStartMonth.observe(viewLifecycleOwner) { month -> - startMonth = month - updateStartDateEditText() - } - sharedViewModel.selectedStartDay.observe(viewLifecycleOwner) { day -> - startDay = day - updateStartDateEditText() - } - sharedViewModel.selectedEndYear.observe(viewLifecycleOwner) { year -> - endYear = year - updateEndDateEditText() - } - sharedViewModel.selectedEndMonth.observe(viewLifecycleOwner) { month -> - endMonth = month - updateEndDateEditText() - } - sharedViewModel.selectedEndDay.observe(viewLifecycleOwner) { day -> - endDay = day - updateEndDateEditText() - } - } - - private fun buildFormattedDate(year: String?, month: String?, day: String?): String { - return "$year$month$day" - } - - private fun updateStartDateEditText() { - val formattedDate = buildFormattedDate(startYear, startMonth, startDay) - binding.etCareerAddCertificateStartDate.text = - Editable.Factory.getInstance().newEditable(formattedDate) - } - - private fun updateEndDateEditText() { - val formattedDate = buildFormattedDate(endYear, endMonth, endDay) - binding.etCareerAddCertificateEndDate.text = - Editable.Factory.getInstance().newEditable(formattedDate) - } - - override fun onDestroyView() { - super.onDestroyView() - } -} diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateViewModel.kt new file mode 100644 index 0000000..5bbe3c3 --- /dev/null +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateViewModel.kt @@ -0,0 +1,149 @@ +package umc.com.mobile.project.ui.career.viewmodel + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.google.gson.GsonBuilder +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import umc.com.mobile.project.data.model.career.AddCareerResponse +import umc.com.mobile.project.data.network.ApiClient +import umc.com.mobile.project.data.network.api.CareerApi +import umc.com.mobile.project.ui.career.adapter.LocalDateAdapter +import umc.com.mobile.project.ui.career.data.CertificateDto +import java.time.LocalDate +import java.time.format.DateTimeFormatter + +class CareerAddCertificateViewModel : ViewModel() { + val title: MutableLiveData = MutableLiveData() + val selectedCertificateType: MutableLiveData = MutableLiveData() + val startDate: MutableLiveData = MutableLiveData() + val endDate: MutableLiveData = MutableLiveData() + + init { + title.value = "" + selectedCertificateType.value = "" + startDate.value = "" + endDate.value = "" + } + + fun init() { + title.value = "" + selectedCertificateType.value = "" + startDate.value = "" + endDate.value = "" + } + + fun updateCertificateType(type: String) { + selectedCertificateType.value = type + } + + /* 버튼 활성화 기능 */ + val isFilledAllOptions: LiveData = MediatorLiveData().apply { + addSource(title) { value = areBothFieldsFilled() } + addSource(selectedCertificateType) { value = areBothFieldsFilled() } + addSource(startDate) { value = areBothFieldsFilled() } + addSource(endDate) { value = areBothFieldsFilled() } + } + + private fun areBothFieldsFilled(): Boolean { + return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && !selectedCertificateType.value.isNullOrEmpty() + && isDateValid(startDate.value) && isDateValid(endDate.value) + } + + private fun isDateValid(date: String?): Boolean { + return !date.isNullOrBlank() && date.length == 8 + } + + private val imageList: MutableList = mutableListOf() + + //API에 전송할 데이터를 포함하는 RequestDto 생성 함수 + fun createRequestDto(): CertificateDto? { + val startDateString = startDate.value + val endDateString = endDate.value + //날짜가 입력되지 않은 경우 + if (startDateString.isNullOrBlank() || endDateString.isNullOrBlank()) { + return null + } + + val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") + val formattedStartDate = LocalDate.parse(startDateString, formatter) + val formattedEndDate = LocalDate.parse(endDateString, formatter) + + val certificationType = when (selectedCertificateType.value) { + "실기" -> "PRACTICAL_EXAM" + "필기" -> "WRITTEN_EXAM" + else -> "INTERVIEW" + } + + return CertificateDto( + title = title.value!!, + category = "CERTIFICATIONS", + startDate = formattedStartDate, + endDate = formattedEndDate, + certificationType = certificationType + ) + } + + private val careerApiService = ApiClient.createService() + + private val _addedCareerInfo: MutableLiveData = MutableLiveData() + val addedCareerInfo: MutableLiveData + get() = _addedCareerInfo + + private val _error: MutableLiveData = MutableLiveData() + val error: LiveData + get() = _error + + fun addCareer() { + val requestDto = createRequestDto() + + val gson = GsonBuilder() + .setDateFormat("yyyy-MM-dd") + .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) + .create() + + val requestDtoJson = gson.toJson(requestDto) + val requestDtoPart: RequestBody = + requestDtoJson.toRequestBody("application/json".toMediaTypeOrNull()) + + careerApiService.addCareer(imageList, requestDtoPart) + .enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + val addCareerResponse = response.body() + if (addCareerResponse != null) { + _addedCareerInfo.postValue(addCareerResponse) + Log.d("addedCareerInfo 성공", "${response.body()}") + } else { + _error.postValue("서버 응답이 올바르지 않습니다.") + } + } else { + _error.postValue("커리어를 추가하지 못했습니다.") + try { + throw response.errorBody()?.string()?.let { + RuntimeException(it) + } ?: RuntimeException("Unknown error") + } catch (e: Exception) { + Log.e("addCareerInfo", "addCareer API 오류: ${e.message}") + } + } + } + + override fun onFailure(call: Call, t: Throwable) { + _error.postValue("네트워크 오류: ${t.message}") + Log.d("addCareerInfo", "addCareer 네트워크 오류: ${t.message}") + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestFragment.kt deleted file mode 100644 index 6d27789..0000000 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestFragment.kt +++ /dev/null @@ -1,110 +0,0 @@ -package umc.com.mobile.project.ui.career - -import android.content.Context -import android.os.Bundle -import android.text.Editable -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.activityViewModels -import umc.com.mobile.project.R -import umc.com.mobile.project.databinding.FragmentCareerAddContestBinding -import umc.com.mobile.project.ui.career.viewmodel.CareerAddContestViewModel -import umc.com.mobile.project.ui.career.viewmodel.CareerAddViewModel -import umc.com.mobile.project.ui.common.NavigationUtil.navigate - -class CareerAddContestFragment : Fragment() { - private var _binding: FragmentCareerAddContestBinding? = null - private val viewModel: CareerAddContestViewModel by activityViewModels() - private val sharedViewModel: CareerAddViewModel by activityViewModels() - private lateinit var mContext: Context - private val binding get() = _binding!! - private var award: String? = null - private var startYear: String? = null - private var startMonth: String? = null - private var startDay: String? = null - private var endYear: String? = null - private var endMonth: String? = null - private var endDay: String? = null - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = FragmentCareerAddContestBinding.inflate(inflater, container, false) - binding.vm = viewModel - binding.lifecycleOwner = this - mContext = requireContext() - - _binding!!.etCareerAddContestStartYear.setOnClickListener { - val bottomSheet = PeriodBottomFragment(mContext, true, 1) - bottomSheet.setStyle(DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme) - bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) - } - _binding!!.etCareerAddContestEndYear.setOnClickListener { - val bottomSheet = PeriodBottomFragment(mContext, false, 1) - bottomSheet.setStyle(DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme) - bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) - } - _binding!!.etCareerAddContestAward.setOnClickListener { - val bottomSheet = AwardBottomFragment(mContext, 1) - bottomSheet.setStyle(DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme) - bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) - } - _binding!!.btnCareerAdd.setOnClickListener { - //api 연결 - viewModel.addCareer() - navigate(R.id.action_fragment_career_add_to_fragment_career_confirm) - } - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - viewModel.init() - viewModel.selectedAward.observe(viewLifecycleOwner) { selectedAward -> - binding.etCareerAddContestAward.text = Editable.Factory.getInstance().newEditable(selectedAward) - } - sharedViewModel.selectedStartYear.observe(viewLifecycleOwner) { year -> - startYear = year - updateStartDateEditText() - } - sharedViewModel.selectedStartMonth.observe(viewLifecycleOwner) { month -> - startMonth = month - updateStartDateEditText() - } - sharedViewModel.selectedStartDay.observe(viewLifecycleOwner) { day -> - startDay = day - updateStartDateEditText() - } - sharedViewModel.selectedEndYear.observe(viewLifecycleOwner) { year -> - endYear = year - updateEndDateEditText() - } - sharedViewModel.selectedEndMonth.observe(viewLifecycleOwner) { month -> - endMonth = month - updateEndDateEditText() - } - sharedViewModel.selectedEndDay.observe(viewLifecycleOwner) { day -> - endDay = day - updateEndDateEditText() - } - } - private fun buildFormattedDate(year: String?, month: String?, day: String?): String { - return "$year$month$day" - } - private fun updateStartDateEditText() { - val formattedDate = buildFormattedDate(startYear, startMonth, startDay) - binding.etCareerAddContestStartYear.text = Editable.Factory.getInstance().newEditable(formattedDate) - } - private fun updateEndDateEditText() { - val formattedDate = buildFormattedDate(endYear, endMonth, endDay) - binding.etCareerAddContestEndYear.text = Editable.Factory.getInstance().newEditable(formattedDate) - } - override fun onDestroyView() { - super.onDestroyView() - } -} diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestViewModel.kt new file mode 100644 index 0000000..4acb315 --- /dev/null +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestViewModel.kt @@ -0,0 +1,147 @@ +package umc.com.mobile.project.ui.career.viewmodel + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import umc.com.mobile.project.data.model.career.AddCareerResponse +import umc.com.mobile.project.data.network.ApiClient +import umc.com.mobile.project.data.network.api.CareerApi +import umc.com.mobile.project.ui.career.data.RequestDto +import java.time.LocalDate +import java.time.format.DateTimeFormatter +import com.google.gson.GsonBuilder +import okhttp3.RequestBody.Companion.toRequestBody +import umc.com.mobile.project.ui.career.adapter.LocalDateAdapter + +class CareerAddContestViewModel : ViewModel() { + val title: MutableLiveData = MutableLiveData() + val selectedAward: MutableLiveData = MutableLiveData() + val startDate: MutableLiveData = MutableLiveData() + val endDate: MutableLiveData = MutableLiveData() + + init { + title.value = "" + selectedAward.value = "" + startDate.value = "" + endDate.value = "" + } + + fun init() { + title.value = "" + selectedAward.value = "" + startDate.value = "" + endDate.value = "" + } + + fun updateSelectedAward(award: String) { + selectedAward.value = award + } + + /* 버튼 활성화 기능 */ + val isFilledAllOptions: LiveData = MediatorLiveData().apply { + addSource(title) { value = areBothFieldsFilled() } + addSource(selectedAward) { value = areBothFieldsFilled() } + addSource(startDate) { value = areBothFieldsFilled() } + addSource(endDate) { value = areBothFieldsFilled() } + } + + private fun areBothFieldsFilled(): Boolean { + return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && !selectedAward.value.isNullOrEmpty() + && isDateValid(startDate.value) && isDateValid(endDate.value) + } + + private fun isDateValid(date: String?): Boolean { + return !date.isNullOrBlank() && date.length == 8 + } + + private val imageList: MutableList = mutableListOf() + + //API에 전송할 데이터를 포함하는 RequestDto 생성 함수 + fun createRequestDto(): RequestDto? { + val startDateString = startDate.value + val endDateString = endDate.value + + val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") + val formattedStartDate = LocalDate.parse(startDateString, formatter) + val formattedEndDate = LocalDate.parse(endDateString, formatter) + + val certificationType = when (selectedAward.value) { + "대상" -> "GRAND_PRIZE" + "최우수상" -> "EXCELLENT_PRIZE" + "우수상" -> "GOOD_PRIZE" + else -> "ENCOURAGEMENT_PRIZE" + } + + return RequestDto( + title = title.value!!, + content = "", + category = "COMPETITIONS", + startDate = formattedStartDate, + endDate = formattedEndDate, + award = certificationType + ) + } + + private val careerApiService = ApiClient.createService() + + private val _addedCareerInfo: MutableLiveData = MutableLiveData() + val addedCareerInfo: MutableLiveData + get() = _addedCareerInfo + + private val _error: MutableLiveData = MutableLiveData() + val error: LiveData + get() = _error + + fun addCareer() { + val requestDto = createRequestDto() + + val gson = GsonBuilder() + .setDateFormat("yyyy-MM-dd") + .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) + .create() + + val requestDtoJson = gson.toJson(requestDto) + val requestDtoPart: RequestBody = + requestDtoJson.toRequestBody("application/json".toMediaTypeOrNull()) + + careerApiService.addCareer(imageList, requestDtoPart) + .enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + if (response.isSuccessful) { + val addCareerResponse = response.body() + if (addCareerResponse != null) { + _addedCareerInfo.postValue(addCareerResponse) + Log.d("addedCareerInfo 성공", "${response.body()}") + } else { + _error.postValue("서버 응답이 올바르지 않습니다.") + } + } else { + _error.postValue("커리어를 추가하지 못했습니다.") + try { + throw response.errorBody()?.string()?.let { + RuntimeException(it) + } ?: RuntimeException("Unknown error") + } catch (e: Exception) { + Log.e("addCareerInfo", "addCareer API 오류: ${e.message}") + } + } + } + + override fun onFailure(call: Call, t: Throwable) { + _error.postValue("네트워크 오류: ${t.message}") + Log.d("addCareerInfo", "addCareer 네트워크 오류: ${t.message}") + } + }) + } +} \ No newline at end of file From a22ed304843cd28549487600e11abf21d4545264 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:21:10 +0900 Subject: [PATCH 04/14] =?UTF-8?q?Fix:=20=EC=82=AD=EC=A0=9C=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/career/CareerAddCertificateFragment.kt | 125 +++++++++++++++ .../career/CareerAddCertificateViewModel.kt | 149 ------------------ .../ui/career/CareerAddContestFragment.kt | 110 +++++++++++++ .../ui/career/CareerAddContestViewModel.kt | 147 ----------------- .../CareerAddCertificateViewModel.kt | 6 +- .../viewmodel/CareerAddContestViewModel.kt | 6 +- 6 files changed, 241 insertions(+), 302 deletions(-) create mode 100644 app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateFragment.kt delete mode 100644 app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateViewModel.kt create mode 100644 app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestFragment.kt delete mode 100644 app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestViewModel.kt diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateFragment.kt new file mode 100644 index 0000000..f16f5b3 --- /dev/null +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateFragment.kt @@ -0,0 +1,125 @@ +package umc.com.mobile.project.ui.career + +import android.content.Context +import android.os.Bundle +import android.text.Editable +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import umc.com.mobile.project.R +import umc.com.mobile.project.databinding.FragmentCareerAddCertificateBinding +import umc.com.mobile.project.ui.career.viewmodel.CareerAddCertificateViewModel +import umc.com.mobile.project.ui.career.viewmodel.CareerAddViewModel +import umc.com.mobile.project.ui.common.NavigationUtil.navigate + +class CareerAddCertificateFragment : Fragment() { + private var _binding: FragmentCareerAddCertificateBinding? = null + private val viewModel: CareerAddCertificateViewModel by activityViewModels() + private val sharedViewModel: CareerAddViewModel by activityViewModels() + private lateinit var mContext: Context + private val binding get() = _binding!! + private var startYear: String? = null + private var startMonth: String? = null + private var startDay: String? = null + private var endYear: String? = null + private var endMonth: String? = null + private var endDay: String? = null + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentCareerAddCertificateBinding.inflate(inflater, container, false) + binding.vm = viewModel + binding.lifecycleOwner = this + mContext = requireContext() + + _binding!!.etCareerAddCertificateStartDate.setOnClickListener { + val bottomSheet = PeriodBottomFragment(mContext, true, 1) + bottomSheet.setStyle( + DialogFragment.STYLE_NORMAL, + R.style.RoundCornerBottomSheetDialogTheme + ) + bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) + } + _binding!!.etCareerAddCertificateEndDate.setOnClickListener { + val bottomSheet = PeriodBottomFragment(mContext, false, 1) + bottomSheet.setStyle( + DialogFragment.STYLE_NORMAL, + R.style.RoundCornerBottomSheetDialogTheme + ) + bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) + } + _binding!!.etCareerAddCertificateType.setOnClickListener { + val bottomSheet = CertificateTypeBottomFragment(mContext, 1) + bottomSheet.setStyle( + DialogFragment.STYLE_NORMAL, + R.style.RoundCornerBottomSheetDialogTheme + ) + bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) + } + _binding!!.btnCareerAdd.setOnClickListener { + //api 연결 + viewModel.addCareer() + navigate(R.id.action_fragment_career_add_to_fragment_career_confirm) + } + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + viewModel.init() + viewModel.selectedCertificateType.observe(viewLifecycleOwner) { selectedType -> + binding.etCareerAddCertificateType.text = + Editable.Factory.getInstance().newEditable(selectedType) + } + sharedViewModel.selectedStartYear.observe(viewLifecycleOwner) { year -> + startYear = year + updateStartDateEditText() + } + sharedViewModel.selectedStartMonth.observe(viewLifecycleOwner) { month -> + startMonth = month + updateStartDateEditText() + } + sharedViewModel.selectedStartDay.observe(viewLifecycleOwner) { day -> + startDay = day + updateStartDateEditText() + } + sharedViewModel.selectedEndYear.observe(viewLifecycleOwner) { year -> + endYear = year + updateEndDateEditText() + } + sharedViewModel.selectedEndMonth.observe(viewLifecycleOwner) { month -> + endMonth = month + updateEndDateEditText() + } + sharedViewModel.selectedEndDay.observe(viewLifecycleOwner) { day -> + endDay = day + updateEndDateEditText() + } + } + + private fun buildFormattedDate(year: String?, month: String?, day: String?): String { + return "$year$month$day" + } + + private fun updateStartDateEditText() { + val formattedDate = buildFormattedDate(startYear, startMonth, startDay) + binding.etCareerAddCertificateStartDate.text = + Editable.Factory.getInstance().newEditable(formattedDate) + } + + private fun updateEndDateEditText() { + val formattedDate = buildFormattedDate(endYear, endMonth, endDay) + binding.etCareerAddCertificateEndDate.text = + Editable.Factory.getInstance().newEditable(formattedDate) + } + + override fun onDestroyView() { + super.onDestroyView() + } +} diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateViewModel.kt deleted file mode 100644 index 5bbe3c3..0000000 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddCertificateViewModel.kt +++ /dev/null @@ -1,149 +0,0 @@ -package umc.com.mobile.project.ui.career.viewmodel - -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MediatorLiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.google.gson.GsonBuilder -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.MultipartBody -import okhttp3.RequestBody -import okhttp3.RequestBody.Companion.toRequestBody -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response -import umc.com.mobile.project.data.model.career.AddCareerResponse -import umc.com.mobile.project.data.network.ApiClient -import umc.com.mobile.project.data.network.api.CareerApi -import umc.com.mobile.project.ui.career.adapter.LocalDateAdapter -import umc.com.mobile.project.ui.career.data.CertificateDto -import java.time.LocalDate -import java.time.format.DateTimeFormatter - -class CareerAddCertificateViewModel : ViewModel() { - val title: MutableLiveData = MutableLiveData() - val selectedCertificateType: MutableLiveData = MutableLiveData() - val startDate: MutableLiveData = MutableLiveData() - val endDate: MutableLiveData = MutableLiveData() - - init { - title.value = "" - selectedCertificateType.value = "" - startDate.value = "" - endDate.value = "" - } - - fun init() { - title.value = "" - selectedCertificateType.value = "" - startDate.value = "" - endDate.value = "" - } - - fun updateCertificateType(type: String) { - selectedCertificateType.value = type - } - - /* 버튼 활성화 기능 */ - val isFilledAllOptions: LiveData = MediatorLiveData().apply { - addSource(title) { value = areBothFieldsFilled() } - addSource(selectedCertificateType) { value = areBothFieldsFilled() } - addSource(startDate) { value = areBothFieldsFilled() } - addSource(endDate) { value = areBothFieldsFilled() } - } - - private fun areBothFieldsFilled(): Boolean { - return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && !selectedCertificateType.value.isNullOrEmpty() - && isDateValid(startDate.value) && isDateValid(endDate.value) - } - - private fun isDateValid(date: String?): Boolean { - return !date.isNullOrBlank() && date.length == 8 - } - - private val imageList: MutableList = mutableListOf() - - //API에 전송할 데이터를 포함하는 RequestDto 생성 함수 - fun createRequestDto(): CertificateDto? { - val startDateString = startDate.value - val endDateString = endDate.value - //날짜가 입력되지 않은 경우 - if (startDateString.isNullOrBlank() || endDateString.isNullOrBlank()) { - return null - } - - val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") - val formattedStartDate = LocalDate.parse(startDateString, formatter) - val formattedEndDate = LocalDate.parse(endDateString, formatter) - - val certificationType = when (selectedCertificateType.value) { - "실기" -> "PRACTICAL_EXAM" - "필기" -> "WRITTEN_EXAM" - else -> "INTERVIEW" - } - - return CertificateDto( - title = title.value!!, - category = "CERTIFICATIONS", - startDate = formattedStartDate, - endDate = formattedEndDate, - certificationType = certificationType - ) - } - - private val careerApiService = ApiClient.createService() - - private val _addedCareerInfo: MutableLiveData = MutableLiveData() - val addedCareerInfo: MutableLiveData - get() = _addedCareerInfo - - private val _error: MutableLiveData = MutableLiveData() - val error: LiveData - get() = _error - - fun addCareer() { - val requestDto = createRequestDto() - - val gson = GsonBuilder() - .setDateFormat("yyyy-MM-dd") - .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) - .create() - - val requestDtoJson = gson.toJson(requestDto) - val requestDtoPart: RequestBody = - requestDtoJson.toRequestBody("application/json".toMediaTypeOrNull()) - - careerApiService.addCareer(imageList, requestDtoPart) - .enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - val addCareerResponse = response.body() - if (addCareerResponse != null) { - _addedCareerInfo.postValue(addCareerResponse) - Log.d("addedCareerInfo 성공", "${response.body()}") - } else { - _error.postValue("서버 응답이 올바르지 않습니다.") - } - } else { - _error.postValue("커리어를 추가하지 못했습니다.") - try { - throw response.errorBody()?.string()?.let { - RuntimeException(it) - } ?: RuntimeException("Unknown error") - } catch (e: Exception) { - Log.e("addCareerInfo", "addCareer API 오류: ${e.message}") - } - } - } - - override fun onFailure(call: Call, t: Throwable) { - _error.postValue("네트워크 오류: ${t.message}") - Log.d("addCareerInfo", "addCareer 네트워크 오류: ${t.message}") - } - }) - } -} \ No newline at end of file diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestFragment.kt new file mode 100644 index 0000000..6d27789 --- /dev/null +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestFragment.kt @@ -0,0 +1,110 @@ +package umc.com.mobile.project.ui.career + +import android.content.Context +import android.os.Bundle +import android.text.Editable +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import umc.com.mobile.project.R +import umc.com.mobile.project.databinding.FragmentCareerAddContestBinding +import umc.com.mobile.project.ui.career.viewmodel.CareerAddContestViewModel +import umc.com.mobile.project.ui.career.viewmodel.CareerAddViewModel +import umc.com.mobile.project.ui.common.NavigationUtil.navigate + +class CareerAddContestFragment : Fragment() { + private var _binding: FragmentCareerAddContestBinding? = null + private val viewModel: CareerAddContestViewModel by activityViewModels() + private val sharedViewModel: CareerAddViewModel by activityViewModels() + private lateinit var mContext: Context + private val binding get() = _binding!! + private var award: String? = null + private var startYear: String? = null + private var startMonth: String? = null + private var startDay: String? = null + private var endYear: String? = null + private var endMonth: String? = null + private var endDay: String? = null + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentCareerAddContestBinding.inflate(inflater, container, false) + binding.vm = viewModel + binding.lifecycleOwner = this + mContext = requireContext() + + _binding!!.etCareerAddContestStartYear.setOnClickListener { + val bottomSheet = PeriodBottomFragment(mContext, true, 1) + bottomSheet.setStyle(DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme) + bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) + } + _binding!!.etCareerAddContestEndYear.setOnClickListener { + val bottomSheet = PeriodBottomFragment(mContext, false, 1) + bottomSheet.setStyle(DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme) + bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) + } + _binding!!.etCareerAddContestAward.setOnClickListener { + val bottomSheet = AwardBottomFragment(mContext, 1) + bottomSheet.setStyle(DialogFragment.STYLE_NORMAL, R.style.RoundCornerBottomSheetDialogTheme) + bottomSheet.show(requireActivity().supportFragmentManager, bottomSheet.tag) + } + _binding!!.btnCareerAdd.setOnClickListener { + //api 연결 + viewModel.addCareer() + navigate(R.id.action_fragment_career_add_to_fragment_career_confirm) + } + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + viewModel.init() + viewModel.selectedAward.observe(viewLifecycleOwner) { selectedAward -> + binding.etCareerAddContestAward.text = Editable.Factory.getInstance().newEditable(selectedAward) + } + sharedViewModel.selectedStartYear.observe(viewLifecycleOwner) { year -> + startYear = year + updateStartDateEditText() + } + sharedViewModel.selectedStartMonth.observe(viewLifecycleOwner) { month -> + startMonth = month + updateStartDateEditText() + } + sharedViewModel.selectedStartDay.observe(viewLifecycleOwner) { day -> + startDay = day + updateStartDateEditText() + } + sharedViewModel.selectedEndYear.observe(viewLifecycleOwner) { year -> + endYear = year + updateEndDateEditText() + } + sharedViewModel.selectedEndMonth.observe(viewLifecycleOwner) { month -> + endMonth = month + updateEndDateEditText() + } + sharedViewModel.selectedEndDay.observe(viewLifecycleOwner) { day -> + endDay = day + updateEndDateEditText() + } + } + private fun buildFormattedDate(year: String?, month: String?, day: String?): String { + return "$year$month$day" + } + private fun updateStartDateEditText() { + val formattedDate = buildFormattedDate(startYear, startMonth, startDay) + binding.etCareerAddContestStartYear.text = Editable.Factory.getInstance().newEditable(formattedDate) + } + private fun updateEndDateEditText() { + val formattedDate = buildFormattedDate(endYear, endMonth, endDay) + binding.etCareerAddContestEndYear.text = Editable.Factory.getInstance().newEditable(formattedDate) + } + override fun onDestroyView() { + super.onDestroyView() + } +} diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestViewModel.kt deleted file mode 100644 index 4acb315..0000000 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerAddContestViewModel.kt +++ /dev/null @@ -1,147 +0,0 @@ -package umc.com.mobile.project.ui.career.viewmodel - -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MediatorLiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.MultipartBody -import okhttp3.RequestBody -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response -import umc.com.mobile.project.data.model.career.AddCareerResponse -import umc.com.mobile.project.data.network.ApiClient -import umc.com.mobile.project.data.network.api.CareerApi -import umc.com.mobile.project.ui.career.data.RequestDto -import java.time.LocalDate -import java.time.format.DateTimeFormatter -import com.google.gson.GsonBuilder -import okhttp3.RequestBody.Companion.toRequestBody -import umc.com.mobile.project.ui.career.adapter.LocalDateAdapter - -class CareerAddContestViewModel : ViewModel() { - val title: MutableLiveData = MutableLiveData() - val selectedAward: MutableLiveData = MutableLiveData() - val startDate: MutableLiveData = MutableLiveData() - val endDate: MutableLiveData = MutableLiveData() - - init { - title.value = "" - selectedAward.value = "" - startDate.value = "" - endDate.value = "" - } - - fun init() { - title.value = "" - selectedAward.value = "" - startDate.value = "" - endDate.value = "" - } - - fun updateSelectedAward(award: String) { - selectedAward.value = award - } - - /* 버튼 활성화 기능 */ - val isFilledAllOptions: LiveData = MediatorLiveData().apply { - addSource(title) { value = areBothFieldsFilled() } - addSource(selectedAward) { value = areBothFieldsFilled() } - addSource(startDate) { value = areBothFieldsFilled() } - addSource(endDate) { value = areBothFieldsFilled() } - } - - private fun areBothFieldsFilled(): Boolean { - return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && !selectedAward.value.isNullOrEmpty() - && isDateValid(startDate.value) && isDateValid(endDate.value) - } - - private fun isDateValid(date: String?): Boolean { - return !date.isNullOrBlank() && date.length == 8 - } - - private val imageList: MutableList = mutableListOf() - - //API에 전송할 데이터를 포함하는 RequestDto 생성 함수 - fun createRequestDto(): RequestDto? { - val startDateString = startDate.value - val endDateString = endDate.value - - val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") - val formattedStartDate = LocalDate.parse(startDateString, formatter) - val formattedEndDate = LocalDate.parse(endDateString, formatter) - - val certificationType = when (selectedAward.value) { - "대상" -> "GRAND_PRIZE" - "최우수상" -> "EXCELLENT_PRIZE" - "우수상" -> "GOOD_PRIZE" - else -> "ENCOURAGEMENT_PRIZE" - } - - return RequestDto( - title = title.value!!, - content = "", - category = "COMPETITIONS", - startDate = formattedStartDate, - endDate = formattedEndDate, - award = certificationType - ) - } - - private val careerApiService = ApiClient.createService() - - private val _addedCareerInfo: MutableLiveData = MutableLiveData() - val addedCareerInfo: MutableLiveData - get() = _addedCareerInfo - - private val _error: MutableLiveData = MutableLiveData() - val error: LiveData - get() = _error - - fun addCareer() { - val requestDto = createRequestDto() - - val gson = GsonBuilder() - .setDateFormat("yyyy-MM-dd") - .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) - .create() - - val requestDtoJson = gson.toJson(requestDto) - val requestDtoPart: RequestBody = - requestDtoJson.toRequestBody("application/json".toMediaTypeOrNull()) - - careerApiService.addCareer(imageList, requestDtoPart) - .enqueue(object : Callback { - override fun onResponse( - call: Call, - response: Response - ) { - if (response.isSuccessful) { - val addCareerResponse = response.body() - if (addCareerResponse != null) { - _addedCareerInfo.postValue(addCareerResponse) - Log.d("addedCareerInfo 성공", "${response.body()}") - } else { - _error.postValue("서버 응답이 올바르지 않습니다.") - } - } else { - _error.postValue("커리어를 추가하지 못했습니다.") - try { - throw response.errorBody()?.string()?.let { - RuntimeException(it) - } ?: RuntimeException("Unknown error") - } catch (e: Exception) { - Log.e("addCareerInfo", "addCareer API 오류: ${e.message}") - } - } - } - - override fun onFailure(call: Call, t: Throwable) { - _error.postValue("네트워크 오류: ${t.message}") - Log.d("addCareerInfo", "addCareer 네트워크 오류: ${t.message}") - } - }) - } -} \ No newline at end of file diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddCertificateViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddCertificateViewModel.kt index c711817..5bbe3c3 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddCertificateViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddCertificateViewModel.kt @@ -48,14 +48,14 @@ class CareerAddCertificateViewModel : ViewModel() { /* 버튼 활성화 기능 */ val isFilledAllOptions: LiveData = MediatorLiveData().apply { addSource(title) { value = areBothFieldsFilled() } + addSource(selectedCertificateType) { value = areBothFieldsFilled() } addSource(startDate) { value = areBothFieldsFilled() } addSource(endDate) { value = areBothFieldsFilled() } } private fun areBothFieldsFilled(): Boolean { - return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && isDateValid( - startDate.value - ) && isDateValid(endDate.value) + return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && !selectedCertificateType.value.isNullOrEmpty() + && isDateValid(startDate.value) && isDateValid(endDate.value) } private fun isDateValid(date: String?): Boolean { diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddContestViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddContestViewModel.kt index efce1bc..4acb315 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddContestViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddContestViewModel.kt @@ -48,14 +48,14 @@ class CareerAddContestViewModel : ViewModel() { /* 버튼 활성화 기능 */ val isFilledAllOptions: LiveData = MediatorLiveData().apply { addSource(title) { value = areBothFieldsFilled() } + addSource(selectedAward) { value = areBothFieldsFilled() } addSource(startDate) { value = areBothFieldsFilled() } addSource(endDate) { value = areBothFieldsFilled() } } private fun areBothFieldsFilled(): Boolean { - return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && isDateValid( - startDate.value - ) && isDateValid(endDate.value) + return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && !selectedAward.value.isNullOrEmpty() + && isDateValid(startDate.value) && isDateValid(endDate.value) } private fun isDateValid(date: String?): Boolean { From aaee90d4e520cb4da79d8c1cdc23eb32904ce2ab Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:35:53 +0900 Subject: [PATCH 05/14] =?UTF-8?q?Fix:=20=EC=BB=A4=EB=A6=AC=EC=96=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94=20=EC=A1=B0=EA=B1=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewmodel/CareerEditCertificateViewModel.kt | 16 ++++++++-------- .../viewmodel/CareerEditContestViewModel.kt | 14 +++++++------- .../viewmodel/CareerEditVolunteerViewModel.kt | 14 +++++++------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditCertificateViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditCertificateViewModel.kt index 3af5d61..20f51d0 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditCertificateViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditCertificateViewModel.kt @@ -44,17 +44,17 @@ class CareerEditCertificateViewModel : ViewModel() { startDate.value = "" endDate.value = "" } - + val isFilledAllOptions: LiveData = MediatorLiveData().apply { - value = areBothFieldsFilled() - addSource(startDate) { value = areBothFieldsFilled() } - addSource(endDate) { value = areBothFieldsFilled() } + value = isAnyFieldFilled() + addSource(title) { value = isAnyFieldFilled() } + addSource(type) { value = isAnyFieldFilled() } + addSource(startDate) { value = isAnyFieldFilled() } + addSource(endDate) { value = isAnyFieldFilled() } } - private fun areBothFieldsFilled(): Boolean { - return (startDate.value.isNullOrBlank() && endDate.value.isNullOrBlank()) || (isDateValid( - startDate.value - ) && isDateValid(endDate.value)) + private fun isAnyFieldFilled(): Boolean { + return !title.value.isNullOrBlank() || !type.value.isNullOrBlank() || !startDate.value.isNullOrBlank() || !endDate.value.isNullOrBlank() } private fun isDateValid(date: String?): Boolean { diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditContestViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditContestViewModel.kt index dc668e9..8bd6c79 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditContestViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditContestViewModel.kt @@ -46,15 +46,15 @@ class CareerEditContestViewModel : ViewModel() { } val isFilledAllOptions: LiveData = MediatorLiveData().apply { - value = areBothFieldsFilled() - addSource(startDate) { value = areBothFieldsFilled() } - addSource(endDate) { value = areBothFieldsFilled() } + value = isAnyFieldFilled() + addSource(title) { value = isAnyFieldFilled() } + addSource(award) { value = isAnyFieldFilled() } + addSource(startDate) { value = isAnyFieldFilled() } + addSource(endDate) { value = isAnyFieldFilled() } } - private fun areBothFieldsFilled(): Boolean { - return (startDate.value.isNullOrBlank() && endDate.value.isNullOrBlank()) || (isDateValid( - startDate.value - ) && isDateValid(endDate.value)) + private fun isAnyFieldFilled(): Boolean { + return !title.value.isNullOrBlank() || !award.value.isNullOrBlank() || !startDate.value.isNullOrBlank() || !endDate.value.isNullOrBlank() } private fun isDateValid(date: String?): Boolean { diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditVolunteerViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditVolunteerViewModel.kt index c8ecee8..07fccca 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditVolunteerViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditVolunteerViewModel.kt @@ -46,15 +46,15 @@ class CareerEditVolunteerViewModel : ViewModel() { } val isFilledAllOptions: LiveData = MediatorLiveData().apply { - value = areBothFieldsFilled() - addSource(startDate) { value = areBothFieldsFilled() } - addSource(endDate) { value = areBothFieldsFilled() } + value = isAnyFieldFilled() + addSource(title) { value = isAnyFieldFilled() } + addSource(hour) { value = isAnyFieldFilled() } + addSource(startDate) { value = isAnyFieldFilled() } + addSource(endDate) { value = isAnyFieldFilled() } } - private fun areBothFieldsFilled(): Boolean { - return (startDate.value.isNullOrBlank() && endDate.value.isNullOrBlank()) || (isDateValid( - startDate.value - ) && isDateValid(endDate.value)) + private fun isAnyFieldFilled(): Boolean { + return !title.value.isNullOrBlank() || !hour.value.isNullOrBlank() || !startDate.value.isNullOrBlank() || !endDate.value.isNullOrBlank() } private fun isDateValid(date: String?): Boolean { From d7232cf1c6f9ff31ab164bd6684d1d5ea3975581 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:47:45 +0900 Subject: [PATCH 06/14] =?UTF-8?q?Feat:=20=EC=BB=A4=EB=A6=AC=EC=96=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=ED=95=98=EA=B8=B0=20=EB=8C=80=EC=99=B8?= =?UTF-8?q?=ED=99=9C=EB=8F=99=20=EB=B2=84=ED=8A=BC=20=ED=99=9C=EC=84=B1?= =?UTF-8?q?=ED=99=94=20=EC=A1=B0=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/career/CareerEditActivityFragment.kt | 2 +- .../viewmodel/CareerEditActivityViewModel.kt | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditActivityFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditActivityFragment.kt index 46b08e3..e92bedf 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditActivityFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/CareerEditActivityFragment.kt @@ -103,7 +103,7 @@ class CareerEditActivityFragment : Fragment() { } }) //버튼 활성화 - viewModel.isFilledAllOptions.observe(viewLifecycleOwner) { isEnabled -> + viewModel.isFilledAnyOptions.observe(viewLifecycleOwner) { isEnabled -> binding?.btnCareerEdit?.isEnabled = isEnabled binding?.btnCareerEdit?.backgroundTintList = ContextCompat.getColorStateList( diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditActivityViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditActivityViewModel.kt index 49655c6..3b577c6 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditActivityViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditActivityViewModel.kt @@ -33,6 +33,9 @@ class CareerEditActivityViewModel : ViewModel() { val endDate: MutableLiveData = MutableLiveData() val fileAddedEvent: MutableLiveData = MutableLiveData() val addFiles: MutableList = mutableListOf() + val addFilesLive: MutableLiveData = MutableLiveData().apply { + value = addFiles.isNotEmpty() + } init { studentId.value = 0 @@ -49,18 +52,19 @@ class CareerEditActivityViewModel : ViewModel() { startDate.value = "" endDate.value = "" addFiles.clear() + addFilesLive.value = addFiles.isNotEmpty() } - val isFilledAllOptions: LiveData = MediatorLiveData().apply { - value = areBothFieldsFilled() - addSource(startDate) { value = areBothFieldsFilled() } - addSource(endDate) { value = areBothFieldsFilled() } + val isFilledAnyOptions: LiveData = MediatorLiveData().apply { + value = isAnyFieldFilled() + addSource(title) { value = isAnyFieldFilled() } + addSource(startDate) { value = isAnyFieldFilled() } + addSource(endDate) { value = isAnyFieldFilled() } + addSource(addFilesLive) { value = isAnyFieldFilled() } } - private fun areBothFieldsFilled(): Boolean { - return (startDate.value.isNullOrBlank() && endDate.value.isNullOrBlank()) || (isDateValid( - startDate.value - ) && isDateValid(endDate.value)) + private fun isAnyFieldFilled(): Boolean { + return !title.value.isNullOrBlank() || !startDate.value.isNullOrBlank() || !endDate.value.isNullOrBlank() || (addFilesLive.value ?: false) } private fun isDateValid(date: String?): Boolean { @@ -71,6 +75,7 @@ class CareerEditActivityViewModel : ViewModel() { val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), file) val body = MultipartBody.Part.createFormData("addFiles", file.name, requestFile) addFiles.add(body) + addFilesLive.value = addFiles.isNotEmpty() fileAddedEvent.value = true } @@ -99,6 +104,7 @@ class CareerEditActivityViewModel : ViewModel() { val requestFile: RequestBody = RequestBody.create(mimeType?.toMediaTypeOrNull(), file) val filePart = MultipartBody.Part.createFormData("addFiles", fileName, requestFile) addFiles.add(filePart) + addFilesLive.value = addFiles.isNotEmpty() fileAddedEvent.value = true } From f77bae4f13a45e6dd447451ecc4cb364aa40a319 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sat, 17 Feb 2024 23:29:30 +0900 Subject: [PATCH 07/14] =?UTF-8?q?Design:=20=EC=A1=B8=EC=97=85=EC=97=90?= =?UTF-8?q?=EC=A0=95=EC=9D=BC=20nestedScrollView=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/res/layout/fragment_grad_date.xml | 297 +++++++++--------- 1 file changed, 151 insertions(+), 146 deletions(-) diff --git a/app/src/main/res/layout/fragment_grad_date.xml b/app/src/main/res/layout/fragment_grad_date.xml index 517ab29..94ca895 100644 --- a/app/src/main/res/layout/fragment_grad_date.xml +++ b/app/src/main/res/layout/fragment_grad_date.xml @@ -11,169 +11,174 @@ - - - - - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + - - + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/iv_grad_date_card1"> + + + + + + - - - - - - - + + - + android:layout_marginBottom="6dp" + android:background="@drawable/bg_solid_gray_radius_25" + android:backgroundTint="@color/gray" + android:minHeight="0dp" + android:paddingTop="17dp" + android:paddingBottom="17dp" + android:stateListAnimator="@null" + android:text="저장하기" + android:textColor="@color/skyBlue" + android:visibility="@{vm.isEditMode ? 0 : 8}" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@+id/tv_grad_date_memo" + app:layout_constraintStart_toStartOf="@+id/tv_grad_date_memo" /> - - - - - - - + \ No newline at end of file From 6d48526cb6dc00d8d4292a71f8ae83bd2bbe5977 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sat, 17 Feb 2024 23:30:55 +0900 Subject: [PATCH 08/14] =?UTF-8?q?Fix:=20=EC=A1=B8=EC=97=85=EC=98=88?= =?UTF-8?q?=EC=A0=95=EC=9D=BC=20=EB=B2=84=ED=8A=BC=20=ED=99=9C=EC=84=B1?= =?UTF-8?q?=ED=99=94=20=EC=A1=B0=EA=B1=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/ui/board/GradDateFragment.kt | 5 +++++ .../ui/board/viewmodel/GradDateViewModel.kt | 22 ++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/umc/com/mobile/project/ui/board/GradDateFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/board/GradDateFragment.kt index 3684339..f7e6487 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/board/GradDateFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/board/GradDateFragment.kt @@ -113,6 +113,11 @@ class GradDateFragment : Fragment() { binding.tvGradDateDday.text = "D-$dday" } + //api에서 메모 hint로 가져오기 + viewModel._dateResponse2.observe(viewLifecycleOwner) { response -> + binding.tvGradDateMemo.hint = response!!.result.message + } + //수정하기 및 버튼 visible 조건 viewModel.isEditMode.observe(viewLifecycleOwner, Observer { isEditMode -> if (isEditMode) { diff --git a/app/src/main/java/umc/com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt index 59b14f0..cceeef1 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt @@ -14,9 +14,11 @@ import umc.com.mobile.project.data.model.home.UpdateGradDateRequest import umc.com.mobile.project.data.model.home.UpdateGradDateResponse import umc.com.mobile.project.data.network.ApiClient import umc.com.mobile.project.data.network.api.HomeApi +import java.text.SimpleDateFormat import java.time.LocalDate import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit +import java.util.Locale class GradDateViewModel : ViewModel() { val _selectedDate: MutableLiveData = MutableLiveData() @@ -55,10 +57,6 @@ class GradDateViewModel : ViewModel() { val isEditMode: LiveData get() = _isEditMode - init { - cheeringMessage.value = "" - } - fun init() { _isEditMode.value = false } @@ -86,12 +84,9 @@ class GradDateViewModel : ViewModel() { _isEditMode.value = !_isEditMode.value!! } - //전의 메모랑 같으면 저장 안됨 - private var previousMessage: String? = null - private var previousDDay: Int? = null - //버튼 활성화 조건 val isButtonEnabled = MediatorLiveData().apply { + //이전 메모랑 내용 같으면 저장 안됨 var previousMessage: String? = null var previousDDay: String? = null @@ -99,14 +94,14 @@ class GradDateViewModel : ViewModel() { val cheeringMessageObserver = Observer { currentMessage -> val dDayValue = _dday.value value = - previousMessage != currentMessage && currentMessage.isNotEmpty() && dDayValue != null && dDayValue != 0 + previousMessage != currentMessage && currentMessage.isNotEmpty() previousMessage = currentMessage } //_dday 값이 변경될 때마다 실행 val dDayObserver = Observer { currentDDay -> val messageValue = cheeringMessage.value value = - previousDDay != currentDDay.toString() && currentDDay != null && currentDDay != 0 && messageValue != null && messageValue.isNotEmpty() + previousDDay != currentDDay.toString() && currentDDay != null && currentDDay != 0 previousDDay = currentDDay.toString() } addSource(cheeringMessage, cheeringMessageObserver) @@ -124,6 +119,13 @@ class GradDateViewModel : ViewModel() { if (dateInfoResponse != null) { dateResponse.postValue(dateInfoResponse)//home에 있어서 놔둠 _dateResponse2.postValue(dateInfoResponse) + val originalFormat = SimpleDateFormat("yyyy-MM-dd", Locale.KOREA) + val targetFormat = SimpleDateFormat("yyyy-M월-d", Locale.KOREA) + if (dateInfoResponse.result.dday != null) { + val date = originalFormat.parse(dateInfoResponse.result.gradDate) + val formattedDate = targetFormat.format(date) + _selectedDateRequest.value = formattedDate + } if (_dateResponse2.value != null && _dateResponse2.value!!.result != null) { _selectedDate.value = _dateResponse2.value!!.result.gradDate } From 7b1aed74b07b808bafd601475e1e378b4bb26754 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:01:28 +0900 Subject: [PATCH 09/14] =?UTF-8?q?Fix:=20=EC=A1=B8=EC=97=85=EC=98=88?= =?UTF-8?q?=EC=A0=95=EC=9D=BC=20null=20=EC=9D=BC=EB=95=8C=20=EB=A9=98?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/fragment_grad_date.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/fragment_grad_date.xml b/app/src/main/res/layout/fragment_grad_date.xml index 94ca895..042dec2 100644 --- a/app/src/main/res/layout/fragment_grad_date.xml +++ b/app/src/main/res/layout/fragment_grad_date.xml @@ -76,7 +76,7 @@ android:layout_marginStart="57dp" android:layout_marginTop="17dp" android:layout_marginEnd="52dp" - android:text="@{String.format(`졸업 예정일 %s`, vm.selectedDate)}" + android:text='@{vm.selectedDate != null ? String.format("졸업 예정일 %s", vm.selectedDate) : "선택해주세요"}' android:textAppearance="@style/MediumFont.14" android:textColor="#555555" app:layout_constraintEnd_toEndOf="@+id/iv_grad_date_card1" @@ -116,7 +116,7 @@ style="@style/BoldFont.30" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@{String.format(`D - %s`, vm.dday)}" + android:text='@{vm.dday != null ? String.format("D - %s", vm.dday) : "D -"}' android:textColor="#7D7D7D" app:layout_constraintBottom_toBottomOf="@+id/iv_grad_date_card2" app:layout_constraintEnd_toEndOf="@+id/iv_grad_date_card2" From 7cf2aaaca5f147d599f842806910eb0da73ffda5 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sun, 18 Feb 2024 00:34:09 +0900 Subject: [PATCH 10/14] =?UTF-8?q?Fix:=20=EC=BB=A4=EB=A6=AC=EC=96=B4=20?= =?UTF-8?q?=EB=8D=94=ED=95=98=EA=B8=B0=20=EB=B4=89=EC=82=AC=ED=99=9C?= =?UTF-8?q?=EB=8F=99=20=EB=B2=84=ED=8A=BC=20=ED=99=9C=EC=84=B1=ED=99=94=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=EC=97=90=20=EB=B4=89=EC=82=AC=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/career/viewmodel/CareerAddVolunteerViewModel.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddVolunteerViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddVolunteerViewModel.kt index eea2d43..24ec08d 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddVolunteerViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddVolunteerViewModel.kt @@ -43,9 +43,8 @@ class CareerAddVolunteerViewModel : ViewModel() { } private fun areBothFieldsFilled(): Boolean { - return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && isDateValid( - startDate.value - ) && isDateValid(endDate.value) + return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && !hour.value.isNullOrBlank() + && isDateValid(startDate.value) && isDateValid(endDate.value) } private fun isDateValid(date: String?): Boolean { From 4f6a65fd9dde9593e0437ccd559070ca83fba1c7 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sun, 18 Feb 2024 02:09:13 +0900 Subject: [PATCH 11/14] =?UTF-8?q?Feat:=20=EC=BB=A4=EB=A6=AC=EC=96=B4=20?= =?UTF-8?q?=EB=8C=80=EC=99=B8=ED=99=9C=EB=8F=99=20=EB=8D=94=ED=95=98?= =?UTF-8?q?=EA=B8=B0/=EC=88=98=EC=A0=95=ED=95=98=EA=B8=B0=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=A1=B0=EA=B1=B4=EC=97=90=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=EC=A6=88=20=EC=A0=9C=ED=95=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewmodel/CareerAddActivityViewModel.kt | 37 ++++++++++++------- .../viewmodel/CareerEditActivityViewModel.kt | 23 +++++++++++- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddActivityViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddActivityViewModel.kt index 29f1f48..4ce6d01 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddActivityViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerAddActivityViewModel.kt @@ -28,12 +28,14 @@ class CareerAddActivityViewModel : ViewModel() { val endDate: MutableLiveData = MutableLiveData() val fileAddedEvent: MutableLiveData = MutableLiveData() val imageList: MutableList = mutableListOf() + val totalFileSize = MutableLiveData(0) init { title.value = "" startDate.value = "" endDate.value = "" imageList.clear() + totalFileSize.value = 0 } fun init() { @@ -41,6 +43,7 @@ class CareerAddActivityViewModel : ViewModel() { startDate.value = "" endDate.value = "" imageList.clear() + totalFileSize.value = 0 } /* 버튼 활성화 기능 */ @@ -48,22 +51,29 @@ class CareerAddActivityViewModel : ViewModel() { addSource(title) { value = areBothFieldsFilled() } addSource(startDate) { value = areBothFieldsFilled() } addSource(endDate) { value = areBothFieldsFilled() } + addSource(totalFileSize) { value = areBothFieldsFilled() } } private fun areBothFieldsFilled(): Boolean { return !(title.value.isNullOrEmpty() || title.value!!.contains(" ") || title.value!!.length > 20) && isDateValid( startDate.value - ) && isDateValid(endDate.value) + ) && isDateValid(endDate.value) && isFileSizeValid() } private fun isDateValid(date: String?): Boolean { return !date.isNullOrBlank() && date.length == 8 } + //파일 사이즈가 30MB를 넘지 않는지 체크 + private fun isFileSizeValid(): Boolean { + return totalFileSize.value ?: 0 <= 30 * 1024 * 1024 + } + fun addImageFile(file: File) { val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), file) val body = MultipartBody.Part.createFormData("image", file.name, requestFile) imageList.add(body) + calculateTotalFileSize() //파일 사이즈 계산 fileAddedEvent.value = true } @@ -93,9 +103,20 @@ class CareerAddActivityViewModel : ViewModel() { val filePart = MultipartBody.Part.createFormData("image", fileName, requestFile) imageList.add(filePart) + calculateTotalFileSize() //파일 사이즈 계산 fileAddedEvent.value = true } + //파일 사이즈 측정 + fun calculateTotalFileSize() { + var totalSize: Long = 0 + for (filePart in imageList) { + val file = filePart.body + totalSize += file?.contentLength() ?: 0 + } + totalFileSize.value = totalSize + } + //API에 전송할 데이터를 포함하는 RequestDto 생성 함수 fun createRequestDto(): ActivityDto? { val startDateString = startDate.value @@ -135,18 +156,6 @@ class CareerAddActivityViewModel : ViewModel() { val requestDtoPart: RequestBody = requestDtoJson.toRequestBody("application/json".toMediaTypeOrNull()) - //파일 사이즈 측정 - fun calculateTotalFileSize(): Long { - var totalSize: Long = 0 - for (filePart in imageList) { - val file = filePart.body - totalSize += file?.contentLength() ?: 0 - } - return totalSize - } - - val totalFileSize = calculateTotalFileSize() - Log.d("File Size", "Total File Size: $totalFileSize bytes") careerApiService.addCareer(imageList, requestDtoPart) .enqueue(object : Callback { override fun onResponse( @@ -158,7 +167,7 @@ class CareerAddActivityViewModel : ViewModel() { if (addCareerResponse != null) { _addedCareerInfo.postValue(addCareerResponse) Log.d("addCareer:Extras 성공", "${response.body()}") - Log.d("addSuccessFileName", imageList.toString()) + Log.d("totalFileSize", totalFileSize.value.toString()) } else { _error.postValue("서버 응답이 올바르지 않습니다.") } diff --git a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditActivityViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditActivityViewModel.kt index 3b577c6..016cf03 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditActivityViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/career/viewmodel/CareerEditActivityViewModel.kt @@ -36,6 +36,7 @@ class CareerEditActivityViewModel : ViewModel() { val addFilesLive: MutableLiveData = MutableLiveData().apply { value = addFiles.isNotEmpty() } + val totalFileSize = MutableLiveData(0) init { studentId.value = 0 @@ -44,6 +45,7 @@ class CareerEditActivityViewModel : ViewModel() { startDate.value = "" endDate.value = "" addFiles.clear() + totalFileSize.value = 0 } fun init() { @@ -53,6 +55,7 @@ class CareerEditActivityViewModel : ViewModel() { endDate.value = "" addFiles.clear() addFilesLive.value = addFiles.isNotEmpty() + totalFileSize.value = 0 } val isFilledAnyOptions: LiveData = MediatorLiveData().apply { @@ -61,21 +64,28 @@ class CareerEditActivityViewModel : ViewModel() { addSource(startDate) { value = isAnyFieldFilled() } addSource(endDate) { value = isAnyFieldFilled() } addSource(addFilesLive) { value = isAnyFieldFilled() } + addSource(totalFileSize) { value = isAnyFieldFilled() } } private fun isAnyFieldFilled(): Boolean { - return !title.value.isNullOrBlank() || !startDate.value.isNullOrBlank() || !endDate.value.isNullOrBlank() || (addFilesLive.value ?: false) + return (!title.value.isNullOrBlank() || !startDate.value.isNullOrBlank() || !endDate.value.isNullOrBlank() || addFilesLive.value ?: false) && isFileSizeValid() } private fun isDateValid(date: String?): Boolean { return date.isNullOrBlank() || date.length == 8 } + //파일 사이즈가 30MB를 넘지 않는지 체크 + private fun isFileSizeValid(): Boolean { + return totalFileSize.value ?: 0 <= 30 * 1024 * 1024 + } + fun addImageFile(file: File) { val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), file) val body = MultipartBody.Part.createFormData("addFiles", file.name, requestFile) addFiles.add(body) addFilesLive.value = addFiles.isNotEmpty() + calculateTotalFileSize() //파일 사이즈 계산 fileAddedEvent.value = true } @@ -105,9 +115,20 @@ class CareerEditActivityViewModel : ViewModel() { val filePart = MultipartBody.Part.createFormData("addFiles", fileName, requestFile) addFiles.add(filePart) addFilesLive.value = addFiles.isNotEmpty() + calculateTotalFileSize() //파일 사이즈 계산 fileAddedEvent.value = true } + //파일 사이즈 측정 + fun calculateTotalFileSize() { + var totalSize: Long = 0 + for (filePart in addFiles) { + val file = filePart.body + totalSize += file?.contentLength() ?: 0 + } + totalFileSize.value = totalSize + } + private val careerApiService = ApiClient.createService() private val _activityDetailInfo: MutableLiveData = MutableLiveData() From 973074c02fc1bda226586803381fb423a21c51cf Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sun, 18 Feb 2024 11:08:31 +0900 Subject: [PATCH 12/14] =?UTF-8?q?Remove:=20=EC=A1=B8=EC=97=85=20=EC=98=88?= =?UTF-8?q?=EC=A0=95=EC=9D=BC=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/umc/com/mobile/project/ui/board/GradDateFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/umc/com/mobile/project/ui/board/GradDateFragment.kt b/app/src/main/java/umc/com/mobile/project/ui/board/GradDateFragment.kt index f7e6487..06265c9 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/board/GradDateFragment.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/board/GradDateFragment.kt @@ -69,7 +69,7 @@ class GradDateFragment : Fragment() { val date = originalFormat.parse(dateString) val formattedDate = targetFormat.format(date) viewModel.updateDateInfo(formattedDate) - Toast.makeText(context, "저장되었습니다.", Toast.LENGTH_LONG).show() + //Toast.makeText(context, "저장되었습니다.", Toast.LENGTH_LONG).show() navigate(R.id.action_fragment_date_to_fragment_home) viewModel.onEditButtonClick() } catch (e: ParseException) { From 18ed985a2a09d919533537b466e10a8f122c9bd8 Mon Sep 17 00:00:00 2001 From: kimyujin-com <80165026+kimyujin-com@users.noreply.github.com> Date: Sun, 18 Feb 2024 11:17:28 +0900 Subject: [PATCH 13/14] =?UTF-8?q?Fix:=20=EC=A1=B8=EC=97=85=20=EC=98=88?= =?UTF-8?q?=EC=A0=95=EC=9D=BC,=20=EC=BB=A4=EB=A6=AC=EC=96=B4=20xml=20conte?= =?UTF-8?q?xt=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/fragment_career.xml | 2 +- app/src/main/res/layout/fragment_grad_date.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/fragment_career.xml b/app/src/main/res/layout/fragment_career.xml index 0cac486..2076eee 100644 --- a/app/src/main/res/layout/fragment_career.xml +++ b/app/src/main/res/layout/fragment_career.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".ui.setting.SettingFragment"> + tools:context="ui.career.CareerFragment"> + tools:context=".ui.board.GradDateFragment"> Date: Sun, 18 Feb 2024 11:29:07 +0900 Subject: [PATCH 14/14] =?UTF-8?q?Remove:=20=EC=A1=B8=EC=97=85=EC=98=88?= =?UTF-8?q?=EC=A0=95=EC=9D=BC=20=EB=B6=88=ED=95=84=EC=9A=94=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/umc/com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt b/app/src/main/java/umc/com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt index cceeef1..70e8fdd 100644 --- a/app/src/main/java/umc/com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt +++ b/app/src/main/java/umc/com/mobile/project/ui/board/viewmodel/GradDateViewModel.kt @@ -126,9 +126,6 @@ class GradDateViewModel : ViewModel() { val formattedDate = targetFormat.format(date) _selectedDateRequest.value = formattedDate } - if (_dateResponse2.value != null && _dateResponse2.value!!.result != null) { - _selectedDate.value = _dateResponse2.value!!.result.gradDate - } Log.d("gradDate", "${response.body()}") } else { _error.postValue("서버 응답이 올바르지 않습니다.")