Skip to content

Commit ae14470

Browse files
committed
✨ 바뀐 그룹 내용이 실시간으로 반영되도록 변경
1 parent be8bc85 commit ae14470

File tree

7 files changed

+110
-30
lines changed

7 files changed

+110
-30
lines changed

data/src/main/java/com/whyranoid/data/group/GroupDataSource.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@ import com.whyranoid.data.constant.FieldId.GROUP_NAME
1010
import com.whyranoid.data.constant.FieldId.JOINED_GROUP_LIST
1111
import com.whyranoid.data.constant.FieldId.RULES
1212
import com.whyranoid.data.model.GroupInfoResponse
13+
import com.whyranoid.data.model.UserResponse
14+
import com.whyranoid.data.model.toGroupInfo
15+
import com.whyranoid.data.model.toUser
16+
import com.whyranoid.domain.model.GroupInfo
1317
import com.whyranoid.domain.model.Rule
18+
import com.whyranoid.domain.model.toRule
19+
import kotlinx.coroutines.channels.awaitClose
20+
import kotlinx.coroutines.flow.Flow
21+
import kotlinx.coroutines.flow.callbackFlow
1422
import kotlinx.coroutines.suspendCancellableCoroutine
1523
import java.util.UUID
1624
import javax.inject.Inject
@@ -116,4 +124,32 @@ class GroupDataSource @Inject constructor(
116124
}
117125
}
118126
}
127+
128+
fun getGroupInfoFlow(uid: String, groupId: String): Flow<GroupInfo> = callbackFlow {
129+
db.collection(GROUPS_COLLECTION)
130+
.document(groupId)
131+
.addSnapshotListener { documentSnapshot, _ ->
132+
val groupInfoResponse = documentSnapshot?.toObject(GroupInfoResponse::class.java)
133+
134+
groupInfoResponse?.let {
135+
db.collection(USERS_COLLECTION)
136+
.document(uid)
137+
.addSnapshotListener { documentSnapshot, _ ->
138+
val userResponse = documentSnapshot?.toObject(UserResponse::class.java)
139+
140+
userResponse?.let {
141+
trySend(
142+
groupInfoResponse.toGroupInfo(
143+
leader = userResponse.toUser(),
144+
rules = groupInfoResponse.rules.map {
145+
it.toRule()
146+
}
147+
)
148+
)
149+
}
150+
}
151+
}
152+
}
153+
awaitClose()
154+
}
119155
}

data/src/main/java/com/whyranoid/data/group/GroupRepositoryImpl.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ class GroupRepositoryImpl @Inject constructor(
3838
return groupDataSource.joinGroup(uid, groupId)
3939
}
4040

41+
override fun getGroupInfoFlow(uid: String, groupId: String): Flow<GroupInfo> {
42+
return groupDataSource.getGroupInfoFlow(uid, groupId)
43+
}
44+
4145
override fun getGroupNotifications(groupId: String): Flow<List<GroupNotification>> {
4246
return groupNotificationDataSource.getGroupNotifications(groupId)
4347
}
@@ -46,7 +50,12 @@ class GroupRepositoryImpl @Inject constructor(
4650
groupNotificationDataSource.notifyRunningStart(uid, groupIdList)
4751
}
4852

49-
override suspend fun createGroup(groupName: String, introduce: String, rules: List<String>, uid: String): Boolean {
53+
override suspend fun createGroup(
54+
groupName: String,
55+
introduce: String,
56+
rules: List<String>,
57+
uid: String
58+
): Boolean {
5059
return groupDataSource.createGroup(groupName, introduce, rules, uid)
5160
}
5261
}

domain/src/main/java/com/whyranoid/domain/repository/GroupRepository.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,19 @@ interface GroupRepository {
2525
// 그룹 나가기 / 그룹에서 먼저 나간 후 성공하면 User 에 반영하기
2626
suspend fun exitGroup(uid: String, groupId: String): Boolean
2727

28+
// 그룹의 정보를 Flow로 가져오기
29+
fun getGroupInfoFlow(uid: String, groupId: String): Flow<GroupInfo>
30+
2831
// 혹은 그룹 채팅을 가져오기 + 글 작성하기
2932
fun getGroupNotifications(groupId: String): Flow<List<GroupNotification>>
3033

3134
suspend fun notifyRunningStart(uid: String, groupIdList: List<String>)
3235

3336
// 그룹 생성하기
34-
suspend fun createGroup(groupName: String, introduce: String, rules: List<String>, uid: String): Boolean
37+
suspend fun createGroup(
38+
groupName: String,
39+
introduce: String,
40+
rules: List<String>,
41+
uid: String
42+
): Boolean
3543
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.whyranoid.domain.usecase
2+
3+
import com.whyranoid.domain.model.GroupInfo
4+
import com.whyranoid.domain.repository.GroupRepository
5+
import kotlinx.coroutines.flow.Flow
6+
import javax.inject.Inject
7+
8+
class GetGroupInfoUseCase @Inject constructor(
9+
private val groupRepository: GroupRepository
10+
) {
11+
operator fun invoke(uid: String, groupId: String): Flow<GroupInfo> {
12+
return groupRepository.getGroupInfoFlow(uid, groupId)
13+
}
14+
}

presentation/src/main/java/com/whyranoid/presentation/community/group/detail/GroupDetailFragment.kt

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ internal class GroupDetailFragment :
3232
private fun setupMenu() {
3333
with(binding.topAppBar) {
3434
// TODO : uid를 DataStore에서 가져올 수 있도록 변경
35-
if (groupDetailArgs.groupInfo.leader.name == "soopeach") {
36-
inflateMenu(R.menu.group_detail_menu)
37-
}
35+
if (viewModel.isLeader) inflateMenu(R.menu.group_detail_menu)
3836

3937
setOnMenuItemClickListener { menuItem ->
4038
when (menuItem.itemId) {
@@ -43,7 +41,10 @@ internal class GroupDetailFragment :
4341
val dialog = GroupSettingDialog(
4442
// TODO : 그룹 수정으로 이동
4543
onEditButtonClickListener = {
46-
val action = GroupDetailFragmentDirections.actionGroupDetailFragmentToEditGroupFragment(groupDetailArgs.groupInfo)
44+
val action =
45+
GroupDetailFragmentDirections.actionGroupDetailFragmentToEditGroupFragment(
46+
groupDetailArgs.groupInfo
47+
)
4748
findNavController().navigate(action)
4849
},
4950
// TODO : 그룹 삭제
@@ -93,13 +94,7 @@ internal class GroupDetailFragment :
9394
}
9495

9596
private fun setBindingData() {
96-
with(binding) {
97-
viewModel = viewModel
98-
groupInfo = groupDetailArgs.groupInfo
99-
// TODO : uid를 DataStore에서 가져올 수 있도록 변경
100-
// TODO : ViewModel로 옮기기
101-
isLeader = groupDetailArgs.groupInfo.leader.name == "soopeach"
102-
}
97+
binding.viewModel = viewModel
10398
}
10499

105100
// TODO : uid를 DataStore에서 가져올 수 있도록 변경

presentation/src/main/java/com/whyranoid/presentation/community/group/detail/GroupDetailViewModel.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,45 @@
11
package com.whyranoid.presentation.community.group.detail
22

3+
import androidx.lifecycle.SavedStateHandle
34
import androidx.lifecycle.ViewModel
45
import androidx.lifecycle.viewModelScope
56
import com.whyranoid.domain.model.FinishNotification
67
import com.whyranoid.domain.model.GroupNotification
78
import com.whyranoid.domain.model.StartNotification
9+
import com.whyranoid.domain.usecase.GetGroupInfoUseCase
810
import com.whyranoid.domain.usecase.GetGroupNotificationsUseCase
11+
import com.whyranoid.presentation.model.GroupInfoUiModel
12+
import com.whyranoid.presentation.model.toGroupInfoUiModel
913
import dagger.hilt.android.lifecycle.HiltViewModel
1014
import kotlinx.coroutines.flow.MutableSharedFlow
1115
import kotlinx.coroutines.flow.MutableStateFlow
1216
import kotlinx.coroutines.flow.SharedFlow
17+
import kotlinx.coroutines.flow.StateFlow
1318
import kotlinx.coroutines.flow.asSharedFlow
19+
import kotlinx.coroutines.flow.asStateFlow
1420
import kotlinx.coroutines.flow.launchIn
1521
import kotlinx.coroutines.flow.onEach
1622
import kotlinx.coroutines.launch
1723
import javax.inject.Inject
1824

1925
@HiltViewModel
2026
class GroupDetailViewModel @Inject constructor(
21-
getGroupNotificationsUseCase: GetGroupNotificationsUseCase
27+
getGroupInfoUseCase: GetGroupInfoUseCase,
28+
getGroupNotificationsUseCase: GetGroupNotificationsUseCase,
29+
stateHandle: SavedStateHandle
2230
) : ViewModel() {
2331

32+
private val groupId = stateHandle.get<GroupInfoUiModel>("groupInfo")?.groupId ?: ""
33+
34+
// TODO : 데이터 스토어에 저장된 Uid와 비교해야함.
35+
val isLeader =
36+
stateHandle.get<GroupInfoUiModel>("groupInfo")?.leader?.name == "soopeach"
37+
38+
private var _groupInfo =
39+
MutableStateFlow<GroupInfoUiModel>(stateHandle.get<GroupInfoUiModel>("groupInfo")!!)
40+
val groupInfo: StateFlow<GroupInfoUiModel>
41+
get() = _groupInfo.asStateFlow()
42+
2443
private val _eventFlow = MutableSharedFlow<Event>()
2544
val eventFlow: SharedFlow<Event>
2645
get() = _eventFlow.asSharedFlow()
@@ -30,6 +49,13 @@ class GroupDetailViewModel @Inject constructor(
3049
val mergedNotifications = MutableStateFlow<List<GroupNotification>>(emptyList())
3150

3251
init {
52+
53+
// TODO : uid를 DataStore에서 가져오도록 변경
54+
getGroupInfoUseCase("hsjeon", groupId).onEach { groupInfo ->
55+
println("테스트 $groupInfo")
56+
_groupInfo.value = groupInfo.toGroupInfoUiModel()
57+
}.launchIn(viewModelScope)
58+
3359
// TODO : 그룹 아이디를 프레그먼트에서 받아오도록 변경
3460
getGroupNotificationsUseCase("수피치 그룹1").onEach { notifications ->
3561

presentation/src/main/res/layout/fragment_group_detail.xml

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,6 @@
77

88
<import type="android.view.View" />
99

10-
<variable
11-
name="isLeader"
12-
type="Boolean" />
13-
14-
<variable
15-
name="groupInfo"
16-
type="com.whyranoid.presentation.model.GroupInfoUiModel" />
17-
1810
<variable
1911
name="viewModel"
2012
type="com.whyranoid.presentation.community.group.detail.GroupDetailViewModel" />
@@ -35,7 +27,7 @@
3527
style="@style/Widget.MaterialComponents.Toolbar.Primary"
3628
android:layout_width="match_parent"
3729
android:layout_height="?attr/actionBarSize"
38-
app:title="@{groupInfo.name}"
30+
app:title="@{viewModel.groupInfo.name}"
3931
tools:title ="수피치 그룹"/>
4032

4133
</com.google.android.material.appbar.AppBarLayout>
@@ -61,7 +53,7 @@
6153
android:layout_height="wrap_content"
6254
android:layout_margin="16dp"
6355
android:gravity="center"
64-
android:text="@{groupInfo.name}"
56+
android:text="@{viewModel.groupInfo.name}"
6557
app:layout_constraintEnd_toEndOf="parent"
6658
app:layout_constraintStart_toStartOf="parent"
6759
app:layout_constraintTop_toTopOf="parent"
@@ -74,7 +66,7 @@
7466
android:layout_height="wrap_content"
7567
android:layout_margin="16dp"
7668
android:gravity="center"
77-
android:text="@{groupInfo.introduce}"
69+
android:text="@{viewModel.groupInfo.introduce}"
7870
app:layout_constraintEnd_toEndOf="parent"
7971
app:layout_constraintStart_toStartOf="parent"
8072
app:layout_constraintTop_toBottomOf="@id/tv_group_name"
@@ -87,7 +79,7 @@
8779
android:layout_height="wrap_content"
8880
android:layout_margin="16dp"
8981
android:gravity="center"
90-
android:text="@{groupInfo.rules.toString()}"
82+
android:text="@{viewModel.groupInfo.rules.toString()}"
9183
app:layout_constraintEnd_toEndOf="parent"
9284
app:layout_constraintStart_toStartOf="parent"
9385
app:layout_constraintTop_toBottomOf="@id/tv_group_introduce"
@@ -100,7 +92,7 @@
10092
android:layout_height="wrap_content"
10193
android:layout_margin="16dp"
10294
android:gravity="center"
103-
android:text="@{@string/text_headcount(groupInfo.headCount)}"
95+
android:text="@{@string/text_headcount(viewModel.groupInfo.headCount)}"
10496
app:layout_constraintEnd_toEndOf="parent"
10597
app:layout_constraintTop_toBottomOf="@id/tv_rules"
10698
tools:text="40명" />
@@ -112,7 +104,7 @@
112104
android:layout_height="wrap_content"
113105
android:layout_margin="16dp"
114106
android:gravity="center"
115-
android:text="@{groupInfo.leader.name}"
107+
android:text="@{viewModel.groupInfo.leader.name}"
116108
app:layout_constraintStart_toStartOf="parent"
117109
app:layout_constraintTop_toBottomOf="@id/tv_rules"
118110
tools:text="수피치" />
@@ -124,7 +116,7 @@
124116
android:layout_margin="16dp"
125117
android:text="@string/text_recruit"
126118
android:onClick="@{() -> viewModel.onRecruitButtonClicked()}"
127-
android:visibility="@{isLeader ? View.VISIBLE : View.INVISIBLE}"
119+
android:visibility="@{viewModel.isLeader ? View.VISIBLE : View.INVISIBLE}"
128120
app:layout_constraintEnd_toEndOf="parent"
129121
app:layout_constraintTop_toBottomOf="@id/tv_head_count" />
130122

@@ -135,7 +127,7 @@
135127
android:layout_margin="16dp"
136128
android:text="@string/text_exit_group"
137129
android:onClick="@{() -> viewModel.onExitGroupButtonClicked()}"
138-
android:visibility="@{isLeader ? View.GONE : View.VISIBLE}"
130+
android:visibility="@{viewModel.isLeader ? View.GONE : View.VISIBLE}"
139131
app:layout_constraintEnd_toEndOf="parent"
140132
app:layout_constraintTop_toBottomOf="@id/tv_head_count" />
141133

0 commit comments

Comments
 (0)