Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/android/double click: 다중 클릭 방지 개선 및 UI, Notification 개선 #230

Merged
merged 10 commits into from
Dec 13, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ class EventStoryRepository @Inject constructor(
fun getFollowingWithEventState(eventId: Int): Flow<List<UserStatus>> {
return flowOf(true)
.map {
eventStoryApi.getFollowingWithEventStatus(eventId).users
eventStoryApi.getFollowingWithEventStatus(eventId).users.sortedBy { it.nickname }
}.catch {
throw it.toException()
}
Expand All @@ -206,7 +206,7 @@ class EventStoryRepository @Inject constructor(
fun getFollowerWithEventState(eventId: Int): Flow<List<UserStatus>> {
return flowOf(true)
.map {
eventStoryApi.getFollowerWithEventStatus(eventId).users
eventStoryApi.getFollowerWithEventStatus(eventId).users.sortedBy { it.nickname }
}.catch {
throw it.toException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class FollowRepository @Inject constructor(
fun getFollowingWithFollowState(): Flow<List<UserStatus>> {
return flowOf(true)
.map {
followApi.getFollowingWithFollowStatus().users
followApi.getFollowingWithFollowStatus().users.sortedBy { it.nickname }
}.catch {
throw it.toException()
}
Expand All @@ -44,7 +44,7 @@ class FollowRepository @Inject constructor(
fun getFollowerWithFollowState(): Flow<List<UserStatus>> {
return flowOf(true)
.map {
followApi.getFollowerWithFollowStatus().users
followApi.getFollowerWithFollowStatus().users.sortedBy { it.nickname }
}.catch {
throw it.toException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import com.teameetmeet.meetmeet.databinding.ActivityAddEventBinding
import com.teameetmeet.meetmeet.presentation.base.BaseActivity
import com.teameetmeet.meetmeet.presentation.model.EventNotification
import com.teameetmeet.meetmeet.presentation.model.EventRepeatTerm
import com.teameetmeet.meetmeet.presentation.util.setClickEvent
import com.teameetmeet.meetmeet.presentation.util.setMenuClickEvent
import com.teameetmeet.meetmeet.util.date.toLocalDateTime
import com.teameetmeet.meetmeet.util.date.toLong
import dagger.hilt.android.AndroidEntryPoint
Expand Down Expand Up @@ -51,14 +53,11 @@ class AddEventActivity : BaseActivity<ActivityAddEventBinding>(R.layout.activity

private fun setTopAppBar() {
with(binding.topAppBar) {
setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
setMenuClickEvent(lifecycleScope) { menuItemId ->
Copy link
Collaborator

@agfalcon agfalcon Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

menu click에 대한 더블 클릭을 구현하셨네요!!! 대단합니다..

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

when (menuItemId) {
R.id.menu_save -> {
viewModel.eventSave()
true
}

else -> false
}
}
setNavigationOnClickListener {
Expand Down Expand Up @@ -138,13 +137,13 @@ class AddEventActivity : BaseActivity<ActivityAddEventBinding>(R.layout.activity
)
}

binding.addEventTvValueStartDate.setOnClickListener {
binding.addEventTvValueStartDate.setClickEvent(lifecycleScope) {
dateRangePicker.show(supportFragmentManager, "DateRangePicker")
}
binding.addEventTvValueEndDate.setOnClickListener {
binding.addEventTvValueEndDate.setClickEvent(lifecycleScope) {
dateRangePicker.show(supportFragmentManager, "DateRangePicker")
}
binding.eventStoryTvValueEventRepeatEndDate.setOnClickListener {
binding.eventStoryTvValueEventRepeatEndDate.setClickEvent(lifecycleScope) {
val datePicker = MaterialDatePicker.Builder.datePicker()
.setTitleText(getString(R.string.story_detail_description_event_repeat_end_date))
.build()
Expand Down Expand Up @@ -173,10 +172,10 @@ class AddEventActivity : BaseActivity<ActivityAddEventBinding>(R.layout.activity
viewModel.setEventEndTime(endTimePicker.hour, endTimePicker.minute)
}

binding.addEventTvValueStartTime.setOnClickListener {
binding.addEventTvValueStartTime.setClickEvent(lifecycleScope) {
startTimePicker.show(supportFragmentManager, "StartTimePicker")
}
binding.addEventTvValueEndTime.setOnClickListener {
binding.addEventTvValueEndTime.setClickEvent(lifecycleScope) {
endTimePicker.show(supportFragmentManager, "EndTimePicker")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,29 @@ import com.teameetmeet.meetmeet.data.model.UserStatus
class FollowAdapter(
private val actionType: FollowActionType,
private val userClickListener: OnUserClickListener,
private val id: Int?
) :
ListAdapter<UserStatus, FollowViewHolder>(ItemDiffCallback) {
private val eventId: Int?
) : ListAdapter<UserStatus, FollowViewHolder>(diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FollowViewHolder {
return FollowViewHolder.from(parent)
return FollowViewHolder.from(parent, actionType, userClickListener, eventId)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

뷰홀더 생성 시 인자 넣어주는 것 좋습니다!!

}

override fun onBindViewHolder(holder: FollowViewHolder, position: Int) {
holder.bind(getItem(position), actionType, userClickListener, id)
holder.bind(getItem(position))
}

object ItemDiffCallback : DiffUtil.ItemCallback<UserStatus>() {
override fun areItemsTheSame(
oldItem: UserStatus,
newItem: UserStatus
): Boolean {
return oldItem.id == newItem.id
}
companion object {
private val diffCallback = object : DiffUtil.ItemCallback<UserStatus>() {
override fun areItemsTheSame(
oldItem: UserStatus, newItem: UserStatus
): Boolean {
return oldItem.id == newItem.id
}

override fun areContentsTheSame(
oldItem: UserStatus,
newItem: UserStatus
): Boolean {
return oldItem == newItem
override fun areContentsTheSame(
oldItem: UserStatus, newItem: UserStatus
): Boolean {
return oldItem == newItem
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class FollowFragment : BaseFragment<FragmentFollowBinding>(R.layout.fragment_fol
followAdapter = FollowAdapter(
actionType = args.actionType,
userClickListener = viewModel,
id = args.id
eventId = args.id
)
binding.followSearchResultRv.adapter = followAdapter
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class FollowSearchFragment :
binding.state = followState

followAdapter = FollowAdapter(
actionType = actionType, userClickListener = followViewModel, id = id
actionType = actionType, userClickListener = followViewModel, eventId = id
)
binding.followListRv.adapter = followAdapter
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,111 @@ package com.teameetmeet.meetmeet.presentation.follow

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.doOnAttach
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.teameetmeet.meetmeet.R
import com.teameetmeet.meetmeet.data.model.UserStatus
import com.teameetmeet.meetmeet.databinding.ItemFollowBinding
import com.teameetmeet.meetmeet.presentation.util.setClickEvent

class FollowViewHolder private constructor(private val binding: ItemFollowBinding) :
RecyclerView.ViewHolder(binding.root) {
class FollowViewHolder private constructor(
private val binding: ItemFollowBinding,
private val actionType: FollowActionType,
private val userClickListener: OnUserClickListener,
private val eventId: Int?
) : RecyclerView.ViewHolder(binding.root) {

fun bind(
user: UserStatus,
actionType: FollowActionType,
userClickListener: OnUserClickListener,
id: Int?
) {
binding.user = user
itemView.setOnClickListener {
userClickListener.onProfileClick(user)
}
when (actionType) {
FollowActionType.FOLLOW -> {
with(binding.followBtnAction) {
user.isFollowed?.let { followStatus ->
if (followStatus) {
text = context.getString(R.string.follow_title_unfollow)
setOnClickListener {
userClickListener.onUnfollowClick(user)
}
} else {
text = context.getString(R.string.follow_title_follow)
setOnClickListener {
userClickListener.onFollowClick(user)
}
}
init {
itemView.doOnAttach {
itemView.findViewTreeLifecycleOwner()?.let { lifecycleOwner ->
binding.user?.let { user ->
itemView.setClickEvent(lifecycleOwner.lifecycleScope) {
userClickListener.onProfileClick(user)
}
}
}

FollowActionType.EVENT -> {
with(binding.followBtnAction) {
when (user.isJoined) {
UserStatus.JOIN_STATUS_JOINABLE -> {
text = context.getString(R.string.event_story_invite)
setOnClickListener {
id?.let {
userClickListener.onInviteEventClick(user, id)
when (actionType) {
FollowActionType.FOLLOW -> {
with(binding.followBtnAction) {
user.isFollowed?.let { followStatus ->
if (followStatus) {
text = context.getString(R.string.follow_title_unfollow)
setClickEvent(lifecycleOwner.lifecycleScope) {
userClickListener.onUnfollowClick(user)
}
} else {
text = context.getString(R.string.follow_title_follow)
setClickEvent(lifecycleOwner.lifecycleScope) {
userClickListener.onFollowClick(user)
}
}
}
}
isEnabled = true
}

UserStatus.JOIN_STATUS_PENDING -> {
text = context.getString(R.string.event_story_pending)
isEnabled = false
}
FollowActionType.EVENT -> {
with(binding.followBtnAction) {
when (user.isJoined) {
UserStatus.JOIN_STATUS_JOINABLE -> {
text = context.getString(R.string.event_story_invite)
setClickEvent(lifecycleOwner.lifecycleScope) {
eventId?.let {
userClickListener.onInviteEventClick(user, eventId)
}
}
isEnabled = true
}

UserStatus.JOIN_STATUS_ACCEPTED -> {
text = context.getString(R.string.event_story_participating)
isEnabled = false
}
UserStatus.JOIN_STATUS_PENDING -> {
text = context.getString(R.string.event_story_pending)
isEnabled = false
}

UserStatus.JOIN_STATUS_ACCEPTED -> {
text = context.getString(R.string.event_story_participating)
isEnabled = false
}

else -> {
isEnabled = false
else -> {
isEnabled = false
}
}
}
}
}
}
}

FollowActionType.GROUP -> {
binding.followBtnAction.setOnClickListener {
id?.let {
userClickListener.onInviteGroupClick(user, id)
FollowActionType.GROUP -> {
binding.followBtnAction.setClickEvent(lifecycleOwner.lifecycleScope) {
eventId?.let {
userClickListener.onInviteGroupClick(user, eventId)
}
}
}
}
}
}
}
}

fun bind(
user: UserStatus
) {
binding.user = user
}

companion object {
fun from(parent: ViewGroup): FollowViewHolder {
fun from(
parent: ViewGroup,
actionType: FollowActionType,
userClickListener: OnUserClickListener,
eventId: Int?
): FollowViewHolder {
val inflater = LayoutInflater.from(parent.context)
return FollowViewHolder(ItemFollowBinding.inflate(inflater, parent, false))
return FollowViewHolder(
ItemFollowBinding.inflate(inflater, parent, false),
actionType,
userClickListener,
eventId
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,14 @@ class EventNotificationViewModel @Inject constructor(

fun onDeleteAll() {
viewModelScope.launch {
userRepository.deleteUserNotification(
_eventNotificationList.value.map { it.inviteId }.joinToString(",")
).catch {
emitExceptionEvent(it, R.string.notification_delete_fail)
}.collectLatest {
fetchEventNotificationList()
if (_eventNotificationList.value.isNotEmpty()) {
userRepository.deleteUserNotification(
_eventNotificationList.value.map { it.inviteId }.joinToString(",")
).catch {
emitExceptionEvent(it, R.string.notification_delete_fail)
}.collectLatest {
fetchEventNotificationList()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ class FollowNotificationViewModel @Inject constructor(

fun onDeleteAll() {
viewModelScope.launch {
userRepository.deleteUserNotification(
_followNotificationList.value.map { it.inviteId }.joinToString(",")
).catch {
emitExceptionEvent(it, R.string.notification_delete_fail)
}.collectLatest {
fetchFollowNotificationList()
if (_followNotificationList.value.isNotEmpty()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외 처리 굳굳 좋습니다!!

userRepository.deleteUserNotification(
_followNotificationList.value.map { it.inviteId }.joinToString(",")
).catch {
emitExceptionEvent(it, R.string.notification_delete_fail)
}.collectLatest {
fetchFollowNotificationList()
}
}
}
}
Expand Down
Loading