Skip to content

Commit ea616f3

Browse files
authored
Merge pull request #40 from Ruang-Opini/38-another-popular
38 another popular
2 parents 2debf37 + 156bb09 commit ea616f3

File tree

17 files changed

+517
-35
lines changed

17 files changed

+517
-35
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package id.ruangopini.data.model
2+
3+
import com.google.firebase.Timestamp
4+
import com.google.firebase.firestore.DocumentId
5+
import id.ruangopini.utils.Helpers
6+
7+
data class CategoryAnalytics(
8+
val name: String? = null,
9+
var discussion: Int? = 0,
10+
var join: Int? = 0,
11+
)
12+
13+
data class DiscussionAnalytics(
14+
val join: Int? = 0,
15+
val comment: Int? = 0,
16+
val post: Int? = 0,
17+
@DocumentId
18+
val discussionId: String? = null
19+
)
20+
21+
data class PostAnalytics(
22+
val voteUp: Int? = 0,
23+
val voteDown: Int? = 0,
24+
val comment: Int? = 0,
25+
@DocumentId
26+
val postId: String? = null,
27+
)
28+
29+
data class Analytics(
30+
val createdAt: Timestamp? = Helpers.getTodayTime(),
31+
@DocumentId
32+
val time: String? = null
33+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package id.ruangopini.data.repo.remote.firebase.firestore.analytics
2+
3+
import id.ruangopini.data.model.CategoryAnalytics
4+
import id.ruangopini.data.repo.State
5+
import kotlinx.coroutines.flow.Flow
6+
7+
interface FirestoreAnalyticsDataStore {
8+
fun updateDiscussion(category: String): Flow<State<Boolean>>
9+
fun updateJoinCategory(category: String, isJoin: Boolean): Flow<State<Boolean>>
10+
11+
fun getAnotherPopular(): Flow<State<List<CategoryAnalytics>>>
12+
13+
fun updateJoinDiscussion(discussionId: String, isJoin: Boolean): Flow<State<Boolean>>
14+
fun updateCommentDiscussion(discussionId: String): Flow<State<Boolean>>
15+
fun updatePostDiscussion(discussionId: String): Flow<State<Boolean>>
16+
17+
fun updateCommentPost(postId: String): Flow<State<Boolean>>
18+
fun updateVoteUpPost(postId: String, vote: Int): Flow<State<Boolean>>
19+
fun updateVoteDownPost(postId: String, vote: Int): Flow<State<Boolean>>
20+
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
package id.ruangopini.data.repo.remote.firebase.firestore.analytics
2+
3+
import android.util.Log
4+
import com.google.firebase.Timestamp
5+
import com.google.firebase.firestore.FieldValue
6+
import com.google.firebase.firestore.ktx.firestore
7+
import com.google.firebase.ktx.Firebase
8+
import id.ruangopini.data.model.Analytics
9+
import id.ruangopini.data.model.CategoryAnalytics
10+
import id.ruangopini.data.model.DiscussionAnalytics
11+
import id.ruangopini.data.model.PostAnalytics
12+
import id.ruangopini.data.repo.State
13+
import id.ruangopini.utils.COLLECTION
14+
import id.ruangopini.utils.DateFormat
15+
import id.ruangopini.utils.Helpers
16+
import id.ruangopini.utils.Helpers.formatDate
17+
import kotlinx.coroutines.Dispatchers
18+
import kotlinx.coroutines.ExperimentalCoroutinesApi
19+
import kotlinx.coroutines.channels.awaitClose
20+
import kotlinx.coroutines.flow.*
21+
import kotlinx.coroutines.tasks.await
22+
23+
@ExperimentalCoroutinesApi
24+
class FirestoreAnalyticsRepository : FirestoreAnalyticsDataStore {
25+
26+
private val instance = Firebase.firestore.collection(COLLECTION.ANALYTICS)
27+
28+
override fun updateDiscussion(category: String): Flow<State<Boolean>> = flow<State<Boolean>> {
29+
emit(State.loading())
30+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
31+
val snapshot = instance.document(date ?: "").collection(COLLECTION.CATEGORY)
32+
.document(category).update("discussion", FieldValue.increment(1))
33+
snapshot.await()
34+
emit(State.success(snapshot.isSuccessful))
35+
}.catch {
36+
emit(State.loading())
37+
val mCategory = CategoryAnalytics(category, 1, 0)
38+
39+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
40+
val docSnap = instance.document(date ?: "")
41+
docSnap.set(Analytics()).await()
42+
43+
val snapshot = docSnap.collection(COLLECTION.CATEGORY)
44+
.document(category).set(mCategory)
45+
snapshot.await()
46+
47+
if (snapshot.isSuccessful) emit(State.success(true))
48+
else {
49+
Log.d("TAG", "updateDiscussion: failed = ${it.message}")
50+
emit(State.failed(it.message ?: ""))
51+
}
52+
}.flowOn(Dispatchers.IO)
53+
54+
override fun updateJoinCategory(category: String, isJoin: Boolean) = flow<State<Boolean>> {
55+
emit(State.loading())
56+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
57+
val snapshot = instance.document(date ?: "").collection(COLLECTION.CATEGORY)
58+
.document(category).update("join", FieldValue.increment(if (isJoin) 1 else -1))
59+
snapshot.await()
60+
emit(State.success(snapshot.isSuccessful))
61+
}.catch {
62+
emit(State.loading())
63+
val mCategory = CategoryAnalytics(category, 0, 1)
64+
65+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
66+
val docSnap = instance.document(date ?: "")
67+
docSnap.set(Analytics()).await()
68+
69+
val snapshot = docSnap.collection(COLLECTION.CATEGORY)
70+
.document(category).set(mCategory)
71+
snapshot.await()
72+
73+
if (snapshot.isSuccessful) emit(State.success(true))
74+
else {
75+
Log.d("TAG", "updateJoinCategory: failed = ${it.message}")
76+
emit(State.failed(it.message ?: ""))
77+
}
78+
}.flowOn(Dispatchers.IO)
79+
80+
override fun getAnotherPopular() = callbackFlow<State<List<CategoryAnalytics>>> {
81+
trySend(State.loading()).isSuccess
82+
instance.whereLessThan("createdAt", Timestamp.now())
83+
.whereGreaterThan("createdAt", Helpers.getSevenDayAgo())
84+
.addSnapshotListener { value, error ->
85+
if (error != null) {
86+
trySend(State.failed(error.message ?: "")).isSuccess
87+
close(error)
88+
return@addSnapshotListener
89+
}
90+
if (value != null && !value.isEmpty) value.toObjects(Analytics::class.java)
91+
.forEach { data ->
92+
instance.document(data.time ?: "").collection(COLLECTION.CATEGORY)
93+
.addSnapshotListener { result, error ->
94+
if (error != null) {
95+
trySend(State.failed(error.message ?: "")).isSuccess
96+
close(error)
97+
}
98+
99+
val category = if (result != null && !result.isEmpty)
100+
result.toObjects(CategoryAnalytics::class.java)
101+
else emptyList()
102+
103+
trySend(State.success(category)).isSuccess
104+
}
105+
}
106+
}
107+
awaitClose()
108+
}.catch {
109+
emit(State.failed(it.message ?: ""))
110+
}.flowOn(Dispatchers.IO)
111+
112+
override fun updatePostDiscussion(discussionId: String) = flow<State<Boolean>> {
113+
emit(State.loading())
114+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
115+
val snapshot = instance.document(date ?: "").collection(COLLECTION.DISCUSSION)
116+
.document(discussionId).update("post", FieldValue.increment(1))
117+
snapshot.await()
118+
emit(State.success(snapshot.isSuccessful))
119+
}.catch {
120+
emit(State.loading())
121+
val discussion = DiscussionAnalytics(0, 0, 1)
122+
123+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
124+
val docSnap = instance.document(date ?: "")
125+
docSnap.set(Analytics()).await()
126+
127+
val snapshot = docSnap.collection(COLLECTION.DISCUSSION)
128+
.document(discussionId).set(discussion)
129+
snapshot.await()
130+
131+
if (snapshot.isSuccessful) emit(State.success(true))
132+
else {
133+
Log.d("TAG", "updatePostDiscussion: failed = ${it.message}")
134+
emit(State.failed(it.message ?: ""))
135+
}
136+
}.flowOn(Dispatchers.IO)
137+
138+
override fun updateJoinDiscussion(discussionId: String, isJoin: Boolean) =
139+
flow<State<Boolean>> {
140+
emit(State.loading())
141+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
142+
val snapshot = instance.document(date ?: "").collection(COLLECTION.DISCUSSION)
143+
.document(discussionId).update("join", FieldValue.increment(if (isJoin) 1 else -1))
144+
snapshot.await()
145+
emit(State.success(snapshot.isSuccessful))
146+
}.catch {
147+
emit(State.loading())
148+
val discussion = DiscussionAnalytics(1, 0, 0)
149+
150+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
151+
val docSnap = instance.document(date ?: "")
152+
docSnap.set(Analytics()).await()
153+
154+
val snapshot = docSnap.collection(COLLECTION.DISCUSSION)
155+
.document(discussionId).set(discussion)
156+
snapshot.await()
157+
158+
if (snapshot.isSuccessful) emit(State.success(true))
159+
else {
160+
Log.d("TAG", "updateJoinDiscussion: failed = ${it.message}")
161+
emit(State.failed(it.message ?: ""))
162+
}
163+
}.flowOn(Dispatchers.IO)
164+
165+
override fun updateCommentDiscussion(discussionId: String) = flow<State<Boolean>> {
166+
emit(State.loading())
167+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
168+
val snapshot = instance.document(date ?: "").collection(COLLECTION.DISCUSSION)
169+
.document(discussionId).update("comment", FieldValue.increment(1))
170+
snapshot.await()
171+
emit(State.success(snapshot.isSuccessful))
172+
}.catch {
173+
emit(State.loading())
174+
val discussion = DiscussionAnalytics(0, 1, 0)
175+
176+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
177+
val docSnap = instance.document(date ?: "")
178+
docSnap.set(Analytics()).await()
179+
180+
val snapshot = docSnap.collection(COLLECTION.DISCUSSION)
181+
.document(discussionId).set(discussion)
182+
snapshot.await()
183+
184+
if (snapshot.isSuccessful) emit(State.success(true))
185+
else {
186+
Log.d("TAG", "updateCommentDiscussion: failed = ${it.message}")
187+
emit(State.failed(it.message ?: ""))
188+
}
189+
}.flowOn(Dispatchers.IO)
190+
191+
override fun updateCommentPost(postId: String) = flow<State<Boolean>> {
192+
emit(State.loading())
193+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
194+
val snapshot = instance.document(date ?: "").collection(COLLECTION.POST)
195+
.document(postId).update("comment", FieldValue.increment(1))
196+
snapshot.await()
197+
emit(State.success(snapshot.isSuccessful))
198+
}.catch {
199+
emit(State.loading())
200+
val post = PostAnalytics(0, 0, 1)
201+
202+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
203+
val docSnap = instance.document(date ?: "")
204+
docSnap.set(Analytics()).await()
205+
206+
val snapshot = docSnap.collection(COLLECTION.POST)
207+
.document(postId).set(post)
208+
snapshot.await()
209+
if (snapshot.isSuccessful) emit(State.success(true))
210+
else {
211+
Log.d("TAG", "updateCommentPost: failed = ${it.message}")
212+
emit(State.failed(it.message ?: ""))
213+
}
214+
}.flowOn(Dispatchers.IO)
215+
216+
override fun updateVoteUpPost(postId: String, vote: Int) = flow<State<Boolean>> {
217+
emit(State.loading())
218+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
219+
val snapshot = instance.document(date ?: "").collection(COLLECTION.POST)
220+
.document(postId).update("voteUp", FieldValue.increment(vote.toLong()))
221+
snapshot.await()
222+
emit(State.success(snapshot.isSuccessful))
223+
}.catch {
224+
emit(State.loading())
225+
val post = PostAnalytics(1, 0, 0)
226+
227+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
228+
val docSnap = instance.document(date ?: "")
229+
docSnap.set(Analytics()).await()
230+
231+
val snapshot = docSnap.collection(COLLECTION.POST)
232+
.document(postId).set(post)
233+
snapshot.await()
234+
if (snapshot.isSuccessful) emit(State.success(true))
235+
else {
236+
Log.d("TAG", "updateVoteUpPost: failed = ${it.message}")
237+
emit(State.failed(it.message ?: ""))
238+
}
239+
}.flowOn(Dispatchers.IO)
240+
241+
override fun updateVoteDownPost(postId: String, vote: Int) = flow<State<Boolean>> {
242+
emit(State.loading())
243+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
244+
val snapshot = instance.document(date ?: "").collection(COLLECTION.POST)
245+
.document(postId).update("voteDown", FieldValue.increment(vote.toLong()))
246+
snapshot.await()
247+
emit(State.success(snapshot.isSuccessful))
248+
}.catch {
249+
emit(State.loading())
250+
val post = PostAnalytics(0, 1, 0)
251+
252+
val date = Timestamp.now().formatDate(DateFormat.SHORT)
253+
val docSnap = instance.document(date ?: "")
254+
docSnap.set(Analytics()).await()
255+
256+
val snapshot = docSnap.collection(COLLECTION.POST)
257+
.document(postId).set(post)
258+
snapshot.await()
259+
if (snapshot.isSuccessful) emit(State.success(true))
260+
else {
261+
Log.d("TAG", "updateVoteDownPost: failed = ${it.message}")
262+
emit(State.failed(it.message ?: ""))
263+
}
264+
}.flowOn(Dispatchers.IO)
265+
}

app/src/main/java/id/ruangopini/di/AppModule.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import id.ruangopini.data.repo.IMainRepository
44
import id.ruangopini.data.repo.MainRepository
55
import id.ruangopini.data.repo.RemoteDataSource
66
import id.ruangopini.data.repo.remote.firebase.auth.AuthRepository
7+
import id.ruangopini.data.repo.remote.firebase.firestore.analytics.FirestoreAnalyticsRepository
78
import id.ruangopini.data.repo.remote.firebase.firestore.comment.FirestoreCommentRepository
89
import id.ruangopini.data.repo.remote.firebase.firestore.discussion.FirestoreDiscussionRepository
910
import id.ruangopini.data.repo.remote.firebase.firestore.help.FirestoreHelpRepository
@@ -104,6 +105,7 @@ val useCaseModule = module {
104105
single { FirestorePostRepository() }
105106
single { FirestoreCommentRepository() }
106107
single { FirestoreHelpRepository() }
108+
single { FirestoreAnalyticsRepository() }
107109
}
108110

109111
val viewModelModule = module {
@@ -115,12 +117,12 @@ val viewModelModule = module {
115117
viewModel { ChangePasswordViewModel(get()) }
116118
viewModel { ProfileViewModel(get(), get()) }
117119
viewModel { LoginViewModel(get(), get()) }
118-
viewModel { CreateDiscussionViewModel(get(), get()) }
119-
viewModel { HomeViewModel(get(), get()) }
120-
viewModel { CreatePostViewModel(get(), get(), get()) }
121-
viewModel { PostViewModel(get()) }
122-
viewModel { DetailPostViewModel(get(), get()) }
123-
viewModel { DetailDiscussionViewModel(get()) }
120+
viewModel { CreateDiscussionViewModel(get(), get(), get()) }
121+
viewModel { HomeViewModel(get(), get(), get()) }
122+
viewModel { CreatePostViewModel(get(), get(), get(), get()) }
123+
viewModel { PostViewModel(get(), get()) }
124+
viewModel { DetailPostViewModel(get(), get(), get()) }
125+
viewModel { DetailDiscussionViewModel(get(), get()) }
124126
viewModel { DetailTrendingPolicyViewModel(get()) }
125127
viewModel { EditProfileViewModel(get(), get()) }
126128
viewModel { HelpViewModel(get()) }

app/src/main/java/id/ruangopini/ui/base/home/HomeFragment.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,18 @@ class HomeFragment : Fragment() {
4949
}
5050

5151
model.getTrending()
52+
model.getAnotherPopular()
53+
5254
trending = TrendingAdapter(requireContext())
53-
anotherPop = TrendingCategoryAdapter(
54-
requireContext(),
55-
listOf("Korupsi", "Medis", "Transportasi", "BUMN")
56-
)
55+
anotherPop = TrendingCategoryAdapter(requireContext())
5756
concatAdapter = ConcatAdapter(header, trending, headerTwo, anotherPop)
5857
updateAdapter()
5958

59+
model.category.observe(viewLifecycleOwner, {
60+
Log.d("TAG", "trending-another: $it")
61+
anotherPop.addAll(it)
62+
})
63+
6064
model.trending.observe(viewLifecycleOwner, {
6165
Log.d("TAG", "trending-twit: $it")
6266
trending.addAll(it)

0 commit comments

Comments
 (0)