diff --git a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/FixedRoundedSpinnerAdapter.kt b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/FixedRoundedSpinnerAdapter.kt new file mode 100644 index 00000000..4874ebeb --- /dev/null +++ b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/FixedRoundedSpinnerAdapter.kt @@ -0,0 +1,31 @@ +package com.example.spoteam_android.ui.study + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.TextView +import com.example.spoteam_android.R +import com.example.spoteam_android.databinding.SpinnerDropdownItemBinding + +class FixedRoundedSpinnerAdapter( + context: Context, + private val items: List +) : ArrayAdapter(context, R.layout.spinner_item, items) { + + override fun getDropDownView(position: Int, convertView: android.view.View?, parent: ViewGroup): android.view.View { + val binding = SpinnerDropdownItemBinding.inflate(LayoutInflater.from(context), parent, false) + + binding.spinnerText.text = items[position] + + val background = when (position) { + 0 -> R.drawable.spinner_item_top + items.size - 1 -> R.drawable.spinner_item_bottom + else -> R.drawable.spinner_item_middle + } + + binding.itemContainer.setBackgroundResource(background) + return binding.root + } +} \ No newline at end of file diff --git a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/MemberNumberRVAdapter.kt b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/MemberNumberRVAdapter.kt index f7a6f4f4..5cb5e4e2 100644 --- a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/MemberNumberRVAdapter.kt +++ b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/MemberNumberRVAdapter.kt @@ -16,7 +16,9 @@ class MemberNumberRVAdapter( private var selectedPosition: Int = 0 var onItemClick: ((position: Int) -> Unit)? = null - inner class ViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) { + inner class ViewHolder(view: ViewGroup) : RecyclerView.ViewHolder(view) { + val textView: TextView = view.findViewById(R.id.tv_member_number) + init { textView.setOnClickListener { onItemClick?.invoke(bindingAdapterPosition) @@ -24,36 +26,41 @@ class MemberNumberRVAdapter( } } + fun getSelectedNumber(): Int { return items.getOrNull(selectedPosition) ?: 0 } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) - .inflate(R.layout.item_member_number, parent, false) as TextView - return ViewHolder(view) + .inflate(R.layout.item_member_number, parent, false) + + val itemWidth = parent.context.resources.displayMetrics.widthPixels / 5 + view.layoutParams = RecyclerView.LayoutParams(itemWidth, ViewGroup.LayoutParams.WRAP_CONTENT) + + return ViewHolder(view as ViewGroup) } + + + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { val number = items[position] val context = holder.itemView.context val typefaceBold = ResourcesCompat.getFont(context, R.font.suit_bold) - val typefaceRegular = ResourcesCompat.getFont(context, R.font.suit_variable) - holder.textView.text = number.toString() if (position == selectedPosition) { - holder.textView.setTextColor(Color.BLACK) - holder.textView.textSize = 24f - holder.textView.typeface = typefaceBold + holder.textView.setBackgroundResource(R.drawable.page_bg) } else { - holder.textView.setTextColor(Color.GRAY) - holder.textView.textSize = 24f - holder.textView.typeface = typefaceRegular + holder.textView.setBackgroundColor(Color.TRANSPARENT) } } + + override fun getItemCount(): Int = items.size fun setSelectedPosition(position: Int) { diff --git a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/MemberStudyFragment.kt b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/MemberStudyFragment.kt index e0fa7bbb..53c488da 100644 --- a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/MemberStudyFragment.kt +++ b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/MemberStudyFragment.kt @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.LinearSnapHelper import androidx.recyclerview.widget.RecyclerView import com.example.spoteam_android.R import com.example.spoteam_android.databinding.FragmentMemberStudyBinding +import com.example.spoteam_android.ui.study.FixedRoundedSpinnerAdapter import com.example.spoteam_android.ui.study.MemberNumberRVAdapter import com.example.spoteam_android.ui.study.OnlineStudyFragment @@ -35,8 +36,12 @@ class MemberStudyFragment : Fragment() { goToPreviusFragment() } - val numbers = (0..9).toList() + val numbers = (1..9).toList() memberAdapter = MemberNumberRVAdapter(numbers) + val snapHelper = LinearSnapHelper() + snapHelper.attachToRecyclerView(binding.rvMemberStudyNum) + + binding.rvMemberStudyNum.adapter = memberAdapter @@ -44,46 +49,30 @@ class MemberStudyFragment : Fragment() { memberAdapter.onItemClick = { position -> - binding.rvMemberStudyNum.smoothScrollToPosition(position) - - val selectedNumber = numbers[position] + smoothScrollToCenter(position) memberAdapter.setSelectedPosition(position) - binding.selectedNumberText.text = "${String.format("%02d", selectedNumber)}명" + binding.selectedNumberText.text = "${String.format("%02d", numbers[position])}명" + binding.fragmentMemberStudyBt.isEnabled = true } + + + + + + return binding.root } + private fun setupSpinners() { - // 참여 인원 Spinner 설정 - // 성별 Spinner 설정 - val genderSpinner: Spinner = binding.fragmentMemberStudyGenderSpinner - val genderAdapter = ArrayAdapter.createFromResource( - requireContext(), - R.array.gender_array, - R.layout.spinner_item - ) - genderAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item) - genderSpinner.adapter = genderAdapter + val genderList = listOf("누구나", "남성", "여성") + val genderAdapter = FixedRoundedSpinnerAdapter(requireContext(), genderList) + binding.fragmentMemberStudyGenderSpinner.adapter = genderAdapter } -// private fun setupSpinners() { -// val context = requireContext() -// -// // 참여 인원 Spinner 설정 -// val numSpinner: Spinner = binding.fragmentMemberStudyNumSpinner -// val numItems = resources.getStringArray(R.array.fragment_study_num_spinner_array).toList() -// val numAdapter = CustomSpinnerAdapter(context, numItems) -// numSpinner.adapter = numAdapter -// -// // 성별 Spinner 설정 -// val genderSpinner: Spinner = binding.fragmentMemberStudyGenderSpinner -// val genderItems = resources.getStringArray(R.array.gender_array).toList() -// val genderAdapter = CustomSpinnerAdapter(context, genderItems) -// genderSpinner.adapter = genderAdapter -// } private fun setupRangeSlider() { @@ -117,7 +106,6 @@ class MemberStudyFragment : Fragment() { val minAge = ageRangeSlider.values[0].toInt() val maxAge = ageRangeSlider.values[1].toInt() - // profileImage를 ViewModel에서 가져오는 예시 val profileImage = viewModel.studyRequest.value?.profileImage viewModel.setStudyData( @@ -136,6 +124,26 @@ class MemberStudyFragment : Fragment() { } +// private fun updateNextButtonState() { +// val isChecked = binding. +// +// if (isOnline) { +// binding.fragmentOnlineStudyBt.isEnabled = true +// binding.fragmentOnlineStudyBt.visibility = View.VISIBLE +// binding.fragmentOnlineStudyLocationPlusBt.visibility = View.GONE +// } else { +// if (hasChip) { +// binding.fragmentOnlineStudyBt.isEnabled = true +// binding.fragmentOnlineStudyBt.visibility = View.VISIBLE +// binding.fragmentOnlineStudyLocationPlusBt.visibility = View.GONE +// } else { +// binding.fragmentOnlineStudyBt.isEnabled = false +// binding.fragmentOnlineStudyBt.visibility = View.GONE +// binding.fragmentOnlineStudyLocationPlusBt.visibility = View.VISIBLE +// } +// } +// } + private fun goToNextFragment() { val transaction = parentFragmentManager.beginTransaction() transaction.replace(R.id.main_frm, ActivityFeeStudyFragment()) @@ -148,4 +156,26 @@ class MemberStudyFragment : Fragment() { transaction.addToBackStack(null) // 백스택에 추가 transaction.commit() } + private fun smoothScrollToCenter(position: Int) { + val layoutManager = binding.rvMemberStudyNum.layoutManager as LinearLayoutManager + val view = layoutManager.findViewByPosition(position) + if (view != null) { + val rvCenterX = binding.rvMemberStudyNum.width / 2 + val viewCenterX = view.left + view.width / 2 + val scrollBy = viewCenterX - rvCenterX + binding.rvMemberStudyNum.smoothScrollBy(scrollBy, 0) + } else { + binding.rvMemberStudyNum.scrollToPosition(position) + binding.rvMemberStudyNum.post { + val v = layoutManager.findViewByPosition(position) + v?.let { + val rvCenterX = binding.rvMemberStudyNum.width / 2 + val viewCenterX = it.left + it.width / 2 + val scrollBy = viewCenterX - rvCenterX + binding.rvMemberStudyNum.smoothScrollBy(scrollBy, 0) + } + } + } + } + } \ No newline at end of file diff --git a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/OnlineStudyFragment.kt b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/OnlineStudyFragment.kt index 6ecc33f3..6b54d044 100644 --- a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/OnlineStudyFragment.kt +++ b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/OnlineStudyFragment.kt @@ -1,283 +1,289 @@ -package com.example.spoteam_android.ui.study - -import LocationStudyFragment -import MemberStudyFragment -import StudyRequest -import StudyViewModel -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 com.bumptech.glide.Glide -import com.example.spoteam_android.R -import com.example.spoteam_android.databinding.FragmentOnlineStudyBinding -import com.example.spoteam_android.util.parseLocationTsv -import com.google.android.material.chip.Chip - -class OnlineStudyFragment : Fragment() { - private lateinit var binding: FragmentOnlineStudyBinding - private val viewModel: StudyViewModel by activityViewModels() - - private var isLocationPlusVisible: Boolean = false - private var selectedLocationCode: String? = null - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentOnlineStudyBinding.inflate(inflater, container, false) - - selectedLocationCode = null - val locationList = parseLocationTsv(requireContext()) - viewModel.setLocationList(locationList) - - if (viewModel.mode.value == StudyFormMode.CREATE) { - viewModel.clearRegions() - arguments?.let { - val address = it.getString("ADDRESS") - val isOffline = it.getBoolean("IS_OFFLINE", false) - selectedLocationCode = it.getString("CODE") - - if (isOffline) { - address?.let { addr -> updateChip(addr) } - setChipState(false) // 오프라인일 경우 offline 체크 - isLocationPlusVisible = true - updateLocationPlusLayoutVisibility(true) - } else { + package com.example.spoteam_android.ui.study + + import LocationStudyFragment + import MemberStudyFragment + import StudyRequest + import StudyViewModel + 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 com.bumptech.glide.Glide + import com.example.spoteam_android.R + import com.example.spoteam_android.databinding.FragmentOnlineStudyBinding + import com.example.spoteam_android.util.parseLocationTsv + import com.google.android.material.chip.Chip + + class OnlineStudyFragment : Fragment() { + private lateinit var binding: FragmentOnlineStudyBinding + private val viewModel: StudyViewModel by activityViewModels() + + private var isLocationPlusVisible: Boolean = false + private var selectedLocationCode: String? = null + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentOnlineStudyBinding.inflate(inflater, container, false) + + selectedLocationCode = null + val locationList = parseLocationTsv(requireContext()) + viewModel.setLocationList(locationList) + + if (viewModel.mode.value == StudyFormMode.CREATE) { + viewModel.clearRegions() + arguments?.let { + val address = it.getString("ADDRESS") + val isOffline = it.getBoolean("IS_OFFLINE", false) + selectedLocationCode = it.getString("CODE") + + if (isOffline) { + address?.let { addr -> updateChip(addr) } + setChipState(false) + isLocationPlusVisible = true + updateLocationPlusLayoutVisibility(true) + } else { + clearChipSelection() + updateLocationPlusLayoutVisibility(false) + binding.fragmentOnlineStudyBt.isEnabled = false + } + } ?: run { clearChipSelection() updateLocationPlusLayoutVisibility(false) binding.fragmentOnlineStudyBt.isEnabled = false } - } ?: run { - clearChipSelection() - updateLocationPlusLayoutVisibility(false) - binding.fragmentOnlineStudyBt.isEnabled = false } - } - viewModel.studyRequest.observe(viewLifecycleOwner) { request -> - if (viewModel.mode.value == StudyFormMode.EDIT) { - Log.d("OnlineStudyFragment", "observe - isOnline: ${request.isOnline}, regions: ${request.regions}") - setChipState(request.isOnline) - isLocationPlusVisible = !request.isOnline - updateLocationPlusLayoutVisibility(isLocationPlusVisible) - - request.regions?.firstOrNull()?.let { code -> - selectedLocationCode = code - val address = viewModel.findAddressFromCode(code) - address?.let { updateChip(it) } + viewModel.studyRequest.observe(viewLifecycleOwner) { request -> + if (viewModel.mode.value == StudyFormMode.EDIT) { + setChipState(request.isOnline) + isLocationPlusVisible = !request.isOnline + updateLocationPlusLayoutVisibility(isLocationPlusVisible) + + val newCode = request.regions?.firstOrNull() + + if (!request.isOnline && newCode != null && newCode != selectedLocationCode) { + val address = viewModel.findAddressFromCode(newCode) + address?.let { + updateChip(it) + selectedLocationCode = newCode + } + } else if (!request.isOnline && newCode == null) { + binding.locationChip.visibility = View.GONE + } } } - } + setupChipGroupListener() + setupChipCloseListener() + binding.fragmentOnlineStudyBt.setOnClickListener { + saveData() + goToNextFragment() + } - setupChipGroupListener() - setupChipCloseListener() + binding.fragmentOnlineStudyLocationPlusBt.setOnClickListener { + goToLocationFragment() + } - binding.fragmentOnlineStudyBt.setOnClickListener { - saveData() - goToNextFragment() - } + binding.fragmentOnlineStudyBackBt.setOnClickListener { + goToPreviusFragment() + } - binding.fragmentOnlineStudyLocationPlusBt.setOnClickListener { - goToLocationFragment() + return binding.root } - binding.fragmentOnlineStudyBackBt.setOnClickListener { - goToPreviusFragment() + override fun onResume() { + super.onResume() + // ✅ LOCATION 화면에서 넘어왔을 때 처리 + arguments?.let { + val address = it.getString("ADDRESS") + val code = it.getString("CODE") + + if (!address.isNullOrBlank() && !code.isNullOrBlank()) { + updateChip(address) + selectedLocationCode = code + + val current = viewModel.studyRequest.value + if (viewModel.mode.value == StudyFormMode.EDIT && current != null) { + val updated = current.copy(regions = listOf(code)) + viewModel.setStudyData( + title = updated.title, + goal = updated.goal, + introduction = updated.introduction, + isOnline = updated.isOnline, + profileImage = updated.profileImage, + regions = updated.regions, + maxPeople = updated.maxPeople, + gender = updated.gender, + minAge = updated.minAge, + maxAge = updated.maxAge, + fee = updated.fee + ) + } + } + + // ✅ 재처리 방지를 위해 초기화 + it.clear() + } } - return binding.root - } - private fun clearChipSelection() { - binding.fragmentOnlineStudyChipOnline.isChecked = false - binding.fragmentOnlineStudyChipOffline.isChecked = false - } + private fun updateChip(address: String) { + binding.locationChip.apply { + visibility = View.VISIBLE + text = address + } + binding.locationChip.post { + updateNextButtonState() + } + } - private fun setupChipGroupListener() { - binding.fragmentOnlineStudyChipOnline.setOnClickListener { - selectChip(binding.fragmentOnlineStudyChipOnline) + private fun setupChipGroupListener() { + binding.fragmentOnlineStudyChipOnline.setOnClickListener { + selectChip(binding.fragmentOnlineStudyChipOnline) + } + binding.fragmentOnlineStudyChipOffline.setOnClickListener { + selectChip(binding.fragmentOnlineStudyChipOffline) + } } - binding.fragmentOnlineStudyChipOffline.setOnClickListener { - selectChip(binding.fragmentOnlineStudyChipOffline) + private fun selectChip(selectedChip: Chip) { + binding.fragmentOnlineStudyChipOnline.isChecked = false + binding.fragmentOnlineStudyChipOffline.isChecked = false + selectedChip.isChecked = true + + val isOnline = selectedChip.id == R.id.fragment_online_study_chip_online + isLocationPlusVisible = !isOnline + + if (viewModel.mode.value == StudyFormMode.CREATE) { + val current = viewModel.studyRequest.value ?: StudyRequest( + themes = listOf("어학"), + title = "", + goal = "", + introduction = "", + isOnline = true, + profileImage = null, + regions = null, + maxPeople = 0, + gender = Gender.UNKNOWN, + minAge = 0, + maxAge = 0, + fee = 0, + hasFee = false + ) + + viewModel.setStudyData( + title = current.title, + goal = current.goal, + introduction = current.introduction, + isOnline = isOnline, + profileImage = current.profileImage, + regions = if (isOnline) null else current.regions ?: mutableListOf(), + maxPeople = current.maxPeople, + gender = current.gender, + minAge = current.minAge, + maxAge = current.maxAge, + fee = current.fee + ) + } + + updateLocationPlusLayoutVisibility(isLocationPlusVisible) + updateNextButtonState() } - } - - private fun selectChip(selectedChip: Chip) { - // Chip UI 업데이트 - binding.fragmentOnlineStudyChipOnline.isChecked = false - binding.fragmentOnlineStudyChipOffline.isChecked = false - selectedChip.isChecked = true - - val isOnline = selectedChip.id == R.id.fragment_online_study_chip_online - isLocationPlusVisible = !isOnline - - // ✅ 등록 모드에서만 ViewModel 값 업데이트 - if (viewModel.mode.value == StudyFormMode.CREATE) { - val currentStudyRequest = viewModel.studyRequest.value ?: StudyRequest( - themes = listOf("어학"), - title = "", - goal = "", - introduction = "", - isOnline = true, - profileImage = null, - regions = null, - maxPeople = 0, - gender = Gender.UNKNOWN, - minAge = 0, - maxAge = 0, - fee = 0, - hasFee = false - ) - viewModel.setStudyData( - title = currentStudyRequest.title, - goal = currentStudyRequest.goal, - introduction = currentStudyRequest.introduction, - isOnline = isOnline, - profileImage = currentStudyRequest.profileImage, - regions = if (isOnline) null else currentStudyRequest.regions ?: mutableListOf(), - maxPeople = currentStudyRequest.maxPeople, - gender = currentStudyRequest.gender, - minAge = currentStudyRequest.minAge, - maxAge = currentStudyRequest.maxAge, - fee = currentStudyRequest.fee - ) + private fun setupChipCloseListener() { + binding.locationChip.setOnCloseIconClickListener { + binding.locationChip.visibility = View.GONE + selectedLocationCode = null + + if (viewModel.mode.value == StudyFormMode.EDIT) { + val current = viewModel.studyRequest.value + val cleared = current?.copy(regions = null) + cleared?.let { + viewModel.setStudyData( + title = it.title, + goal = it.goal, + introduction = it.introduction, + isOnline = it.isOnline, + profileImage = it.profileImage, + regions = it.regions, + maxPeople = it.maxPeople, + gender = it.gender, + minAge = it.minAge, + maxAge = it.maxAge, + fee = it.fee + ) + } + } + + updateNextButtonState() + } } - updateLocationPlusLayoutVisibility(isLocationPlusVisible) - updateNextButtonState() - } + private fun setChipState(isOnline: Boolean) { + binding.fragmentOnlineStudyChipOnline.isChecked = isOnline + binding.fragmentOnlineStudyChipOffline.isChecked = !isOnline + } + private fun updateLocationPlusLayoutVisibility(visible: Boolean) { + binding.fragmentOnlineStudyLocationPlusCl.visibility = if (visible) View.VISIBLE else View.GONE + binding.fragmentOnlineStudyBt.visibility = if (visible) View.GONE else View.VISIBLE + binding.fragmentOnlineStudyLocationPlusBt.visibility = if (visible) View.VISIBLE else View.GONE + } + private fun updateNextButtonState() { + val isOnline = binding.fragmentOnlineStudyChipOnline.isChecked + val hasChip = binding.locationChip.visibility == View.VISIBLE + binding.fragmentOnlineStudyBt.isEnabled = isOnline || hasChip + binding.fragmentOnlineStudyBt.visibility = if (isOnline || hasChip) View.VISIBLE else View.GONE + binding.fragmentOnlineStudyLocationPlusBt.visibility = if (isOnline || hasChip) View.GONE else View.VISIBLE + } + private fun saveData() { + val current = viewModel.studyRequest.value ?: return + val regions = selectedLocationCode?.let { listOf(it) } ?: listOf() - private fun setupChipCloseListener() { - binding.locationChip.setOnCloseIconClickListener { - binding.locationChip.visibility = View.GONE - updateNextButtonState() + viewModel.setStudyData( + title = current.title, + goal = current.goal, + introduction = current.introduction, + isOnline = current.isOnline, + profileImage = current.profileImage, + regions = if (current.isOnline) null else regions, + maxPeople = current.maxPeople, + gender = current.gender, + minAge = current.minAge, + maxAge = current.maxAge, + fee = current.fee + ) } - } - - private fun setChipState(isOnline: Boolean) { - binding.fragmentOnlineStudyChipOnline.isChecked = isOnline - binding.fragmentOnlineStudyChipOffline.isChecked = !isOnline - } - - - private fun updateLocationPlusLayoutVisibility(visible: Boolean) { - binding.fragmentOnlineStudyLocationPlusCl.visibility = if (visible) View.VISIBLE else View.GONE - binding.fragmentOnlineStudyBt.visibility = if (visible) View.GONE else View.VISIBLE - binding.fragmentOnlineStudyLocationPlusBt.visibility = if (visible) View.VISIBLE else View.GONE - } - - private fun updateNextButtonState() { - val isOnline = binding.fragmentOnlineStudyChipOnline.isChecked - val hasChip = binding.locationChip.visibility == View.VISIBLE - - if (isOnline) { - binding.fragmentOnlineStudyBt.isEnabled = true - binding.fragmentOnlineStudyBt.visibility = View.VISIBLE - binding.fragmentOnlineStudyLocationPlusBt.visibility = View.GONE - } else { - if (hasChip) { - binding.fragmentOnlineStudyBt.isEnabled = true - binding.fragmentOnlineStudyBt.visibility = View.VISIBLE - binding.fragmentOnlineStudyLocationPlusBt.visibility = View.GONE - } else { - binding.fragmentOnlineStudyBt.isEnabled = false - binding.fragmentOnlineStudyBt.visibility = View.GONE - binding.fragmentOnlineStudyLocationPlusBt.visibility = View.VISIBLE - } + private fun clearChipSelection() { + binding.fragmentOnlineStudyChipOnline.isChecked = false + binding.fragmentOnlineStudyChipOffline.isChecked = false } - } - - - private fun saveData() { - val currentStudyRequest = viewModel.studyRequest.value ?: StudyRequest( - themes = listOf("어학"), - title = "", - goal = "", - introduction = "", - isOnline = true, - profileImage = null, - regions = null, - maxPeople = 0, - gender = Gender.UNKNOWN, - minAge = 0, - maxAge = 0, - fee = 0, - hasFee = false - ) - - val currentRegions = currentStudyRequest.regions?.toMutableList() ?: mutableListOf() - - selectedLocationCode?.let { code -> - if (code !in currentRegions) { - currentRegions.add(code) - } + + private fun goToNextFragment() { + parentFragmentManager.beginTransaction() + .replace(R.id.main_frm, MemberStudyFragment()) + .commit() } - viewModel.setStudyData( - title = currentStudyRequest.title, - goal = currentStudyRequest.goal, - introduction = currentStudyRequest.introduction, - isOnline = currentStudyRequest.isOnline, - profileImage = currentStudyRequest.profileImage, - regions = if (currentStudyRequest.isOnline) null else currentRegions, - maxPeople = currentStudyRequest.maxPeople, - gender = currentStudyRequest.gender, - minAge = currentStudyRequest.minAge, - maxAge = currentStudyRequest.maxAge, - fee = currentStudyRequest.fee - ) - } - - - - private fun goToNextFragment() { - val transaction = parentFragmentManager.beginTransaction() - transaction.replace(R.id.main_frm, MemberStudyFragment()) - transaction.commit() - } - - private fun goToPreviusFragment() { - val transaction = parentFragmentManager.beginTransaction() - transaction.replace(R.id.main_frm, IntroduceStudyFragment()) // 변경할 Fragment로 교체 - transaction.addToBackStack(null) // 백스택에 추가 - transaction.commit() - } - - private fun goToLocationFragment() { - val transaction = parentFragmentManager.beginTransaction() - transaction.replace(R.id.main_frm, LocationStudyFragment()) - transaction.commit() - } - -// private fun extractAddressUntilDong(address: String): String { -// val index = address.indexOf("동") -// return if (index != -1) { -// address.substring(0, index + 1) -// } else { -// address -// } -// } - - fun updateChip(address: String) { -// val truncatedAddress = extractAddressUntilDong(address) - binding.locationChip.apply { - visibility = View.VISIBLE - text = address + private fun goToPreviusFragment() { + parentFragmentManager.beginTransaction() + .replace(R.id.main_frm, IntroduceStudyFragment()) + .addToBackStack(null) + .commit() } - binding.locationChip.post { - updateNextButtonState() - } // 하 이코드 떄문에 개고생.. - } -} \ No newline at end of file + + private fun goToLocationFragment() { + parentFragmentManager.beginTransaction() + .replace(R.id.main_frm, LocationStudyFragment()) + .commit() + } + } \ No newline at end of file diff --git a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/StudyViewModel.kt b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/StudyViewModel.kt index da9b433e..3e6cfa92 100644 --- a/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/StudyViewModel.kt +++ b/SPOTeam_android/app/src/main/java/com/example/spoteam_android/ui/study/StudyViewModel.kt @@ -129,9 +129,9 @@ class StudyViewModel : ViewModel() { title: String, goal: String, introduction: String, isOnline: Boolean, profileImage: String?, regions: List?, maxPeople: Int, gender: Gender, minAge: Int, maxAge: Int, fee: Int ) { - val hasFee = fee > 0 - _studyRequest.value = StudyRequest( + + val newRequest = StudyRequest( themes = _themes.value ?: listOf(), title = title, goal = goal, @@ -146,8 +146,18 @@ class StudyViewModel : ViewModel() { fee = fee, hasFee = hasFee ) + + if (_studyRequest.value != newRequest) { + Log.d("StudyViewModel", "✅ studyRequest 값 변경됨. 옵저버 갱신") + _studyRequest.value = newRequest + } else { + Log.d("StudyViewModel", "⚠️ studyRequest 값이 같아서 옵저버 미호출됨") + } + _studyRequest.value = newRequest } + + private fun updateStudyRequest() { _studyRequest.value = _studyRequest.value?.copy( profileImage = _profileImageUri.value, @@ -238,6 +248,10 @@ class StudyViewModel : ViewModel() { fun findAddressFromCode(code: String): String? { return _locationList.find { it.code == code }?.address } + fun findCodeFromAddress(address: String): String? { + return _locationList.firstOrNull { it.address == address }?.code + } + fun reset() { _mode.value = StudyFormMode.CREATE diff --git a/SPOTeam_android/app/src/main/res/drawable/background_spinner_item.xml b/SPOTeam_android/app/src/main/res/drawable/background_spinner_item.xml index 4379c8f3..59cbb882 100644 --- a/SPOTeam_android/app/src/main/res/drawable/background_spinner_item.xml +++ b/SPOTeam_android/app/src/main/res/drawable/background_spinner_item.xml @@ -9,8 +9,8 @@ + - \ No newline at end of file + diff --git a/SPOTeam_android/app/src/main/res/drawable/page_bg.xml b/SPOTeam_android/app/src/main/res/drawable/page_bg.xml new file mode 100644 index 00000000..6783bf52 --- /dev/null +++ b/SPOTeam_android/app/src/main/res/drawable/page_bg.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/SPOTeam_android/app/src/main/res/drawable/spinner_item_bottom.xml b/SPOTeam_android/app/src/main/res/drawable/spinner_item_bottom.xml new file mode 100644 index 00000000..80d3726a --- /dev/null +++ b/SPOTeam_android/app/src/main/res/drawable/spinner_item_bottom.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/SPOTeam_android/app/src/main/res/drawable/spinner_item_middle.xml b/SPOTeam_android/app/src/main/res/drawable/spinner_item_middle.xml new file mode 100644 index 00000000..e654bee9 --- /dev/null +++ b/SPOTeam_android/app/src/main/res/drawable/spinner_item_middle.xml @@ -0,0 +1,4 @@ + + + + diff --git a/SPOTeam_android/app/src/main/res/drawable/spinner_item_top.xml b/SPOTeam_android/app/src/main/res/drawable/spinner_item_top.xml new file mode 100644 index 00000000..81ceebdb --- /dev/null +++ b/SPOTeam_android/app/src/main/res/drawable/spinner_item_top.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/SPOTeam_android/app/src/main/res/drawable/spinner_popup_bg.xml b/SPOTeam_android/app/src/main/res/drawable/spinner_popup_bg.xml new file mode 100644 index 00000000..f386d6a9 --- /dev/null +++ b/SPOTeam_android/app/src/main/res/drawable/spinner_popup_bg.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/SPOTeam_android/app/src/main/res/layout/fragment_member_study.xml b/SPOTeam_android/app/src/main/res/layout/fragment_member_study.xml index 97ce2665..c68abd63 100644 --- a/SPOTeam_android/app/src/main/res/layout/fragment_member_study.xml +++ b/SPOTeam_android/app/src/main/res/layout/fragment_member_study.xml @@ -4,61 +4,61 @@ android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools"> - + app:layout_constraintEnd_toEndOf="parent" + android:layout_marginStart="20dp"> - - + android:src="@drawable/ic_arrow"/> - + android:drawablePadding="20dp"/> + + + + app:layout_constraintTop_toBottomOf="@id/fragment_member_study_pb"/> @@ -66,7 +66,7 @@ android:id="@+id/fragment_member_study_num_frameLayout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="20dp" + android:layout_marginTop="40dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/fragment_member_study_activity_tv"> @@ -77,13 +77,12 @@ android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_centerVertical="true" - android:fontFamily="@font/pretendard" + android:fontFamily="@font/suit_bold" android:layout_marginStart="15dp" android:layout_marginTop="10dp" - android:text="참여인원(스터디장 포함)" + android:text="참여인원" android:textColor="@color/black" - android:textSize="16sp" - android:textStyle="bold" + android:textSize="16dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -92,8 +91,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00명" + android:fontFamily="@font/suit_semi_bold" android:textColor="@color/b500" - android:textSize="18dp" + android:textSize="16dp" android:layout_marginEnd="15dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/fragment_member_study_num_tv" /> @@ -102,10 +102,11 @@ android:id="@+id/rv_member_study_num" android:layout_width="match_parent" android:layout_height="80dp" + android:layout_marginTop="30dp" android:layout_gravity="center" - android:paddingHorizontal="80dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" android:orientation="horizontal" - android:layout_marginTop="50dp" app:layout_constraintTop_toBottomOf="@+id/fragment_member_study_num_tv" /> @@ -113,7 +114,7 @@ @@ -127,10 +128,9 @@ android:layout_gravity="start|center" android:layout_marginStart="15dp" android:text="성별" - android:textStyle="bold" - android:fontFamily="@font/pretendard" + android:fontFamily="@font/suit_bold" android:textColor="@color/black" - android:textSize="16sp" /> + android:textSize="16dp" /> + android:spinnerMode="dropdown" + android:popupBackground="@drawable/spinner_popup_bg"/> @@ -148,6 +149,7 @@ android:id="@+id/fragment_member_study_age_fl" android:layout_width="match_parent" android:layout_height="120dp" + android:layout_marginTop="70dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/fragment_member_study_gender_frameLayout"> @@ -160,10 +162,9 @@ android:layout_marginStart="15dp" android:layout_marginTop="20dp" android:text="연령대" - android:textStyle="bold" - android:fontFamily="@font/pretendard" + android:fontFamily="@font/suit_bold" android:textColor="@color/black" - android:textSize="16sp" /> + android:textSize="16dp" /> @@ -186,8 +190,9 @@ android:layout_marginEnd="60dp" android:layout_marginTop="20dp" android:text="18" - android:textColor="@color/gray_03" - android:textSize="14sp" /> + android:fontFamily="@font/suit_semi_bold" + android:textColor="@color/b500" + android:textSize="14dp" /> + android:text="-" + android:textColor="@color/b500" + android:fontFamily="@font/suit_semi_bold" + android:textSize="14dp" /> + android:textColor="@color/b500" + android:fontFamily="@font/suit_semi_bold" + android:textSize="14dp" /> + android:textColor="@color/b500" + android:fontFamily="@font/suit_semi_bold" + android:textSize="14dp" /> + diff --git a/SPOTeam_android/app/src/main/res/layout/item_member_number.xml b/SPOTeam_android/app/src/main/res/layout/item_member_number.xml index f4d35468..6fa77266 100644 --- a/SPOTeam_android/app/src/main/res/layout/item_member_number.xml +++ b/SPOTeam_android/app/src/main/res/layout/item_member_number.xml @@ -1,10 +1,18 @@ - - + android:gravity="center"> + + + diff --git a/SPOTeam_android/app/src/main/res/layout/spinner_dropdown_item.xml b/SPOTeam_android/app/src/main/res/layout/spinner_dropdown_item.xml index fa337274..c0654140 100644 --- a/SPOTeam_android/app/src/main/res/layout/spinner_dropdown_item.xml +++ b/SPOTeam_android/app/src/main/res/layout/spinner_dropdown_item.xml @@ -1,10 +1,21 @@ - - + + android:minHeight="40dp" + android:orientation="horizontal" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:background="@android:color/transparent" + android:gravity="center_vertical"> + + + diff --git a/SPOTeam_android/app/src/main/res/layout/spinner_item.xml b/SPOTeam_android/app/src/main/res/layout/spinner_item.xml index 891306ad..751342f3 100644 --- a/SPOTeam_android/app/src/main/res/layout/spinner_item.xml +++ b/SPOTeam_android/app/src/main/res/layout/spinner_item.xml @@ -4,7 +4,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" - android:textSize="14dp" - android:textColor="#123456" + android:textSize="15dp" + android:fontFamily="@font/suit_semi_bold" + android:textColor="@color/black" android:drawableEnd="@drawable/ic_down_arrow" android:gravity="center_vertical" /> \ No newline at end of file