Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
android:exported="false" />
<activity android:name=".presentation.user.home.UserQRVerifyActivity" />
<activity android:name=".presentation.user.dashboard.UserSuggestCompleteActivity" />
<activity android:name=".presentation.user.dashboard.UserServiceSuggestActivity" />
<!-- <activity android:name=".presentation.user.dashboard.UserServiceSuggestActivity" />-->
<activity android:name=".presentation.user.review.mypage.UserMyReviewActivity" />
<activity android:name=".presentation.user.review.writing.UserFinishReviewActivity" />
<activity android:name=".presentation.user.review.writing.UserPhotoReviewActivity" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
override fun onStart() {
super.onStart()
// 하단 탭을 눌러 이 프래그먼트에 진입하자마자 제휴 건의 화면으로 이동
val intent = Intent(requireContext(), UserServiceSuggestActivity::class.java)
startActivity(intent)
// val intent = Intent(requireContext(), UserServiceSuggestActivity::class.java)
// startActivity(intent)
}

override fun initView() {
binding.btnSuggestService.setOnClickListener {
val intent = Intent(requireContext(), UserServiceSuggestActivity::class.java)
startActivity(intent)
}
// binding.btnSuggestService.setOnClickListener {
// val intent = Intent(requireContext(), UserServiceSuggestActivity::class.java)
// startActivity(intent)
// }

// 초기 UI 설정 로직
initAdapter()
Expand Down Expand Up @@ -170,4 +170,5 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
binding.ivDashBackArrow.isEnabled = true
binding.ivDashBackArrow.alpha = 1.0f
}
}
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.ssu.assu.presentation.user.dashboard

import android.R.attr.elevation
import android.app.Activity
import android.content.Context
import android.content.Intent
Expand All @@ -13,35 +12,40 @@ import android.view.View
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.PopupWindow
import android.widget.Toast
import androidx.activity.viewModels
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.ssu.assu.R
import com.ssu.assu.databinding.ActivityUserServiceSuggestBinding
import com.ssu.assu.databinding.FragmentServiceSuggestDropDownBinding
import com.ssu.assu.databinding.FragmentUserServiceSuggestBinding
import com.ssu.assu.domain.model.suggestion.SuggestionTargetModel
import com.ssu.assu.presentation.base.BaseActivity
import com.ssu.assu.presentation.base.BaseFragment
import com.ssu.assu.presentation.common.report.OnServiceSuggestListener
import com.ssu.assu.presentation.user.home.temporary.UserServiceSuggestDialogFragment
import com.ssu.assu.presentation.user.home.temporary.UserTemporaryCompleteFragment
import com.ssu.assu.ui.suggestion.SuggestionViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch

@AndroidEntryPoint
class UserServiceSuggestActivity : BaseActivity<ActivityUserServiceSuggestBinding>(R.layout.activity_user_service_suggest), OnServiceSuggestListener{
class UserServiceSuggestFragment : BaseFragment<FragmentUserServiceSuggestBinding>(R.layout.fragment_user_service_suggest), OnServiceSuggestListener {

private val viewModel: SuggestionViewModel by viewModels()
private val viewModel: SuggestionViewModel by activityViewModels()
private var suggestionTargets: List<SuggestionTargetModel> = emptyList()

private var dropdownWindow: PopupWindow? = null

private val ARG_ENTRY_POINT = "entry_point"
private val ENTRY_QR = "QR_FLOW"

override fun initView() {
// 1. Data Binding 설정
binding.viewModel = viewModel
binding.lifecycleOwner = this
binding.lifecycleOwner = viewLifecycleOwner // Fragment에서는 viewLifecycleOwner 권장

// 2. Window Insets 설정 (Fragment의 root view 사용)
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
val extraPaddingTop = 3
Expand All @@ -53,13 +57,12 @@ class UserServiceSuggestActivity : BaseActivity<ActivityUserServiceSuggestBindin
)
insets
}
// val targetList = resources.getStringArray(R.array.suggest_target).toList()

activateCompleteButton()

binding.spinnerTarget.setOnClickListener {
if (suggestionTargets.isEmpty()) {
Toast.makeText(this, "건의 가능한 대상이 없습니다.", Toast.LENGTH_SHORT).show()
Toast.makeText(requireContext(), "건의 가능한 대상이 없습니다.", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}

Expand All @@ -70,46 +73,29 @@ class UserServiceSuggestActivity : BaseActivity<ActivityUserServiceSuggestBindin
}
}

// 뒤로가기 버튼
// binding.btnSuggestBack.setOnClickListener {
// finish()
// }

// 그냥 애초에 이 액티비티를 닫아서 UserSugesstCompleteActivity의 backStack을 UserMainActivity로 만듦.
binding.btnSuggestComplete.setOnClickListener {
// toCompleteActivity()

// TODO : 1학기 임시 운영버전
temporaryPopUpDialog()
}
}

private fun toCompleteActivity(){
viewModel.writeSuggestion()
val intent = Intent(this, UserSuggestCompleteActivity::class.java)
startActivity(intent)
finish()
}

override fun initObserver() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.getAdminsState.collect { state ->
Log.d("SuggestActivity", "getAdminsState changed: $state")

when (state) {
is SuggestionViewModel.GetAdminsUiState.Success -> {
suggestionTargets = state.data
}
is SuggestionViewModel.GetAdminsUiState.Fail -> {
Toast.makeText(this@UserServiceSuggestActivity, state.message, Toast.LENGTH_SHORT).show()
}
is SuggestionViewModel.GetAdminsUiState.Error -> {
Toast.makeText(this@UserServiceSuggestActivity, "오류가 발생했습니다.", Toast.LENGTH_SHORT).show()
}
else -> {}
// Fragment에서는 viewLifecycleOwner.lifecycleScope를 사용해야 안전합니다.
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.getAdminsState.collect { state ->
Log.d("SuggestFragment", "getAdminsState changed: $state")
when (state) {
is SuggestionViewModel.GetAdminsUiState.Success -> {
suggestionTargets = state.data
}
is SuggestionViewModel.GetAdminsUiState.Fail -> {
Toast.makeText(requireContext(), state.message, Toast.LENGTH_SHORT).show()
}
is SuggestionViewModel.GetAdminsUiState.Error -> {
Toast.makeText(requireContext(), "오류가 발생했습니다.", Toast.LENGTH_SHORT).show()
}
else -> {}
}
}
}
Expand All @@ -123,41 +109,27 @@ class UserServiceSuggestActivity : BaseActivity<ActivityUserServiceSuggestBindin
private fun activateCompleteButton() {
val textWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val input1 = binding.etSuggestMarket.text.toString().trim()
val input2 = binding.etSuggestWantBenefit.text.toString().trim()

val isFilled = input1.isNotEmpty() && input2.isNotEmpty()

binding.btnSuggestComplete.isEnabled = isFilled

if (isFilled) {
binding.btnSuggestComplete.setBackgroundResource(R.drawable.btn_basic_selected)
} else {
binding.btnSuggestComplete.setBackgroundResource(R.drawable.btn_basic_unselected)
}
binding.btnSuggestComplete.setBackgroundResource(
if (isFilled) R.drawable.btn_basic_selected else R.drawable.btn_basic_unselected
)
}

override fun afterTextChanged(s: Editable?) {}
}

binding.etSuggestMarket.addTextChangedListener(textWatcher)
binding.etSuggestWantBenefit.addTextChangedListener(textWatcher)

// 초기 상태
binding.btnSuggestComplete.isEnabled = false
binding.btnSuggestComplete.setBackgroundResource(R.drawable.btn_basic_unselected)
}


private fun showDropdownMenu(anchor : View, targets: List<SuggestionTargetModel>) {

if (targets.isEmpty()) {
Toast.makeText(this, "건의 가능한 대상이 없습니다.", Toast.LENGTH_SHORT).show()
return
}

private fun showDropdownMenu(anchor: View, targets: List<SuggestionTargetModel>) {
val popupBinding = FragmentServiceSuggestDropDownBinding.inflate(layoutInflater)
val popupWindow = PopupWindow(
popupBinding.root,
Expand All @@ -169,9 +141,7 @@ class UserServiceSuggestActivity : BaseActivity<ActivityUserServiceSuggestBindin
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}

popupWindow.setOnDismissListener {
dropdownWindow = null
}
popupWindow.setOnDismissListener { dropdownWindow = null }

val textViews = listOf(
popupBinding.tvSuggestDropTarget1,
Expand All @@ -185,13 +155,13 @@ class UserServiceSuggestActivity : BaseActivity<ActivityUserServiceSuggestBindin

targets.forEachIndexed { index, target ->
if (index < textViews.size) {
val textView = textViews[index]
textView.visibility = View.VISIBLE
textView.text = target.name

textView.setOnClickListener {
viewModel.selectTarget(target)
popupWindow.dismiss()
textViews[index].apply {
visibility = View.VISIBLE
text = target.name
setOnClickListener {
viewModel.selectTarget(target)
popupWindow.dismiss()
}
}
if (index < targets.size - 1 && index < dividers.size) {
dividers[index].visibility = View.VISIBLE
Expand All @@ -200,22 +170,38 @@ class UserServiceSuggestActivity : BaseActivity<ActivityUserServiceSuggestBindin
}

popupWindow.showAsDropDown(anchor, -5, -155)

this.dropdownWindow = popupWindow
}

private fun temporaryPopUpDialog(){
UserServiceSuggestDialogFragment().show(supportFragmentManager, null)

private fun temporaryPopUpDialog() {
// childFragmentManager를 사용하는 것이 Fragment 내의 Dialog 관리에 적합합니다.
UserServiceSuggestDialogFragment().show(childFragmentManager, "SuggestDialog")
}

override fun onServiceSuggest() {
val entryPoint = arguments?.getString(ARG_ENTRY_POINT)
viewModel.writeSuggestion()
viewModel.insertTemporaryQrData("SUGGEST")
val resultIntent = Intent()
setResult(Activity.RESULT_OK, resultIntent)

Log.d("ActivityResult", "RESULT_OK 설정 완료 및 finish 호출")
finish()
// Activity의 setResult 및 finish 호출
if (entryPoint == ENTRY_QR) {
// 1. QR 인증을 통해 들어온 경우: 결과 전달 후 액티비티 종료 (완료 화면으로 이동)
parentFragmentManager.beginTransaction()
.replace(R.id.fragment_container_view, UserTemporaryCompleteFragment())
.commit()
} else {
Toast.makeText(requireContext(), "건의가 완료되었습니다.", Toast.LENGTH_SHORT).show()
resetInputs()
Log.d("SuggestFragment", "일반 진입 플로우 - 화면 유지")
}
}

private fun resetInputs() {
viewModel.clearInputs()
}

override fun onDestroyView() {
super.onDestroyView()
dropdownWindow?.dismiss() // 메모리 누수 방지
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ class MyPartnershipDetailsFragment :

override fun initObserver() {
// 리뷰 목록 관찰 (ServiceRecord)
viewModel.usageList.observe(viewLifecycleOwner) { records ->
serviceRecordAdapter?.setData(records)
}
// viewModel.usageList.observe(viewLifecycleOwner) { records ->
// serviceRecordAdapter?.setData(records)
// }

// 임시 QR 데이터 관찰 (스탬프 적립 내역)
viewModel.qrDataList.observe(viewLifecycleOwner) { qrList ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,41 @@ class TransparentHoleView @JvmOverloads constructor(
setLayerType(LAYER_TYPE_HARDWARE, null)
}

// fun updateHoleRectFromView(targetView: View) {
// val location = IntArray(2)
// targetView.getLocationOnScreen(location)
//
// val x = location[0].toFloat()
// val y = location[1].toFloat()-90
// val width = targetView.width.toFloat()
// val height = targetView.height.toFloat()
//
// holeRect = RectF(x, y, x + width, y + height)
// invalidate()
// }


// 화면 비율 맞추어 홀뷰 조정
fun updateHoleRectFromView(targetView: View) {
val location = IntArray(2)
targetView.getLocationOnScreen(location)
// 1. 타겟 뷰의 화면상 절대 좌표 구하기
val targetLocation = IntArray(2)
targetView.getLocationInWindow(targetLocation)

// 2. 이 오버레이 뷰 자체의 화면상 절대 좌표 구하기
val overlayLocation = IntArray(2)
this.getLocationInWindow(overlayLocation)

// 3. 타겟 좌표에서 오버레이 좌표를 빼서 '상대적'인 위치 계산
// 이렇게 하면 상태바 높이나 툴바 위치를 수동으로 계산할 필요가 없습니다.
val x = (targetLocation[0] - overlayLocation[0]).toFloat()
val y = (targetLocation[1] - overlayLocation[1]).toFloat()

val x = location[0].toFloat()
val y = location[1].toFloat()-90
val width = targetView.width.toFloat()
val height = targetView.height.toFloat()

// 4. 사각형 영역 설정 (여백을 주고 싶다면 여기서 값을 가감하세요)
holeRect = RectF(x, y, x + width, y + height)

invalidate()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package com.ssu.assu.presentation.user.home

import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.activityViewModels
import com.ssu.assu.R
import com.ssu.assu.data.dto.certification.request.PersonalCertificationRequestDto
Expand Down Expand Up @@ -80,6 +84,19 @@ class UserPartnershipSelectFragment :
Log.d("프래그먼트 UI 업데이트", "storeName: $storeName")
}
// ---------------


viewModel.isLoading.observe(viewLifecycleOwner) { isLoading ->
if (isLoading) {
// 로딩 중일 때
binding.loadingOverlay.visibility = View.VISIBLE
binding.clPartnershipSelectFragment.visibility = View.INVISIBLE
} else {
// 로딩 완료 시
binding.loadingOverlay.visibility = View.GONE
binding.clPartnershipSelectFragment.visibility = View.VISIBLE
}
}
}

private fun temporaryNavigateFragment() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class UserQRVerifyActivity :
}


binding.tvUniversity.text = infoManager.getBasicInfoUniversity()
binding.tvUniversity.text = infoManager.getBasicInfoUniversity() +" 학생"
binding.tvDepartment.text = infoManager.getBasicInfoDepartment()
// TODO 나중에 주석해제
cameraExecutor = Executors.newSingleThreadExecutor()
Expand Down
Loading