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

Feature/android/#35 join event : 일정 참여, 일정 멤버 자세히 보기, 알림 화면 구현 #163

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class NoDataException : Exception() //데이터 요청 시 반환되는 데이
class ExpiredTokenException(): Exception()
class ExpiredRefreshTokenException(): Exception() // refreshToken 만료인 경우


fun Throwable.toException(): Throwable {
return when(this) {
is HttpException -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,43 @@
package com.teameetmeet.meetmeet.data.model

import android.os.Parcel
import android.os.Parcelable
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class EventMember(
@Json(name = "id")
val id: Int,
@Json(name = "nickname")
val nickname: String,
@Json(name = "profile")
val profile: String
) : Parcelable {
Comment on lines +8 to +16
Copy link
Collaborator

Choose a reason for hiding this comment

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

args로 전달하기 위해 Parcelable로 선언한 부분인가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

네 맞습니다!!! 이벤트 멤버를 전달해서 더보기에서 사용하기 위해 Parcelable로 구현을 했습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

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

이거 list를 data class로 한번 더 감싸면 serealizable만 상속받아도 전달할 수 있더라고요! 뭐가 더 나은지는 모르겠어요...

constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString().toString(),
parcel.readString().toString()
) {
}

override fun describeContents(): Int {
return id
}

override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id)
parcel.writeString(nickname)
parcel.writeString(profile)
}

companion object CREATOR : Parcelable.Creator<EventMember> {
override fun createFromParcel(parcel: Parcel): EventMember {
return EventMember(parcel)
}

)
override fun newArray(size: Int): Array<EventMember?> {
return arrayOfNulls(size)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.teameetmeet.meetmeet.data.model

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class UserWithFollowStatus(
@Json(name = "id")
val id: Int,
@Json(name = "nickname")
val nickname: String,
@Json(name = "profile")
val profile: String,
@Json(name = "isFollowed")
val isFollowed: Boolean,
val isMe: Boolean = false
)
Comment on lines +6 to +17
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 부분은 팔로우랑 일정 초대 부분을 묶어서 구현해야할 것 같아서 제가 나중에 수정할 수도 있을 것 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵넵 좋습니다. isMe 부분은 자기를 검색했을 때 버튼을 보여주지 않기 위해서 사용을 했고 repository에서 자기와 닉네임이 같은 지 검사하여 isMe 부분을 변경하는 로직을 함께 작성 했어요!

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ interface EventStoryApi {
@POST()
suspend fun editNotification(@Body singleStringRequest: KakaoLoginRequest)

@POST("event/schedule/join/{eventId}")
suspend fun joinEventStory(@Path("eventId") eventId: Int)

@DELETE("event/{eventId}")
suspend fun deleteEventStory(
@Path("eventId") id: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.teameetmeet.meetmeet.data.network.api

import com.teameetmeet.meetmeet.data.network.entity.FollowRequest
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.POST
import retrofit2.http.Query

interface FollowApi {

@POST("follow")
suspend fun follow(@Body followRequest: FollowRequest)

@DELETE("follow/follow")
suspend fun unFollow(@Query("userId") userId: Int)
Comment on lines +11 to +15
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍👍

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.teameetmeet.meetmeet.data.network.api

import com.teameetmeet.meetmeet.data.model.UserProfile
import com.teameetmeet.meetmeet.data.model.UserWithFollowStatus
import com.teameetmeet.meetmeet.data.network.entity.AvailableResponse
import com.teameetmeet.meetmeet.data.network.entity.PasswordChangeRequest
import okhttp3.MultipartBody
Expand All @@ -24,6 +25,9 @@ interface UserApi {
@GET("auth/check/nickname")
suspend fun checkNickNameDuplication(@Query("nickname") nickname: String): AvailableResponse

@GET("user/search")
suspend fun getUserWithFollowStatus(@Query("nickname") nickname: String): UserWithFollowStatus

@PATCH("user/account")
suspend fun patchPassword(@Body passwordChangeRequest: PasswordChangeRequest): UserProfile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.teameetmeet.meetmeet.data.network.api.AuthApi
import com.teameetmeet.meetmeet.data.network.api.CalendarApi
import com.teameetmeet.meetmeet.data.network.api.EventStoryApi
import com.teameetmeet.meetmeet.data.network.api.FollowApi
import com.teameetmeet.meetmeet.data.network.api.LoginApi
import com.teameetmeet.meetmeet.data.network.api.UserApi
import com.teameetmeet.meetmeet.data.repository.TokenRepository
Expand Down Expand Up @@ -135,4 +136,9 @@ class NetworkModule {
fun provideEventStoryApi(@Named("retrofitWithAuth") retrofit: Retrofit): EventStoryApi
= retrofit.create(EventStoryApi::class.java)

@Singleton
@Provides
fun provideFollowApi(@Named("retrofitWithAuth") retrofit: Retrofit): FollowApi
= retrofit.create(FollowApi::class.java)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.teameetmeet.meetmeet.data.network.entity

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class FollowRequest(
@Json(name = "userId")
val userId: Int
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class EventStoryRepository @Inject constructor(
}.catch {
throw it.toException()
}
//TODO("이벤트 세부 정보 가져오고 로컬에 이벤트가 있으면 색과 알림 가져오기 아니면 DEFAULT 색 일정으로 파싱해서 내리기")
}

fun deleteEventStory(id: Int, isAll: Boolean = false): Flow<Unit> {
Expand Down Expand Up @@ -94,7 +93,7 @@ class EventStoryRepository @Inject constructor(
.map {
eventStoryApi.editNotification(KakaoLoginRequest(message))
}.catch {
throw it
throw it.toException()
}
}

Expand All @@ -114,4 +113,12 @@ class EventStoryRepository @Inject constructor(
}
}

fun joinEventStory(eventId: Int): Flow<Unit> {
return flowOf(true).map {
eventStoryApi.joinEventStory(eventId)
}.catch {
throw it.toException()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.teameetmeet.meetmeet.data.repository

import com.teameetmeet.meetmeet.data.network.api.FollowApi
import com.teameetmeet.meetmeet.data.network.entity.FollowRequest
import com.teameetmeet.meetmeet.data.toException
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class FollowRepository @Inject constructor(
private val followApi: FollowApi
) {

fun follow(userId: Int): Flow<Unit> {
return flowOf(true)
.map{
followApi.follow(FollowRequest(userId = userId))
}.catch {
throw it.toException()
}
}

fun unFollow(userId: Int): Flow<Unit> {
return flowOf(true)
.map {
followApi.unFollow(userId = userId)
}.catch {
throw it.toException()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.teameetmeet.meetmeet.data.repository

import com.teameetmeet.meetmeet.data.NoDataException
import com.teameetmeet.meetmeet.data.local.datastore.DataStoreHelper
import com.teameetmeet.meetmeet.data.model.UserProfile
import com.teameetmeet.meetmeet.data.model.UserWithFollowStatus
import com.teameetmeet.meetmeet.data.network.api.UserApi
import com.teameetmeet.meetmeet.data.network.entity.PasswordChangeRequest
import com.teameetmeet.meetmeet.data.toException
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
Expand All @@ -25,9 +26,7 @@ class UserRepository @Inject constructor(
fun getUserProfile(): Flow<UserProfile> {
return flowOf(true)
.map {
val token = dataStore.getAppToken().first() ?: throw NoDataException()
val result = userApi.getUserProfile()
result
userApi.getUserProfile()
}.onEach {
fetchUserProfile(it)
}.catch {
Expand All @@ -50,6 +49,22 @@ class UserRepository @Inject constructor(
}
}

suspend fun getUserWithFollowStatus(nickname: String): Flow<UserWithFollowStatus> {
val userNickname = dataStore.getUserProfile().first().nickname
return flowOf(true)
.map {
val user = userApi.getUserWithFollowStatus(nickname)
if(user.nickname == userNickname) {
user.copy(isMe = true)
} else {
user
}
}.catch {
throw it.toException()
}
}


private suspend fun fetchUserProfile(userProfile: UserProfile) {
dataStore.fetchUserProfile(userProfile)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import com.teameetmeet.meetmeet.data.datasource.RemoteCalendarDataSource
import com.teameetmeet.meetmeet.data.local.datastore.DataStoreHelper
import com.teameetmeet.meetmeet.data.network.api.AuthApi
import com.teameetmeet.meetmeet.data.network.api.EventStoryApi
import com.teameetmeet.meetmeet.data.network.api.FollowApi
import com.teameetmeet.meetmeet.data.network.api.LoginApi
import com.teameetmeet.meetmeet.data.network.api.UserApi
import com.teameetmeet.meetmeet.data.repository.CalendarRepository
import com.teameetmeet.meetmeet.data.repository.EventStoryRepository
import com.teameetmeet.meetmeet.data.repository.FollowRepository
import com.teameetmeet.meetmeet.data.repository.LoginRepository
import com.teameetmeet.meetmeet.data.repository.SettingRepository
import com.teameetmeet.meetmeet.data.repository.TokenRepository
Expand Down Expand Up @@ -63,4 +65,10 @@ class RepositoryModule {
dataStore: DataStoreHelper,
authApi: AuthApi
) = TokenRepository(dataStore, authApi)

@Singleton
@Provides
fun provideFollowRepository(
followApi: FollowApi
) = FollowRepository(followApi)
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,21 @@ class EventStoryFragment : BaseFragment<FragmentEventStoryBinding>(R.layout.frag
showDialog(viewModel.getNoti())
}
eventStoryIbSeeMoreMember.setOnClickListener {
//TODO("더보기")
findNavController().navigate(EventStoryFragmentDirections.actionEventStoryFragmentToEventMemberFragment(viewModel.eventStoryUiState.value.eventStory?.eventMembers?.toTypedArray().orEmpty()))
}
eventStoryCvInviteMember.setOnClickListener {
when (viewModel.eventStoryUiState.value.authority) {
EventAuthority.GUEST -> {}//TODO("참여 신청")
EventAuthority.GUEST -> {
viewModel.joinEventStory()
}
EventAuthority.OWNER -> {
//TODO("초대 페이지로 이동")
viewModel.eventStoryUiState.value.eventStory?.let { story ->
findNavController().navigate(
EventStoryFragmentDirections.actionEventStoryFragmentToFollowFragment()
.setId(story.id)
)
}
}

else -> return@setOnClickListener
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ class EventStoryViewModel @Inject constructor(
return eventStoryUiState.value.eventStory?.announcement.orEmpty()
}

fun joinEventStory() {
viewModelScope.launch {
eventStoryRepository.joinEventStory(eventStoryUiState.value.eventId).catch { exception ->
when(exception) {
is ExpiredRefreshTokenException -> _event.emit(EventStoryEvent.NavigateToLoginActivity)
is UnknownHostException -> _event.emit(EventStoryEvent.ShowMessage(R.string.common_message_no_internet))
else -> _event.emit(EventStoryEvent.ShowMessage(R.string.event_story_message_join_event_fail, exception.message.orEmpty()))
}
}.collect {
_event.emit(EventStoryEvent.ShowMessage(R.string.event_story_message_join_event_success))
}
}
}


override fun onItemClick() {
_eventStoryUiState.update {
Expand All @@ -86,6 +100,7 @@ class EventStoryViewModel @Inject constructor(
}
}


override fun onSaveButtonClick(message: String) {
viewModelScope.launch {
eventStoryRepository.editNotification(message).catch {
Expand All @@ -94,7 +109,6 @@ class EventStoryViewModel @Inject constructor(
_eventStoryUiState.update {
it.copy(eventStory = eventStoryUiState.value.eventStory?.copy(announcement = message))
}
//TODO("일정 공지 수정되는 거 봐야함")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.teameetmeet.meetmeet.presentation.eventstory.eventstory.eventmember

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import com.teameetmeet.meetmeet.data.model.UserWithFollowStatus
import com.teameetmeet.meetmeet.databinding.ItemEventJoinMemberBinding

class EventMemberAdapter(private val eventMemberClickListener: EventMemberClickListener) : ListAdapter<UserWithFollowStatus, EventMemberViewHolder>(diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventMemberViewHolder {
val binding = ItemEventJoinMemberBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return EventMemberViewHolder(binding, eventMemberClickListener)
}

override fun onBindViewHolder(holder: EventMemberViewHolder, position: Int) {
holder.bind(getItem(position))
}

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

override fun areContentsTheSame(
oldItem: UserWithFollowStatus,
newItem: UserWithFollowStatus
): Boolean {
return oldItem == newItem
}

}
}
}
Loading