diff --git a/app/src/main/java/com/toyou/toyouandroid/model/CalendarItem.kt b/app/src/main/java/com/toyou/toyouandroid/model/CalendarItem.kt index 4b324a93..c3f106c3 100644 --- a/app/src/main/java/com/toyou/toyouandroid/model/CalendarItem.kt +++ b/app/src/main/java/com/toyou/toyouandroid/model/CalendarItem.kt @@ -4,3 +4,8 @@ data class CalendarItem( val emotion: Int, val nickname: String ) + +data class DateWithItems( + val date: String, + val items: List +) diff --git a/app/src/main/java/com/toyou/toyouandroid/model/FriendDate.kt b/app/src/main/java/com/toyou/toyouandroid/model/FriendDate.kt new file mode 100644 index 00000000..7ff4032d --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/model/FriendDate.kt @@ -0,0 +1,8 @@ +package com.toyou.toyouandroid.model + +import java.util.Date + +data class FriendDate( + val date: Date, + val people: String +) diff --git a/app/src/main/java/com/toyou/toyouandroid/model/MyDate.kt b/app/src/main/java/com/toyou/toyouandroid/model/MyDate.kt new file mode 100644 index 00000000..4115f3f9 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/model/MyDate.kt @@ -0,0 +1,8 @@ +package com.toyou.toyouandroid.model + +import java.util.Date + +data class MyDate( + val date: Date, + val imageResId: Int? +) diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/base/MainActivity.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/base/MainActivity.kt index 7196e6a9..042b7a53 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/base/MainActivity.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/base/MainActivity.kt @@ -40,8 +40,8 @@ class MainActivity : AppCompatActivity() { navController.navigate(R.id.navigation_social) true } - R.id.navigation_calendar -> { - navController.navigate(R.id.navigation_calendar) + R.id.navigation_record -> { + navController.navigate(R.id.navigation_record) true } R.id.navigation_mypage -> { diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarFragment.kt deleted file mode 100644 index c460abc7..00000000 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarFragment.kt +++ /dev/null @@ -1,79 +0,0 @@ -package com.toyou.toyouandroid.presentation.fragment.calendar - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.navigation.NavController -import androidx.navigation.Navigation -import androidx.recyclerview.widget.GridLayoutManager -import com.toyou.toyouandroid.R -import com.toyou.toyouandroid.databinding.FragmentCalendarBinding -import com.toyou.toyouandroid.model.CalendarItem - -class CalendarFragment : Fragment() { - - lateinit var navController: NavController - private var _binding: FragmentCalendarBinding? = null - private val binding: FragmentCalendarBinding - get() = requireNotNull(_binding){"FragmentCalendarBinding -> null"} - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - - _binding = FragmentCalendarBinding.inflate(inflater, container, false) - - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - navController = Navigation.findNavController(view) - - val items = listOf( - CalendarItem(R.drawable.home_stamp_option_normal, "태연"), - CalendarItem(R.drawable.home_stamp_option_exciting, "승원"), - CalendarItem(R.drawable.home_stamp_option_happy, "현정"), - CalendarItem(R.drawable.home_stamp_option_anxiety, "유은"), - CalendarItem(R.drawable.home_stamp_option_normal, "태연"), - CalendarItem(R.drawable.home_stamp_option_upset, "승원"), - CalendarItem(R.drawable.home_stamp_option_exciting, "현정"), - CalendarItem(R.drawable.home_stamp_option_normal, "유은"), - CalendarItem(R.drawable.home_stamp_option_anxiety, "태연"), - CalendarItem(R.drawable.home_stamp_option_happy, "승원"), - CalendarItem(R.drawable.home_stamp_option_normal, "현정"), - CalendarItem(R.drawable.home_stamp_option_anxiety, "유은"), - CalendarItem(R.drawable.home_stamp_option_exciting, "태연"), - CalendarItem(R.drawable.home_stamp_option_normal, "태연"), - CalendarItem(R.drawable.home_stamp_option_exciting, "승원"), - CalendarItem(R.drawable.home_stamp_option_happy, "현정"), - CalendarItem(R.drawable.home_stamp_option_anxiety, "유은"), - CalendarItem(R.drawable.home_stamp_option_normal, "태연"), - CalendarItem(R.drawable.home_stamp_option_upset, "승원"), - CalendarItem(R.drawable.home_stamp_option_exciting, "현정"), - CalendarItem(R.drawable.home_stamp_option_normal, "유은"), - CalendarItem(R.drawable.home_stamp_option_anxiety, "태연"), - CalendarItem(R.drawable.home_stamp_option_happy, "승원"), - CalendarItem(R.drawable.home_stamp_option_normal, "현정"), - CalendarItem(R.drawable.home_stamp_option_anxiety, "유은"), - CalendarItem(R.drawable.home_stamp_option_exciting, "태연"), - ) - - val adapter = CalendarAdapter(items) - binding.calendarRv.layoutManager = GridLayoutManager(context, 6) - binding.calendarRv.adapter = adapter - - val verticalSpaceHeight = resources.getDimensionPixelSize(R.dimen.recycler_item_spacing) - val horizontalSpaceHeight = verticalSpaceHeight / 2 - binding.calendarRv.addItemDecoration(CalendarItemDecoration(horizontalSpaceHeight, verticalSpaceHeight)) - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarViewModel.kt deleted file mode 100644 index 13076326..00000000 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarViewModel.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.toyou.toyouandroid.presentation.fragment.calendar - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class CalendarViewModel : ViewModel() { - - private val _text = MutableLiveData().apply { - value = "This is calendar Fragment" - } - val text: LiveData = _text -} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionFragment.kt index 4132b0db..22cce94b 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionFragment.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeOptionFragment.kt @@ -53,7 +53,7 @@ class HomeOptionFragment : Fragment() { homeViewModel.updateHomeEmotion( R.drawable.home_emotion_anxiety, getString(R.string.home_emotion_anxiety_title), - R.color.g01, + R.color.g02, R.drawable.background_green) homeViewModel.updateMypageEmotion(R.drawable.home_stamp_option_anxiety) diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeResultFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeResultFragment.kt index 8a13e3b0..519c5e43 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeResultFragment.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/emotionstamp/HomeResultFragment.kt @@ -46,7 +46,7 @@ class HomeResultFragment : Fragment() { binding.homeResultTv.text = text ObjectAnimator.ofFloat(binding.homeResultTv, "alpha", 0f, 1f).apply { - duration = 3000 + duration = 2000 interpolator = DecelerateInterpolator() start() } diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageDialog.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageDialog.kt new file mode 100644 index 00000000..d3e5c9f6 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageDialog.kt @@ -0,0 +1,49 @@ +package com.toyou.toyouandroid.presentation.fragment.mypage + +import android.app.Dialog +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.Window +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import com.toyou.toyouandroid.R +import com.toyou.toyouandroid.databinding.DialogMypageBinding + +class MypageDialog : DialogFragment() { + + private val viewModel: MypageDialogViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val binding: DialogMypageBinding = DataBindingUtil.inflate( + inflater, R.layout.dialog_mypage, container, false + ) + binding.lifecycleOwner = this + binding.viewModel = viewModel + return binding.root + } + + override fun onResume() { + super.onResume() + dialog?.window?.setLayout( + convertDpToPx(280), + convertDpToPx(120) + ) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return Dialog(requireContext(), R.style.MypageDialog).apply { + requestWindowFeature(Window.FEATURE_NO_TITLE) + window?.setBackgroundDrawableResource(android.R.color.transparent) + } + } + + private fun convertDpToPx(dp: Int): Int { + return (dp * resources.displayMetrics.density).toInt() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageDialogViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageDialogViewModel.kt new file mode 100644 index 00000000..e8060e53 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageDialogViewModel.kt @@ -0,0 +1,56 @@ +package com.toyou.toyouandroid.presentation.fragment.mypage + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class MypageDialogViewModel : ViewModel() { + private val _title = MutableLiveData() + val title: LiveData get() = _title + + private val _subTitle = MutableLiveData() + val subTitle: LiveData get() = _subTitle + + private val _leftButtonText = MutableLiveData() + val leftButtonText: LiveData get() = _leftButtonText + + private val _rightButtonText = MutableLiveData() + val rightButtonText: LiveData get() = _rightButtonText + + private val _leftButtonTextColor = MutableLiveData() + val leftButtonTextColor: LiveData get() = _leftButtonTextColor + + private val _rightButtonTextColor = MutableLiveData() + val rightButtonTextColor: LiveData get() = _rightButtonTextColor + + private val _leftButtonClickAction = MutableLiveData<() -> Unit>() + private val _rightButtonClickAction = MutableLiveData<() -> Unit>() + + fun setDialogData( + title: String, + subTitle: String?, + leftButtonText: String, + rightButtonText: String, + leftButtonTextColor: Int, + rightButtonTextColor: Int, + leftButtonClickAction: () -> Unit, + rightButtonClickAction: () -> Unit + ) { + _title.value = title + _subTitle.value = subTitle + _leftButtonText.value = leftButtonText + _rightButtonText.value = rightButtonText + _leftButtonTextColor.value = leftButtonTextColor + _rightButtonTextColor.value = rightButtonTextColor + _leftButtonClickAction.value = leftButtonClickAction + _rightButtonClickAction.value = rightButtonClickAction + } + + fun onLeftButtonClick() { + _leftButtonClickAction.value?.invoke() + } + + fun onRightButtonClick() { + _rightButtonClickAction.value?.invoke() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageFragment.kt index 37e527fa..0a2fbc95 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageFragment.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageFragment.kt @@ -1,6 +1,7 @@ package com.toyou.toyouandroid.presentation.fragment.mypage import android.content.ContentValues.TAG +import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -28,7 +29,9 @@ class MypageFragment : Fragment() { private val nicknameViewModel: SignupNicknameViewModel by activityViewModels() private val homeViewModel: HomeViewModel by activityViewModels() private val viewModel: MypageViewModel by viewModels() + private val mypageDialogViewModel: MypageDialogViewModel by activityViewModels() private lateinit var viewModelManager: ViewModelManager + private var mypageDialog: MypageDialog? = null override fun onCreateView( inflater: LayoutInflater, @@ -37,6 +40,7 @@ class MypageFragment : Fragment() { ): View { _binding = FragmentMypageBinding.inflate(inflater, container, false) + binding.viewModel = viewModel binding.lifecycleOwner = this @@ -68,41 +72,66 @@ class MypageFragment : Fragment() { navController.navigate(R.id.action_navigation_mypage_to_terms_of_use_fragment) } - binding.mypageVersion.setOnClickListener { - navController.navigate(R.id.action_navigation_mypage_to_version_fragment) - } - - binding.mypageLogoutBtn.setOnClickListener { - UserApiClient.instance.logout { error -> - if (error != null) { - Timber.tag(TAG).e(error, "로그아웃 실패. SDK에서 토큰 삭제됨") - } - else { - Timber.tag(TAG).i("로그아웃 성공. SDK에서 토큰 삭제됨") - } - } - viewModelManager.resetAllViewModels() -// resetApp() - navController.navigate(R.id.action_navigation_mypage_to_login_fragment) + // ViewModel에서 닉네임을 가져와서 TextView에 설정 + nicknameViewModel.nickname.observe(viewLifecycleOwner) { nickname -> + binding.profileNickname.text = nickname } binding.mypageSignoutBtn.setOnClickListener { - activity?.finishAffinity() + mypageDialogViewModel.setDialogData( + title = "정말 탈퇴하시겠어요?", + subTitle = "탈퇴 시, 모든 정보가 사라집니다", + leftButtonText = "탈퇴하기", + rightButtonText = "취소", + leftButtonTextColor = Color.RED, + rightButtonTextColor = R.color.black, + leftButtonClickAction = { handleSignout() }, + rightButtonClickAction = { dismissDialog() } + ) + mypageDialog = MypageDialog() + mypageDialog?.show(parentFragmentManager, "CustomDialog") } - // ViewModel에서 닉네임을 가져와서 TextView에 설정 - nicknameViewModel.nickname.observe(viewLifecycleOwner) { nickname -> - binding.profileNickname.text = nickname + binding.mypageLogoutBtn.setOnClickListener { + mypageDialogViewModel.setDialogData( + title = "정말 로그아웃하시겠어요?", + subTitle = "", + leftButtonText = "취소", + rightButtonText = "로그아웃", + leftButtonTextColor = R.color.black, + rightButtonTextColor = Color.RED, + leftButtonClickAction = { dismissDialog() }, + rightButtonClickAction = { handleLogout() } + ) + mypageDialog = MypageDialog() + mypageDialog?.show(parentFragmentManager, "CustomDialog") } + } - homeViewModel.mypageEmotionStamp.observe(viewLifecycleOwner) { emotion -> - binding.mypageEmotionStamp.setImageResource(emotion) + private fun handleSignout() { + Timber.tag("handleSignout").d("handleSignout") + activity?.finishAffinity() + } + + private fun handleLogout() { + Timber.tag("handleLogout").d("handleWithdraw") + + UserApiClient.instance.logout { error -> + if (error != null) { + Timber.tag(TAG).e(error, "로그아웃 실패. SDK에서 토큰 삭제됨") + } + else { + Timber.tag(TAG).i("로그아웃 성공. SDK에서 토큰 삭제됨") + } } + viewModelManager.resetAllViewModels() + navController.navigate(R.id.action_navigation_mypage_to_login_fragment) + mypageDialog?.dismiss() } - private fun resetApp() { - val navGraph = navController.navInflater.inflate(R.navigation.nav_graph) - navController.graph = navGraph + private fun dismissDialog() { + Timber.tag("dismissDialog").d("dismissDialog") + mypageDialog?.dismiss() } override fun onDestroyView() { diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageViewModel.kt index 6afa649d..a9c8a49e 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageViewModel.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/MypageViewModel.kt @@ -1,13 +1,6 @@ package com.toyou.toyouandroid.presentation.fragment.mypage -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class MypageViewModel : ViewModel() { - - private val _text = MutableLiveData().apply { - value = "This is mypage Fragment" - } - val text: LiveData = _text } \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileFragment.kt index 7cae2d25..096830b6 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileFragment.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/ProfileFragment.kt @@ -1,21 +1,34 @@ package com.toyou.toyouandroid.presentation.fragment.mypage +import com.toyou.toyouandroid.presentation.fragment.onboarding.SignupNicknameViewModel import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.navigation.NavController -import androidx.navigation.Navigation +import androidx.navigation.fragment.findNavController +import com.toyou.toyouandroid.R import com.toyou.toyouandroid.databinding.FragmentProfileBinding +import com.toyou.toyouandroid.presentation.base.MainActivity +import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModel +import com.toyou.toyouandroid.presentation.viewmodel.ViewModelManager class ProfileFragment : Fragment() { private lateinit var navController: NavController - private var _binding: FragmentProfileBinding? = null private val binding: FragmentProfileBinding get() = requireNotNull(_binding){"FragmentProfileBinding -> null"} + private val viewModel: SignupNicknameViewModel by activityViewModels() + private val nicknameViewModel: SignupNicknameViewModel by activityViewModels() + private val homeViewModel: HomeViewModel by activityViewModels() + private lateinit var viewModelManager: ViewModelManager override fun onCreateView( inflater: LayoutInflater, @@ -24,13 +37,69 @@ class ProfileFragment : Fragment() { ): View { _binding = FragmentProfileBinding.inflate(inflater, container, false) + binding.viewModel = viewModel + binding.lifecycleOwner = this + + binding.signupNicknameInput.setText("") + viewModel.resetNicknameEditState() return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - navController = Navigation.findNavController(view) + viewModelManager = ViewModelManager(nicknameViewModel, homeViewModel) + + (requireActivity() as MainActivity).hideBottomNavigation(true) + + // navController 초기화 + navController = findNavController() + + binding.signupNicknameBackBtn.setOnClickListener { + navController.navigate(R.id.action_navigation_profile_to_mypage_fragment) + } + + binding.signupNicknameInput.addTextChangedListener(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 length = s?.length ?: 0 + viewModel.updateTextCount(length) + viewModel.duplicateBtnActivate() + viewModel.updateLength15(length) + } + + override fun afterTextChanged(s: Editable?) { + val nickname = s?.toString() ?: "" + viewModel.setNickname(nickname) + } + }) + + binding.signupNicknameBtn.setOnClickListener{ + navController.navigate(R.id.action_navigation_profile_to_mypage_fragment) + } + + binding.signupAgreeNicknameDoublecheckBtn.setOnClickListener { + viewModel.checkDuplicate() + hideKeyboard() + } + + binding.root.setOnTouchListener { v, event -> + if (event.action == MotionEvent.ACTION_DOWN) { + hideKeyboard() + v.performClick() + } + false + } + + binding.root.setOnClickListener { + hideKeyboard() + } + } + + private fun hideKeyboard() { + val imm = requireActivity().getSystemService(InputMethodManager::class.java) + imm.hideSoftInputFromWindow(view?.windowToken, 0) } override fun onDestroyView() { diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/VersionFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/VersionFragment.kt deleted file mode 100644 index c0445381..00000000 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/mypage/VersionFragment.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.toyou.toyouandroid.presentation.fragment.mypage - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.navigation.NavController -import androidx.navigation.Navigation -import com.toyou.toyouandroid.databinding.FragmentVersionBinding - -class VersionFragment : Fragment() { - - private lateinit var navController: NavController - - private var _binding: FragmentVersionBinding? = null - private val binding: FragmentVersionBinding - get() = requireNotNull(_binding){"FragmentVersionBinding -> null"} - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - - _binding = FragmentVersionBinding.inflate(inflater, container, false) - - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - navController = Navigation.findNavController(view) - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeAdapter.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeAdapter.kt index b9af861e..1926ba40 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeAdapter.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeAdapter.kt @@ -69,23 +69,37 @@ class NoticeAdapter(private val items: MutableList) : override fun getItemCount(): Int = items.size - class FriendRequestViewHolder(private val binding: ItemNoticeFriendRequestBinding) : RecyclerView.ViewHolder(binding.root) { + inner class FriendRequestViewHolder(private val binding: ItemNoticeFriendRequestBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(item: NoticeItem.NoticeFriendRequestItem) { binding.itemFriendRequest = item + binding.noticeCardCheckDelete.setOnClickListener { + removeItem(this.layoutPosition) + } binding.executePendingBindings() } } - class FriendRequestAcceptedViewHolder(private val binding: ItemNoticeFriendRequestAcceptedBinding) : RecyclerView.ViewHolder(binding.root) { + inner class FriendRequestAcceptedViewHolder(private val binding: ItemNoticeFriendRequestAcceptedBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(item: NoticeItem.NoticeFriendRequestAcceptedItem) { binding.itemFriendRequestAccepted = item + binding.noticeCardCheckDelete.setOnClickListener { + removeItem(this.layoutPosition) + } + + val layoutParams = binding.root.layoutParams + layoutParams.width = (binding.root.context.resources.displayMetrics.widthPixels * 5 / 6) + binding.root.layoutParams = layoutParams + binding.executePendingBindings() } } - class CardCheckViewHolder(private val binding: ItemNoticeCardCheckBinding) : RecyclerView.ViewHolder(binding.root) { + inner class CardCheckViewHolder(private val binding: ItemNoticeCardCheckBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(item: NoticeItem.NoticeCardCheckItem) { binding.itemCardCheck = item + binding.noticeCardCheckDelete.setOnClickListener { + removeItem(this.layoutPosition) + } binding.executePendingBindings() } } @@ -94,6 +108,7 @@ class NoticeAdapter(private val items: MutableList) : if (position >= 0 && position < items.size) { items.removeAt(position) notifyItemRemoved(position) + notifyItemRangeChanged(position, items.size) // 아이템을 제거한 이후의 아이템들에 대해 포지션 업데이트 } } } diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeFragment.kt index c89e906f..8609fc66 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeFragment.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/notice/NoticeFragment.kt @@ -51,29 +51,32 @@ class NoticeFragment : Fragment() { NoticeItem.NoticeFriendRequestItem("테디"), NoticeItem.NoticeCardCheckItem("현정"), NoticeItem.NoticeFriendRequestItem("테디"), - NoticeItem.NoticeCardCheckItem("승원"), - NoticeItem.NoticeFriendRequestAcceptedItem("테디"), - NoticeItem.NoticeCardCheckItem("유은"), - NoticeItem.NoticeFriendRequestItem("테디"), - NoticeItem.NoticeCardCheckItem("현정"), - NoticeItem.NoticeFriendRequestItem("테디"), - NoticeItem.NoticeCardCheckItem("승원"), - NoticeItem.NoticeFriendRequestAcceptedItem("테디"), - NoticeItem.NoticeCardCheckItem("유은"), - NoticeItem.NoticeFriendRequestItem("테디"), - NoticeItem.NoticeFriendRequestAcceptedItem("현정") + NoticeItem.NoticeCardCheckItem("승원") ) val adapter = NoticeAdapter(items) binding.noticeRv.layoutManager = GridLayoutManager(context, 1) binding.noticeRv.adapter = adapter - val itemTouchHelper = ItemTouchHelper(SwipeToDeleteNotice(adapter)) - itemTouchHelper.attachToRecyclerView(binding.noticeRv) - val verticalSpaceHeight = resources.getDimensionPixelSize(R.dimen.recycler_item_spacing) binding.noticeRv.addItemDecoration(NoticeItemDecoration(verticalSpaceHeight)) + val swipeToDeleteNotice = SwipeToDeleteNotice().apply { + setClamp(resources.displayMetrics.widthPixels.toFloat() / 5) + } + ItemTouchHelper(swipeToDeleteNotice).attachToRecyclerView(binding.noticeRv) + + binding.noticeRv.apply { + setOnTouchListener { v, _ -> + swipeToDeleteNotice.removePreviousClamp(this) + v.performClick() + false + } + + setOnClickListener { + } + } + binding.noticeBackBtn.setOnClickListener { navController.navigate(R.id.action_navigation_notice_to_home_fragment) } diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameFragment.kt index ef14e175..0bd694a1 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameFragment.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameFragment.kt @@ -15,6 +15,8 @@ import androidx.navigation.fragment.findNavController import com.toyou.toyouandroid.R import com.toyou.toyouandroid.databinding.FragmentSignupnicknameBinding import com.toyou.toyouandroid.presentation.base.MainActivity +import com.toyou.toyouandroid.presentation.viewmodel.HomeViewModel +import com.toyou.toyouandroid.presentation.viewmodel.ViewModelManager class SignupNicknameFragment : Fragment() { @@ -23,6 +25,9 @@ class SignupNicknameFragment : Fragment() { private val binding: FragmentSignupnicknameBinding get() = requireNotNull(_binding){"FragmentSignupnicknameBinding -> null"} private val viewModel: SignupNicknameViewModel by activityViewModels() + private val nicknameViewModel: SignupNicknameViewModel by activityViewModels() + private val homeViewModel: HomeViewModel by activityViewModels() + private lateinit var viewModelManager: ViewModelManager override fun onCreateView( inflater: LayoutInflater, @@ -39,6 +44,7 @@ class SignupNicknameFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewModelManager = ViewModelManager(nicknameViewModel, homeViewModel) (requireActivity() as MainActivity).hideBottomNavigation(true) diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameViewModel.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameViewModel.kt index 7adfb7f4..af120c46 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameViewModel.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/onboarding/SignupNicknameViewModel.kt @@ -7,6 +7,12 @@ import com.toyou.toyouandroid.R class SignupNicknameViewModel : ViewModel() { + private val _title = MutableLiveData() + val title: LiveData get() = _title + + private val _backButtonAction = MutableLiveData<() -> Unit>() + val backButtonAction: LiveData<() -> Unit> get() = _backButtonAction + private val _textCount = MutableLiveData("0/15") val textCount: LiveData get() = _textCount @@ -53,10 +59,15 @@ class SignupNicknameViewModel : ViewModel() { } val nextButtonBackground: LiveData = _nextButtonBackground + private val _nickname = MutableLiveData() + val nickname: LiveData get() = _nickname + init { inputText.observeForever { text -> _isDuplicateCheckEnabled.value = !text.isNullOrEmpty() } + _title.value = "회원가입" +// _backButtonAction.value = { /* 회원가입 화면에서의 back 버튼 로직 */ } } fun checkDuplicate() { @@ -83,13 +94,19 @@ class SignupNicknameViewModel : ViewModel() { } } - private val _nickname = MutableLiveData() - val nickname: LiveData get() = _nickname - fun setNickname(newNickname: String) { _nickname.value = newNickname } + fun setForEditNickname() { + _title.value = "프로필 수정" + _backButtonAction.value = { /* 닉네임 수정 화면에서의 back 버튼 로직 */ } + } + + fun onBackButtonClicked() { + _backButtonAction.value?.invoke() + } + fun resetState() { _duplicateCheckMessage.value = "중복된 닉네임인지 확인해주세요" _duplicateCheckMessageColor.value = 0xFF000000.toInt() @@ -100,4 +117,14 @@ class SignupNicknameViewModel : ViewModel() { _duplicateCheckButtonTextColor.value = 0xFFA6A6A6.toInt() _duplicateCheckButtonBackground.value = R.drawable.next_button } + + fun resetNicknameEditState() { + _duplicateCheckMessage.value = "중복된 닉네임인지 확인해주세요" + _duplicateCheckMessageColor.value = 0xFF000000.toInt() + _isNextButtonEnabled.value = false + _nextButtonTextColor.value = 0xFFA6A6A6.toInt() + _nextButtonBackground.value = R.drawable.next_button + _duplicateCheckButtonTextColor.value = 0xFFA6A6A6.toInt() + _duplicateCheckButtonBackground.value = R.drawable.next_button + } } \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarAdapter.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/CalendarAdapter.kt similarity index 81% rename from app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarAdapter.kt rename to app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/CalendarAdapter.kt index 7b82d997..95c55c89 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarAdapter.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/CalendarAdapter.kt @@ -1,4 +1,4 @@ -package com.toyou.toyouandroid.presentation.fragment.calendar +package com.toyou.toyouandroid.presentation.fragment.record import android.view.LayoutInflater import android.view.ViewGroup @@ -6,7 +6,7 @@ import androidx.recyclerview.widget.RecyclerView import com.toyou.toyouandroid.databinding.ItemCalendarFriendStampBinding import com.toyou.toyouandroid.model.CalendarItem -class CalendarAdapter(private val items: List) : RecyclerView.Adapter() { +class CalendarAdapter(private var items: List) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val inflater = LayoutInflater.from(parent.context) @@ -23,6 +23,11 @@ class CalendarAdapter(private val items: List) : RecyclerView.Adap return items.size } + fun updateData(newItems: List) { + items = newItems + notifyDataSetChanged() + } + inner class ViewHolder(private val binding: ItemCalendarFriendStampBinding) : RecyclerView.ViewHolder(binding.root) { fun bind(item: CalendarItem) { diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarItemDecoration.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/CalendarItemDecoration.kt similarity index 88% rename from app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarItemDecoration.kt rename to app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/CalendarItemDecoration.kt index a27b6b49..63e64b2b 100644 --- a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/calendar/CalendarItemDecoration.kt +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/CalendarItemDecoration.kt @@ -1,4 +1,4 @@ -package com.toyou.toyouandroid.presentation.fragment.calendar +package com.toyou.toyouandroid.presentation.fragment.record import android.graphics.Rect import android.view.View diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/DayOfTheWeekAdapter.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/DayOfTheWeekAdapter.kt new file mode 100644 index 00000000..4e090a55 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/DayOfTheWeekAdapter.kt @@ -0,0 +1,27 @@ +package com.toyou.toyouandroid.presentation.fragment.record + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.toyou.toyouandroid.databinding.ItemDayoftheweekBinding + +class DayOfTheWeekAdapter(private val days: List) : RecyclerView.Adapter() { + + class DayViewHolder(private val binding: ItemDayoftheweekBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(day: String) { + binding.dayTextOfWeek.text = day + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DayViewHolder { + val binding = ItemDayoftheweekBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return DayViewHolder(binding) + } + + override fun onBindViewHolder(holder: DayViewHolder, position: Int) { + holder.bind(days[position]) + } + + override fun getItemCount(): Int = days.size + +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/RecordFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/RecordFragment.kt new file mode 100644 index 00000000..60f17a12 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/RecordFragment.kt @@ -0,0 +1,72 @@ +package com.toyou.toyouandroid.presentation.fragment.record + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.commit +import androidx.navigation.NavController +import androidx.navigation.Navigation +import com.google.android.material.tabs.TabLayout +import com.toyou.toyouandroid.R +import com.toyou.toyouandroid.databinding.FragmentRecordBinding +import com.toyou.toyouandroid.presentation.fragment.record.friend.CalendarFriendRecordFragment +import com.toyou.toyouandroid.presentation.fragment.record.my.CalendarMyRecordFragment + +class RecordFragment : Fragment() { + + lateinit var navController: NavController + private var _binding: FragmentRecordBinding? = null + private val binding: FragmentRecordBinding + get() = requireNotNull(_binding){"FragmentRecordBinding -> null"} + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + + _binding = FragmentRecordBinding.inflate(inflater, container, false) + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + navController = Navigation.findNavController(view) + + val tabLayout: TabLayout = binding.tabLayout + + tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabSelected(tab: TabLayout.Tab) { + when (tab.position) { + 0 -> replaceFragment(CalendarMyRecordFragment()) + 1 -> replaceFragment(CalendarFriendRecordFragment()) + } + } + + override fun onTabUnselected(tab: TabLayout.Tab) {} + + override fun onTabReselected(tab: TabLayout.Tab) {} + }) + + // 초기 화면 설정 + if (savedInstanceState == null) { + tabLayout.getTabAt(0)?.select() + replaceFragment(CalendarMyRecordFragment()) + } + } + + private fun replaceFragment(fragment: Fragment) { + childFragmentManager.commit { + replace(R.id.record_fragment_Container, fragment) + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/CalendarFriendRecordFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/CalendarFriendRecordFragment.kt new file mode 100644 index 00000000..47e8f645 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/CalendarFriendRecordFragment.kt @@ -0,0 +1,145 @@ +package com.toyou.toyouandroid.presentation.fragment.record.friend + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.navigation.NavController +import androidx.navigation.Navigation +import androidx.recyclerview.widget.GridLayoutManager +import androidx.viewpager2.widget.ViewPager2 +import com.toyou.toyouandroid.R +import com.toyou.toyouandroid.databinding.FragmentCalendarFriendrecordBinding +import com.toyou.toyouandroid.model.FriendDate +import com.toyou.toyouandroid.presentation.fragment.record.CalendarAdapter +import com.toyou.toyouandroid.presentation.fragment.record.CalendarItemDecoration +import com.toyou.toyouandroid.utils.FriendDates +import com.toyou.toyouandroid.utils.FriendDates.generateFriendDatesForMonths +import com.toyou.toyouandroid.utils.FriendRecordData +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +class CalendarFriendRecordFragment : Fragment(), FriendCalendarRVAdapter.OnDateClickListener { + + lateinit var navController: NavController + private var _binding: FragmentCalendarFriendrecordBinding? = null + private val binding: FragmentCalendarFriendrecordBinding + get() = requireNotNull(_binding){"FragmentCalendarFriendrecordBinding -> null"} + + private var calendar = Calendar.getInstance() + private val startCalendar: Calendar = Calendar.getInstance().apply { + time = Date() + } + private var monthDates = generateFriendDatesForMonths(calendar, 12, 12) + + private lateinit var calendarAdapter: CalendarAdapter + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + + _binding = FragmentCalendarFriendrecordBinding.inflate(inflater, container, false) + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + navController = Navigation.findNavController(view) + + startCalendar.time = calendar.time + + val today = Calendar.getInstance().time + val formattedToday = SimpleDateFormat("yyyyMMdd 나의 기록", Locale.getDefault()).format(today) + binding.recordTitle.text = formattedToday + + // 월 달력 + binding.calendarViewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL + binding.calendarViewPager.registerOnPageChangeCallback(object : + ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 12 + position) + updateCalendar() + } + }) + + // 오늘로 돌아가기 + binding.btnTodayDate.setOnClickListener { + calendar = Calendar.getInstance() + startCalendar.time = calendar.time + monthDates = generateFriendDatesForMonths(calendar, 12, 12) // 이전 달과 다음 달을 포함 + updateCalendar() + onDateClick(today) + } + + updateCalendar() // 초기 달력 업데이트 + dayTextView() + + // 오늘 날짜에 해당하는 아이템 가져오기 + val items = FriendRecordData.getItemsForDate(SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(today)) + + calendarAdapter = CalendarAdapter(items) + binding.calendarRv.layoutManager = GridLayoutManager(context, 5) + binding.calendarRv.adapter = calendarAdapter + + val verticalSpaceHeight = resources.getDimensionPixelSize(R.dimen.recycler_item_spacing) + val horizontalSpaceHeight = resources.getDimensionPixelSize(R.dimen.recycler_item_spacing_side) + binding.calendarRv.addItemDecoration(CalendarItemDecoration(horizontalSpaceHeight, verticalSpaceHeight)) + } + + private fun dayTextView() { + + val startCalendarClone = startCalendar.clone() as Calendar // 복제된 객체 생성 + val endCalendar = startCalendarClone.clone() as Calendar + endCalendar.add(Calendar.DATE, 6) + + // 일요일까지의 날짜 차이를 계산 + val differenceToSunday = + (Calendar.SUNDAY + 7) - startCalendarClone.get(Calendar.DAY_OF_WEEK) + val endSunDayCalendar = startCalendarClone.clone() as Calendar + endSunDayCalendar.add(Calendar.DATE, differenceToSunday) + } + + + private fun updateCalendar() { + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + binding.yearMonthTextView.text = "${year}년 ${month + 1}월" + + val months = generateMonths(calendar) + val pagerAdapter = FriendCalendarPagerAdapter(months, month, this) + binding.calendarViewPager.adapter = pagerAdapter + binding.calendarViewPager.setCurrentItem(months.size / 2, false) + } + + private fun generateMonths(calendar: Calendar): List> { + + val months = mutableListOf>() + + for (i in -12..12) { + val cal = calendar.clone() as Calendar + cal.add(Calendar.MONTH, i) + months.add(FriendDates.generateFriendDates(cal)) + } + + return months + } + + override fun onDateClick(date: Date) { + // 여기서 record_title의 텍스트를 클릭한 날짜로 설정할 수 있습니다. + val formattedDate = SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(date) + val items = FriendRecordData.getItemsForDate(formattedDate) + calendarAdapter.updateData(items) + binding.recordTitle.text = SimpleDateFormat("yyyyMMdd 친구 기록", Locale.getDefault()).format(date) + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCalendarPagerAdapter.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCalendarPagerAdapter.kt new file mode 100644 index 00000000..3138d17e --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCalendarPagerAdapter.kt @@ -0,0 +1,46 @@ +package com.toyou.toyouandroid.presentation.fragment.record.friend + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.toyou.toyouandroid.databinding.CalendarPageBinding +import com.toyou.toyouandroid.model.FriendDate +import com.toyou.toyouandroid.presentation.fragment.record.DayOfTheWeekAdapter + +class FriendCalendarPagerAdapter( + private val datesList: List>, + private val currentMonth: Int, + private val onDateClickListener: FriendCalendarRVAdapter.OnDateClickListener +) : RecyclerView.Adapter() { + + inner class ViewHolder(val binding: CalendarPageBinding) : RecyclerView.ViewHolder(binding.root) { + val calendarRecyclerView: RecyclerView = binding.calendarViewPager + val dayOfTheWeekRecyclerView: RecyclerView = binding.dayOfTheWeekRecyclerView + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = CalendarPageBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) + } + + // 각 페이지의 RecyclerView에 CalendarAdapter를 설정하고, 해당 월의 날짜 데이터를 연결 + // GridLayoutManager를 사용하여 달력을 그리드 형식으로 표시 + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + + val dates = datesList[position] + val adapter = FriendCalendarRVAdapter(dates, currentMonth, onDateClickListener) + + holder.calendarRecyclerView.adapter = adapter + holder.calendarRecyclerView.layoutManager = GridLayoutManager(holder.itemView.context, 7) + + val daysOfWeek = listOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun") + val dayOfWeekAdapter = DayOfTheWeekAdapter(daysOfWeek) + holder.dayOfTheWeekRecyclerView.adapter = dayOfWeekAdapter + holder.dayOfTheWeekRecyclerView.layoutManager = GridLayoutManager(holder.itemView.context, 7) + } + + override fun getItemCount(): Int { + return datesList.size + } +} diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCalendarRVAdapter.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCalendarRVAdapter.kt new file mode 100644 index 00000000..f85fdaf6 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/friend/FriendCalendarRVAdapter.kt @@ -0,0 +1,88 @@ +package com.toyou.toyouandroid.presentation.fragment.record.friend + +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.toyou.toyouandroid.databinding.CalendarFriendrecordItemBinding +import com.toyou.toyouandroid.model.FriendDate +import timber.log.Timber +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +class FriendCalendarRVAdapter( + private val dates: List, + currentMonth: Int, + private val onDateClickListener: OnDateClickListener +) : RecyclerView.Adapter() { + + private val thisMonth = currentMonth + + inner class ViewHolder(private val binding: CalendarFriendrecordItemBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(friendDate: FriendDate) { + val date = friendDate.date + val people = friendDate.people + val calendar = Calendar.getInstance() + calendar.time = date + val month = calendar.get(Calendar.MONTH) + val dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) + + if (month != thisMonth) { + binding.dayText.setTextColor(Color.LTGRAY) + } else { + when (dayOfWeek) { + Calendar.SATURDAY -> { + binding.dayText.setTextColor(Color.BLUE) + } + Calendar.SUNDAY -> { + binding.dayText.setTextColor(Color.RED) + } + else -> { + binding.dayText.setTextColor(Color.BLACK) + } + } + } + + // 이미지 설정 + if (people == "0") { + binding.friendrecordImageView.visibility = View.GONE + binding.friendrecordPeople.visibility = View.GONE + } else { + binding.friendrecordPeople.text = people + binding.friendrecordImageView.visibility = View.VISIBLE + binding.friendrecordPeople.visibility = View.VISIBLE + } + + binding.dayText.text = SimpleDateFormat("d", Locale.getDefault()).format(date) + binding.root.setOnClickListener { + Timber.tag("CalendarRVAdapter").d("Date clicked: $date") + + // 날짜 클릭했을 때 기록탭 날짜 변경로직 + onDateClickListener.onDateClick(date) + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = CalendarFriendrecordItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(dates[position]) + } + + override fun getItemCount(): Int { + return dates.size + } + + interface OnDateClickListener { + fun onDateClick(date: Date) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/CalendarMyRecordFragment.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/CalendarMyRecordFragment.kt new file mode 100644 index 00000000..2fde98c0 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/CalendarMyRecordFragment.kt @@ -0,0 +1,113 @@ +package com.toyou.toyouandroid.presentation.fragment.record.my + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.navigation.NavController +import androidx.navigation.Navigation +import androidx.viewpager2.widget.ViewPager2 +import com.toyou.toyouandroid.databinding.FragmentCalendarMyrecordBinding +import com.toyou.toyouandroid.model.MyDate +import com.toyou.toyouandroid.utils.MyDates.generateDatesForMonths +import com.toyou.toyouandroid.utils.MyDates +import java.util.Calendar +import java.util.Date + +class CalendarMyRecordFragment : Fragment(), MyRecordCalendarRVAdapter.OnDateClickListener { + + lateinit var navController: NavController + private var _binding: FragmentCalendarMyrecordBinding? = null + private val binding: FragmentCalendarMyrecordBinding + get() = requireNotNull(_binding){"FragmentCalendarMyrecordBinding -> null"} + + private var calendar = Calendar.getInstance() + private val startCalendar: Calendar = Calendar.getInstance().apply { + time = Date() + } + private var monthDates = generateDatesForMonths(calendar, 12, 12) + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + + _binding = FragmentCalendarMyrecordBinding.inflate(inflater, container, false) + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + navController = Navigation.findNavController(view) + + startCalendar.time = calendar.time + + // 월 달력 + binding.calendarViewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL + binding.calendarViewPager.registerOnPageChangeCallback(object : + ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 12 + position) + updateCalendar() + } + }) + + // 오늘로 돌아가기 + binding.btnTodayDate.setOnClickListener { + calendar = Calendar.getInstance() + startCalendar.time = calendar.time + monthDates = generateDatesForMonths(calendar, 12, 12) // 이전 달과 다음 달을 포함 + updateCalendar() + } + + updateCalendar() // 초기 달력 업데이트 + dayTextView() + } + + private fun dayTextView() { + + val startCalendarClone = startCalendar.clone() as Calendar // 복제된 객체 생성 + val endCalendar = startCalendarClone.clone() as Calendar + endCalendar.add(Calendar.DATE, 6) + + // 일요일까지의 날짜 차이를 계산 + val differenceToSunday = + (Calendar.SUNDAY + 7) - startCalendarClone.get(Calendar.DAY_OF_WEEK) + val endSunDayCalendar = startCalendarClone.clone() as Calendar + endSunDayCalendar.add(Calendar.DATE, differenceToSunday) + } + + private fun updateCalendar() { + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + binding.yearMonthTextView.text = "${year}년 ${month + 1}월" + + val months = generateMonths(calendar) + val pagerAdapter = MyrecordCalendarPagerAdapter(months, month, this) + binding.calendarViewPager.adapter = pagerAdapter + binding.calendarViewPager.setCurrentItem(months.size / 2, false) + } + + private fun generateMonths(calendar: Calendar): List> { + + val months = mutableListOf>() + + for (i in -12..12) { + val cal = calendar.clone() as Calendar + cal.add(Calendar.MONTH, i) + months.add(MyDates.generateDates(cal)) + } + + return months + } + + override fun onDateClick(date: Date) {} + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyRecordCalendarRVAdapter.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyRecordCalendarRVAdapter.kt new file mode 100644 index 00000000..e3aef243 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyRecordCalendarRVAdapter.kt @@ -0,0 +1,86 @@ +package com.toyou.toyouandroid.presentation.fragment.record.my + +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.toyou.toyouandroid.databinding.CalendarMyrecordItemBinding +import com.toyou.toyouandroid.model.MyDate +import timber.log.Timber +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +class MyRecordCalendarRVAdapter( + private val dates: List, + currentMonth: Int, + private val onDateClickListener: OnDateClickListener +) : RecyclerView.Adapter() { + + private val thisMonth = currentMonth + + inner class ViewHolder(private val binding: CalendarMyrecordItemBinding) : + RecyclerView.ViewHolder(binding.root) { + + fun bind(myDate: MyDate) { + val date = myDate.date + val imageResId = myDate.imageResId + val calendar = Calendar.getInstance() + calendar.time = date + val month = calendar.get(Calendar.MONTH) + val dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) + + if (month != thisMonth) { + binding.dayText.setTextColor(Color.LTGRAY) + } else { + when (dayOfWeek) { + Calendar.SATURDAY -> { + binding.dayText.setTextColor(Color.BLUE) + } + Calendar.SUNDAY -> { + binding.dayText.setTextColor(Color.RED) + } + else -> { + binding.dayText.setTextColor(Color.BLACK) + } + } + } + + // 이미지 설정 + if (imageResId != null) { + binding.myrecordImageView.setImageResource(imageResId) + binding.myrecordImageView.visibility = View.VISIBLE + } else { + binding.myrecordImageView.visibility = View.GONE + } + + binding.dayText.text = SimpleDateFormat("d", Locale.getDefault()).format(date) + binding.root.setOnClickListener { + Timber.tag("CalendarRVAdapter").d("Date clicked: $date") + + // 날짜 클릭했을 때 기록탭 날짜 변경로직 + onDateClickListener.onDateClick(date) + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = CalendarMyrecordItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(dates[position]) + } + + override fun getItemCount(): Int { + return dates.size + } + + interface OnDateClickListener { + fun onDateClick(date: Date) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyrecordCalendarPagerAdapter.kt b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyrecordCalendarPagerAdapter.kt new file mode 100644 index 00000000..aa9b46e5 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/presentation/fragment/record/my/MyrecordCalendarPagerAdapter.kt @@ -0,0 +1,46 @@ +package com.toyou.toyouandroid.presentation.fragment.record.my + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.toyou.toyouandroid.databinding.CalendarPageBinding +import com.toyou.toyouandroid.model.MyDate +import com.toyou.toyouandroid.presentation.fragment.record.DayOfTheWeekAdapter + +class MyrecordCalendarPagerAdapter( + private val datesList: List>, + private val currentMonth: Int, + private val onDateClickListener: MyRecordCalendarRVAdapter.OnDateClickListener +) : RecyclerView.Adapter() { + + inner class ViewHolder(val binding: CalendarPageBinding) : RecyclerView.ViewHolder(binding.root) { + val calendarRecyclerView: RecyclerView = binding.calendarViewPager + val dayOfTheWeekRecyclerView: RecyclerView = binding.dayOfTheWeekRecyclerView + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = CalendarPageBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) + } + + // 각 페이지의 RecyclerView에 CalendarAdapter를 설정하고, 해당 월의 날짜 데이터를 연결 + // GridLayoutManager를 사용하여 달력을 그리드 형식으로 표시 + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + + val dates = datesList[position] + val adapter = MyRecordCalendarRVAdapter(dates, currentMonth, onDateClickListener) + + holder.calendarRecyclerView.adapter = adapter + holder.calendarRecyclerView.layoutManager = GridLayoutManager(holder.itemView.context, 7) + + val daysOfWeek = listOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun") + val dayOfWeekAdapter = DayOfTheWeekAdapter(daysOfWeek) + holder.dayOfTheWeekRecyclerView.adapter = dayOfWeekAdapter + holder.dayOfTheWeekRecyclerView.layoutManager = GridLayoutManager(holder.itemView.context, 7) + } + + override fun getItemCount(): Int { + return datesList.size + } +} diff --git a/app/src/main/java/com/toyou/toyouandroid/utils/BindingAdapters.kt b/app/src/main/java/com/toyou/toyouandroid/utils/BindingAdapters.kt index 8a3bb97a..46f705ae 100644 --- a/app/src/main/java/com/toyou/toyouandroid/utils/BindingAdapters.kt +++ b/app/src/main/java/com/toyou/toyouandroid/utils/BindingAdapters.kt @@ -3,6 +3,7 @@ package com.toyou.toyouandroid.utils import android.graphics.BitmapFactory import android.widget.Button import android.widget.ImageView +import android.widget.TextView import androidx.appcompat.widget.AppCompatButton import androidx.databinding.BindingAdapter import androidx.lifecycle.LiveData @@ -27,4 +28,11 @@ fun loadImage(view: ImageView, imagePath: String) { @BindingAdapter("android:setBackground") fun setBackground(button: AppCompatButton, resource: Int?) { resource?.let { button.setBackgroundResource(it) } +} + +@BindingAdapter("formattedNickname") +fun setFormattedNickname(textView: TextView, nickname: String?) { + nickname?.let { + textView.text = if (it.length > 3) "${it.substring(0, 3)}..." else it + } } \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/utils/FriendDates.kt b/app/src/main/java/com/toyou/toyouandroid/utils/FriendDates.kt new file mode 100644 index 00000000..eabdc66e --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/utils/FriendDates.kt @@ -0,0 +1,63 @@ +package com.toyou.toyouandroid.utils + +import com.toyou.toyouandroid.model.FriendDate +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale + +object FriendDates { + + fun generateFriendDates(calendar: Calendar): List { + val dates = mutableListOf() + val cal = calendar.clone() as Calendar + cal.set(Calendar.DAY_OF_MONTH, 1) + + val dateFormat = SimpleDateFormat("yyyyMMdd", Locale.getDefault()) + + // 달의 첫 번째 날의 요일 계산 (월요일이 시작일인 경우) + val firstDayOfWeek = (cal.get(Calendar.DAY_OF_WEEK) + 5) % 7 + + // 전월의 마지막 일로 채우기 + cal.add(Calendar.DAY_OF_MONTH, -firstDayOfWeek) + for (i in 0 until firstDayOfWeek) { + dates.add(FriendDate(cal.time, "0")) + cal.add(Calendar.DAY_OF_MONTH, 1) + } + + // 현재 달의 일자 추가 + val daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH) + for (i in 0 until daysInMonth) { + + val dateString = dateFormat.format(cal.time) + val items = FriendRecordData.getItemsForDate(dateString) + val peopleCount = items.size + + dates.add(FriendDate(cal.time, peopleCount.toString())) + cal.add(Calendar.DAY_OF_MONTH, 1) + } + + // 다음 달의 처음 일로 채우기 + val lastDayOfWeek = (cal.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY + 6) % 7 + val remainingDays = 6 - lastDayOfWeek + + // 마지막 날이 일요일이 아니거나, 마지막 날이 일요일이지만 다음 달 1일이 월요일이 아닌 경우에만 채우기 + if (lastDayOfWeek != 6 || (remainingDays == 0 && cal.get(Calendar.DAY_OF_MONTH) != 1)) { + for (i in 0 until remainingDays) { + dates.add(FriendDate(cal.time, "0")) + cal.add(Calendar.DAY_OF_MONTH, 1) + } + } + + return dates + } + + fun generateFriendDatesForMonths(calendar: Calendar, monthsBefore: Int, monthsAfter: Int): List { + val dates = mutableListOf() + for (i in -monthsBefore..monthsAfter) { + val cal = calendar.clone() as Calendar + cal.add(Calendar.MONTH, i) + dates.addAll(generateFriendDates(cal)) + } + return dates + } +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/utils/FriendRecordData.kt b/app/src/main/java/com/toyou/toyouandroid/utils/FriendRecordData.kt new file mode 100644 index 00000000..4a00c234 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/utils/FriendRecordData.kt @@ -0,0 +1,46 @@ +package com.toyou.toyouandroid.utils + +import com.toyou.toyouandroid.R +import com.toyou.toyouandroid.model.CalendarItem +import com.toyou.toyouandroid.model.DateWithItems + +object FriendRecordData { + + val data: List = listOf( + DateWithItems( + date = "20240801", + items = listOf( + CalendarItem(R.drawable.home_stamp_option_normal, "태연"), + CalendarItem(R.drawable.home_stamp_option_exciting, "승원"), + CalendarItem(R.drawable.home_stamp_option_happy, "현정"), + CalendarItem(R.drawable.home_stamp_option_anxiety, "유은"), + CalendarItem(R.drawable.home_stamp_option_exciting, "혜음킹"), + CalendarItem(R.drawable.home_stamp_option_anxiety, "태연킹"), + CalendarItem(R.drawable.home_stamp_option_happy, "승원킹"), + CalendarItem(R.drawable.home_stamp_option_normal, "현정킹"), + CalendarItem(R.drawable.home_stamp_option_anxiety, "유은킹") + ) + ), + DateWithItems( + date = "20240802", + items = listOf( + CalendarItem(R.drawable.home_stamp_option_normal, "태연"), + CalendarItem(R.drawable.home_stamp_option_exciting, "승원"), + CalendarItem(R.drawable.home_stamp_option_happy, "현정"), + CalendarItem(R.drawable.home_stamp_option_anxiety, "유은"), + CalendarItem(R.drawable.home_stamp_option_anxiety, "혜음"), + CalendarItem(R.drawable.home_stamp_option_normal, "태연킹왕짱"), + CalendarItem(R.drawable.home_stamp_option_happy, "현정킹왕짱"), + CalendarItem(R.drawable.home_stamp_option_anxiety, "유은킹왕짱"), + CalendarItem(R.drawable.home_stamp_option_normal, "혜음킹왕짱"), + CalendarItem(R.drawable.home_stamp_option_upset, "승원"), + CalendarItem(R.drawable.home_stamp_option_exciting, "현정"), + CalendarItem(R.drawable.home_stamp_option_normal, "유은") + ) + ) + ) + + fun getItemsForDate(date: String): List { + return data.find { it.date == date }?.items ?: emptyList() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/utils/MyDates.kt b/app/src/main/java/com/toyou/toyouandroid/utils/MyDates.kt new file mode 100644 index 00000000..dfdc8409 --- /dev/null +++ b/app/src/main/java/com/toyou/toyouandroid/utils/MyDates.kt @@ -0,0 +1,69 @@ +package com.toyou.toyouandroid.utils + +import com.toyou.toyouandroid.R +import com.toyou.toyouandroid.model.MyDate +import java.util.Calendar + +object MyDates { + + fun generateDates(calendar: Calendar): List { + val dates = mutableListOf() + val cal = calendar.clone() as Calendar + cal.set(Calendar.DAY_OF_MONTH, 1) + + // 더미 이미지 데이터 매핑 + val imageMap = mapOf( + Pair(2024, Calendar.AUGUST) to mapOf( + 1 to R.drawable.home_stamp_option_exciting, + 2 to R.drawable.home_stamp_option_happy + ) + ) + + // 달의 첫 번째 날의 요일 계산 (월요일이 시작일인 경우) + val firstDayOfWeek = (cal.get(Calendar.DAY_OF_WEEK) + 5) % 7 + + // 전월의 마지막 일로 채우기 + cal.add(Calendar.DAY_OF_MONTH, -firstDayOfWeek) + for (i in 0 until firstDayOfWeek) { + dates.add(MyDate(cal.time, null)) + cal.add(Calendar.DAY_OF_MONTH, 1) + } + + // 현재 달의 일자 추가 + val daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH) + for (i in 0 until daysInMonth) { + + val year = cal.get(Calendar.YEAR) + val month = cal.get(Calendar.MONTH) + val day = cal.get(Calendar.DAY_OF_MONTH) + + val imageResId = imageMap[Pair(year, month)]?.get(day) + dates.add(MyDate(cal.time, imageResId)) + cal.add(Calendar.DAY_OF_MONTH, 1) + } + + // 다음 달의 처음 일로 채우기 + val lastDayOfWeek = (cal.get(Calendar.DAY_OF_WEEK) - Calendar.MONDAY + 6) % 7 + val remainingDays = 6 - lastDayOfWeek + + // 마지막 날이 일요일이 아니거나, 마지막 날이 일요일이지만 다음 달 1일이 월요일이 아닌 경우에만 채우기 + if (lastDayOfWeek != 6 || (remainingDays == 0 && cal.get(Calendar.DAY_OF_MONTH) != 1)) { + for (i in 0 until remainingDays) { + dates.add(MyDate(cal.time, null)) + cal.add(Calendar.DAY_OF_MONTH, 1) + } + } + + return dates + } + + fun generateDatesForMonths(calendar: Calendar, monthsBefore: Int, monthsAfter: Int): List { + val dates = mutableListOf() + for (i in -monthsBefore..monthsAfter) { + val cal = calendar.clone() as Calendar + cal.add(Calendar.MONTH, i) + dates.addAll(generateDates(cal)) + } + return dates + } +} \ No newline at end of file diff --git a/app/src/main/java/com/toyou/toyouandroid/utils/SwipeToDeleteNotice.kt b/app/src/main/java/com/toyou/toyouandroid/utils/SwipeToDeleteNotice.kt index 3f90e02c..eebac5fd 100644 --- a/app/src/main/java/com/toyou/toyouandroid/utils/SwipeToDeleteNotice.kt +++ b/app/src/main/java/com/toyou/toyouandroid/utils/SwipeToDeleteNotice.kt @@ -1,25 +1,147 @@ package com.toyou.toyouandroid.utils +import android.graphics.Canvas +import android.view.View import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_SWIPE import androidx.recyclerview.widget.RecyclerView -import com.toyou.toyouandroid.presentation.fragment.notice.NoticeAdapter +import com.toyou.toyouandroid.R +import kotlin.math.min -class SwipeToDeleteNotice( - private val adapter: NoticeAdapter -) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { +class SwipeToDeleteNotice : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { + + // notice_layout swipe 했을 때 <삭제> 화면이 보이도록 고정하기 위한 변수들 + private var currentPosition: Int? = null // 현재 선택된 recycler view의 position + private var previousPosition: Int? = null // 이전에 선택했던 recycler view의 position + private var currentDx = 0f // 현재 x 값 + private var clamp = 0f // 고정시킬 크기 override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder ): Boolean { - return false + return true } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - val position = viewHolder.bindingAdapterPosition - if (position != RecyclerView.NO_POSITION) { - adapter.removeItem(position) + // 스와이프 후 <삭제> 버튼 눌러야 삭제 되도록 변경 + } + + // notice_layout만 슬라이드 되도록 + 일정 범위를 swipe하면 <삭제> 화면 보이게 하기 + + // swipe가 cancel되거나 complete되었을 때 호출 + override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { + currentDx = 0f // 현재 x 위치 초기화 + previousPosition = viewHolder.bindingAdapterPosition // 스와이프 동작이 끝난 view의 position 기억하기 + getDefaultUIUtil().clearView(getView(viewHolder)) + } + + // ItemTouchHelper가 ViewHolder를 스와이프 되었거나 드래그 되었을 때 호출 + override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { + viewHolder?.let { + currentPosition = viewHolder.bindingAdapterPosition // 현재 스와이프 중인 view 의 position 기억하기 + getDefaultUIUtil().onSelected(getView(it)) + } + } + + // 아이템을 터치하거나 스와이프하는 등 뷰에 변화가 생길 경우 호출 + override fun onChildDraw( + c: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + if (actionState == ACTION_STATE_SWIPE) { + val view = getView(viewHolder) + val isClamped = getTag(viewHolder) // 고정할지 말지 결정, true : 고정함 false : 고정 안 함 + val newX = clampViewPositionHorizontal(dX, isClamped, isCurrentlyActive) // newX 만큼 이동(고정 시 이동 위치/고정 해제 시 이동 위치 결정) + + // 고정시킬 시 애니메이션 추가 + if (newX == -clamp) { + getView(viewHolder).animate().translationX(-clamp).setDuration(100L).start() + return + } + + currentDx = newX + getDefaultUIUtil().onDraw( + c, + recyclerView, + view, + newX, + dY, + actionState, + isCurrentlyActive + ) + } + } + + // 사용자가 view를 swipe 했다고 간주할 최소 속도 정하기 + override fun getSwipeEscapeVelocity(defaultValue: Float): Float { + return defaultValue * 8 + } + + // 사용자가 view를 swipe 했다고 간주하기 위해 이동해야하는 부분 반환 + // (사용자가 손을 떼면 호출됨) + override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float { + // -clamp 이상 swipe시 isClamped를 true로 변경 아닐시 false로 변경 + setTag(viewHolder, currentDx <= -clamp) + return 2f + } + + // notice_layout 반환 -> notice_layout만 이동할 수 있게 해줌 + private fun getView(viewHolder: RecyclerView.ViewHolder) : View = viewHolder.itemView.findViewById(R.id.notice_layout) + + // notice_layout swipe 했을 때 휴지통 아이콘이 보이도록 고정 + private fun clampViewPositionHorizontal( + dX: Float, + isClamped: Boolean, + isCurrentlyActive: Boolean + ) : Float { + // RIGHT 방향으로 swipe 막기 + val max = 0f + + // 고정할 수 있으면 + val newX = if (isClamped) { + // 현재 swipe 중이면 swipe되는 영역 제한 + if (isCurrentlyActive) + // 오른쪽 swipe일 때 + if (dX < 0) dX/4 - clamp + // 왼쪽 swipe일 때 + else dX - clamp + // swipe 중이 아니면 고정시키기 + else -clamp + } + // 고정할 수 없으면 newX는 스와이프한 만큼 + else dX / 2 + + // newX가 0보다 작은지 확인 + return min(newX, max) + } + + // isClamped를 view의 tag로 관리 + // isClamped = true : 고정, false : 고정 해제 + private fun setTag(viewHolder: RecyclerView.ViewHolder, isClamped: Boolean) { viewHolder.itemView.tag = isClamped } + private fun getTag(viewHolder: RecyclerView.ViewHolder) : Boolean = viewHolder.itemView.tag as? Boolean ?: false + + + // view가 swipe 되었을 때 고정될 크기 설정 + fun setClamp(clamp: Float) { this.clamp = clamp } + + // 다른 View가 swipe 되거나 터치되면 고정 해제 + fun removePreviousClamp(recyclerView: RecyclerView) { + // 현재 선택한 view가 이전에 선택한 view와 같으면 패스 + if (currentPosition == previousPosition) return + + // 이전에 선택한 위치의 view 고정 해제 + previousPosition?.let { + val viewHolder = recyclerView.findViewHolderForAdapterPosition(it) ?: return + getView(viewHolder).animate().x(0f).setDuration(100L).start() + setTag(viewHolder, false) + previousPosition = null } } } diff --git a/app/src/main/res/drawable/background_friend_calendar_item.xml b/app/src/main/res/drawable/background_friend_calendar_item.xml new file mode 100644 index 00000000..97b3fe61 --- /dev/null +++ b/app/src/main/res/drawable/background_friend_calendar_item.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/dialog_background.xml b/app/src/main/res/drawable/dialog_background.xml new file mode 100644 index 00000000..aaecd296 --- /dev/null +++ b/app/src/main/res/drawable/dialog_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/home_bottomsheet_pseudo.xml b/app/src/main/res/drawable/home_bottomsheet_pseudo.xml new file mode 100644 index 00000000..6eb63db1 --- /dev/null +++ b/app/src/main/res/drawable/home_bottomsheet_pseudo.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/app/src/main/res/drawable/notice_delete_ic.xml b/app/src/main/res/drawable/notice_delete_ic.xml new file mode 100644 index 00000000..3ad0d3e5 --- /dev/null +++ b/app/src/main/res/drawable/notice_delete_ic.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/notice_mypage_box_transparent.xml b/app/src/main/res/drawable/notice_mypage_box_transparent.xml new file mode 100644 index 00000000..6259d2ee --- /dev/null +++ b/app/src/main/res/drawable/notice_mypage_box_transparent.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/signupnickname_input.xml b/app/src/main/res/drawable/signupnickname_input.xml index 92e15d92..7fd1bd8d 100644 --- a/app/src/main/res/drawable/signupnickname_input.xml +++ b/app/src/main/res/drawable/signupnickname_input.xml @@ -2,7 +2,7 @@ + android:color="@color/white" /> diff --git a/app/src/main/res/layout/calendar_friendrecord_item.xml b/app/src/main/res/layout/calendar_friendrecord_item.xml new file mode 100644 index 00000000..28c62c73 --- /dev/null +++ b/app/src/main/res/layout/calendar_friendrecord_item.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/calendar_item.xml b/app/src/main/res/layout/calendar_item.xml new file mode 100644 index 00000000..b4abfa57 --- /dev/null +++ b/app/src/main/res/layout/calendar_item.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/calendar_myrecord_item.xml b/app/src/main/res/layout/calendar_myrecord_item.xml new file mode 100644 index 00000000..9353d943 --- /dev/null +++ b/app/src/main/res/layout/calendar_myrecord_item.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/calendar_page.xml b/app/src/main/res/layout/calendar_page.xml new file mode 100644 index 00000000..838ba2f3 --- /dev/null +++ b/app/src/main/res/layout/calendar_page.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_mypage.xml b/app/src/main/res/layout/dialog_mypage.xml new file mode 100644 index 00000000..6ac7e5e2 --- /dev/null +++ b/app/src/main/res/layout/dialog_mypage.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_calendar.xml b/app/src/main/res/layout/fragment_calendar.xml deleted file mode 100644 index 90a98171..00000000 --- a/app/src/main/res/layout/fragment_calendar.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_calendar_friendrecord.xml b/app/src/main/res/layout/fragment_calendar_friendrecord.xml new file mode 100644 index 00000000..c2a8a9bc --- /dev/null +++ b/app/src/main/res/layout/fragment_calendar_friendrecord.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + +