Skip to content

Commit

Permalink
Merge pull request #40 from Ruang-Opini/38-another-popular
Browse files Browse the repository at this point in the history
38 another popular
  • Loading branch information
derysudrajat authored Jun 9, 2021
2 parents 2debf37 + 156bb09 commit ea616f3
Show file tree
Hide file tree
Showing 17 changed files with 517 additions and 35 deletions.
33 changes: 33 additions & 0 deletions app/src/main/java/id/ruangopini/data/model/Analytics.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package id.ruangopini.data.model

import com.google.firebase.Timestamp
import com.google.firebase.firestore.DocumentId
import id.ruangopini.utils.Helpers

data class CategoryAnalytics(
val name: String? = null,
var discussion: Int? = 0,
var join: Int? = 0,
)

data class DiscussionAnalytics(
val join: Int? = 0,
val comment: Int? = 0,
val post: Int? = 0,
@DocumentId
val discussionId: String? = null
)

data class PostAnalytics(
val voteUp: Int? = 0,
val voteDown: Int? = 0,
val comment: Int? = 0,
@DocumentId
val postId: String? = null,
)

data class Analytics(
val createdAt: Timestamp? = Helpers.getTodayTime(),
@DocumentId
val time: String? = null
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package id.ruangopini.data.repo.remote.firebase.firestore.analytics

import id.ruangopini.data.model.CategoryAnalytics
import id.ruangopini.data.repo.State
import kotlinx.coroutines.flow.Flow

interface FirestoreAnalyticsDataStore {
fun updateDiscussion(category: String): Flow<State<Boolean>>
fun updateJoinCategory(category: String, isJoin: Boolean): Flow<State<Boolean>>

fun getAnotherPopular(): Flow<State<List<CategoryAnalytics>>>

fun updateJoinDiscussion(discussionId: String, isJoin: Boolean): Flow<State<Boolean>>
fun updateCommentDiscussion(discussionId: String): Flow<State<Boolean>>
fun updatePostDiscussion(discussionId: String): Flow<State<Boolean>>

fun updateCommentPost(postId: String): Flow<State<Boolean>>
fun updateVoteUpPost(postId: String, vote: Int): Flow<State<Boolean>>
fun updateVoteDownPost(postId: String, vote: Int): Flow<State<Boolean>>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
package id.ruangopini.data.repo.remote.firebase.firestore.analytics

import android.util.Log
import com.google.firebase.Timestamp
import com.google.firebase.firestore.FieldValue
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import id.ruangopini.data.model.Analytics
import id.ruangopini.data.model.CategoryAnalytics
import id.ruangopini.data.model.DiscussionAnalytics
import id.ruangopini.data.model.PostAnalytics
import id.ruangopini.data.repo.State
import id.ruangopini.utils.COLLECTION
import id.ruangopini.utils.DateFormat
import id.ruangopini.utils.Helpers
import id.ruangopini.utils.Helpers.formatDate
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.tasks.await

@ExperimentalCoroutinesApi
class FirestoreAnalyticsRepository : FirestoreAnalyticsDataStore {

private val instance = Firebase.firestore.collection(COLLECTION.ANALYTICS)

override fun updateDiscussion(category: String): Flow<State<Boolean>> = flow<State<Boolean>> {
emit(State.loading())
val date = Timestamp.now().formatDate(DateFormat.SHORT)
val snapshot = instance.document(date ?: "").collection(COLLECTION.CATEGORY)
.document(category).update("discussion", FieldValue.increment(1))
snapshot.await()
emit(State.success(snapshot.isSuccessful))
}.catch {
emit(State.loading())
val mCategory = CategoryAnalytics(category, 1, 0)

val date = Timestamp.now().formatDate(DateFormat.SHORT)
val docSnap = instance.document(date ?: "")
docSnap.set(Analytics()).await()

val snapshot = docSnap.collection(COLLECTION.CATEGORY)
.document(category).set(mCategory)
snapshot.await()

if (snapshot.isSuccessful) emit(State.success(true))
else {
Log.d("TAG", "updateDiscussion: failed = ${it.message}")
emit(State.failed(it.message ?: ""))
}
}.flowOn(Dispatchers.IO)

override fun updateJoinCategory(category: String, isJoin: Boolean) = flow<State<Boolean>> {
emit(State.loading())
val date = Timestamp.now().formatDate(DateFormat.SHORT)
val snapshot = instance.document(date ?: "").collection(COLLECTION.CATEGORY)
.document(category).update("join", FieldValue.increment(if (isJoin) 1 else -1))
snapshot.await()
emit(State.success(snapshot.isSuccessful))
}.catch {
emit(State.loading())
val mCategory = CategoryAnalytics(category, 0, 1)

val date = Timestamp.now().formatDate(DateFormat.SHORT)
val docSnap = instance.document(date ?: "")
docSnap.set(Analytics()).await()

val snapshot = docSnap.collection(COLLECTION.CATEGORY)
.document(category).set(mCategory)
snapshot.await()

if (snapshot.isSuccessful) emit(State.success(true))
else {
Log.d("TAG", "updateJoinCategory: failed = ${it.message}")
emit(State.failed(it.message ?: ""))
}
}.flowOn(Dispatchers.IO)

override fun getAnotherPopular() = callbackFlow<State<List<CategoryAnalytics>>> {
trySend(State.loading()).isSuccess
instance.whereLessThan("createdAt", Timestamp.now())
.whereGreaterThan("createdAt", Helpers.getSevenDayAgo())
.addSnapshotListener { value, error ->
if (error != null) {
trySend(State.failed(error.message ?: "")).isSuccess
close(error)
return@addSnapshotListener
}
if (value != null && !value.isEmpty) value.toObjects(Analytics::class.java)
.forEach { data ->
instance.document(data.time ?: "").collection(COLLECTION.CATEGORY)
.addSnapshotListener { result, error ->
if (error != null) {
trySend(State.failed(error.message ?: "")).isSuccess
close(error)
}

val category = if (result != null && !result.isEmpty)
result.toObjects(CategoryAnalytics::class.java)
else emptyList()

trySend(State.success(category)).isSuccess
}
}
}
awaitClose()
}.catch {
emit(State.failed(it.message ?: ""))
}.flowOn(Dispatchers.IO)

override fun updatePostDiscussion(discussionId: String) = flow<State<Boolean>> {
emit(State.loading())
val date = Timestamp.now().formatDate(DateFormat.SHORT)
val snapshot = instance.document(date ?: "").collection(COLLECTION.DISCUSSION)
.document(discussionId).update("post", FieldValue.increment(1))
snapshot.await()
emit(State.success(snapshot.isSuccessful))
}.catch {
emit(State.loading())
val discussion = DiscussionAnalytics(0, 0, 1)

val date = Timestamp.now().formatDate(DateFormat.SHORT)
val docSnap = instance.document(date ?: "")
docSnap.set(Analytics()).await()

val snapshot = docSnap.collection(COLLECTION.DISCUSSION)
.document(discussionId).set(discussion)
snapshot.await()

if (snapshot.isSuccessful) emit(State.success(true))
else {
Log.d("TAG", "updatePostDiscussion: failed = ${it.message}")
emit(State.failed(it.message ?: ""))
}
}.flowOn(Dispatchers.IO)

override fun updateJoinDiscussion(discussionId: String, isJoin: Boolean) =
flow<State<Boolean>> {
emit(State.loading())
val date = Timestamp.now().formatDate(DateFormat.SHORT)
val snapshot = instance.document(date ?: "").collection(COLLECTION.DISCUSSION)
.document(discussionId).update("join", FieldValue.increment(if (isJoin) 1 else -1))
snapshot.await()
emit(State.success(snapshot.isSuccessful))
}.catch {
emit(State.loading())
val discussion = DiscussionAnalytics(1, 0, 0)

val date = Timestamp.now().formatDate(DateFormat.SHORT)
val docSnap = instance.document(date ?: "")
docSnap.set(Analytics()).await()

val snapshot = docSnap.collection(COLLECTION.DISCUSSION)
.document(discussionId).set(discussion)
snapshot.await()

if (snapshot.isSuccessful) emit(State.success(true))
else {
Log.d("TAG", "updateJoinDiscussion: failed = ${it.message}")
emit(State.failed(it.message ?: ""))
}
}.flowOn(Dispatchers.IO)

override fun updateCommentDiscussion(discussionId: String) = flow<State<Boolean>> {
emit(State.loading())
val date = Timestamp.now().formatDate(DateFormat.SHORT)
val snapshot = instance.document(date ?: "").collection(COLLECTION.DISCUSSION)
.document(discussionId).update("comment", FieldValue.increment(1))
snapshot.await()
emit(State.success(snapshot.isSuccessful))
}.catch {
emit(State.loading())
val discussion = DiscussionAnalytics(0, 1, 0)

val date = Timestamp.now().formatDate(DateFormat.SHORT)
val docSnap = instance.document(date ?: "")
docSnap.set(Analytics()).await()

val snapshot = docSnap.collection(COLLECTION.DISCUSSION)
.document(discussionId).set(discussion)
snapshot.await()

if (snapshot.isSuccessful) emit(State.success(true))
else {
Log.d("TAG", "updateCommentDiscussion: failed = ${it.message}")
emit(State.failed(it.message ?: ""))
}
}.flowOn(Dispatchers.IO)

override fun updateCommentPost(postId: String) = flow<State<Boolean>> {
emit(State.loading())
val date = Timestamp.now().formatDate(DateFormat.SHORT)
val snapshot = instance.document(date ?: "").collection(COLLECTION.POST)
.document(postId).update("comment", FieldValue.increment(1))
snapshot.await()
emit(State.success(snapshot.isSuccessful))
}.catch {
emit(State.loading())
val post = PostAnalytics(0, 0, 1)

val date = Timestamp.now().formatDate(DateFormat.SHORT)
val docSnap = instance.document(date ?: "")
docSnap.set(Analytics()).await()

val snapshot = docSnap.collection(COLLECTION.POST)
.document(postId).set(post)
snapshot.await()
if (snapshot.isSuccessful) emit(State.success(true))
else {
Log.d("TAG", "updateCommentPost: failed = ${it.message}")
emit(State.failed(it.message ?: ""))
}
}.flowOn(Dispatchers.IO)

override fun updateVoteUpPost(postId: String, vote: Int) = flow<State<Boolean>> {
emit(State.loading())
val date = Timestamp.now().formatDate(DateFormat.SHORT)
val snapshot = instance.document(date ?: "").collection(COLLECTION.POST)
.document(postId).update("voteUp", FieldValue.increment(vote.toLong()))
snapshot.await()
emit(State.success(snapshot.isSuccessful))
}.catch {
emit(State.loading())
val post = PostAnalytics(1, 0, 0)

val date = Timestamp.now().formatDate(DateFormat.SHORT)
val docSnap = instance.document(date ?: "")
docSnap.set(Analytics()).await()

val snapshot = docSnap.collection(COLLECTION.POST)
.document(postId).set(post)
snapshot.await()
if (snapshot.isSuccessful) emit(State.success(true))
else {
Log.d("TAG", "updateVoteUpPost: failed = ${it.message}")
emit(State.failed(it.message ?: ""))
}
}.flowOn(Dispatchers.IO)

override fun updateVoteDownPost(postId: String, vote: Int) = flow<State<Boolean>> {
emit(State.loading())
val date = Timestamp.now().formatDate(DateFormat.SHORT)
val snapshot = instance.document(date ?: "").collection(COLLECTION.POST)
.document(postId).update("voteDown", FieldValue.increment(vote.toLong()))
snapshot.await()
emit(State.success(snapshot.isSuccessful))
}.catch {
emit(State.loading())
val post = PostAnalytics(0, 1, 0)

val date = Timestamp.now().formatDate(DateFormat.SHORT)
val docSnap = instance.document(date ?: "")
docSnap.set(Analytics()).await()

val snapshot = docSnap.collection(COLLECTION.POST)
.document(postId).set(post)
snapshot.await()
if (snapshot.isSuccessful) emit(State.success(true))
else {
Log.d("TAG", "updateVoteDownPost: failed = ${it.message}")
emit(State.failed(it.message ?: ""))
}
}.flowOn(Dispatchers.IO)
}
14 changes: 8 additions & 6 deletions app/src/main/java/id/ruangopini/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import id.ruangopini.data.repo.IMainRepository
import id.ruangopini.data.repo.MainRepository
import id.ruangopini.data.repo.RemoteDataSource
import id.ruangopini.data.repo.remote.firebase.auth.AuthRepository
import id.ruangopini.data.repo.remote.firebase.firestore.analytics.FirestoreAnalyticsRepository
import id.ruangopini.data.repo.remote.firebase.firestore.comment.FirestoreCommentRepository
import id.ruangopini.data.repo.remote.firebase.firestore.discussion.FirestoreDiscussionRepository
import id.ruangopini.data.repo.remote.firebase.firestore.help.FirestoreHelpRepository
Expand Down Expand Up @@ -104,6 +105,7 @@ val useCaseModule = module {
single { FirestorePostRepository() }
single { FirestoreCommentRepository() }
single { FirestoreHelpRepository() }
single { FirestoreAnalyticsRepository() }
}

val viewModelModule = module {
Expand All @@ -115,12 +117,12 @@ val viewModelModule = module {
viewModel { ChangePasswordViewModel(get()) }
viewModel { ProfileViewModel(get(), get()) }
viewModel { LoginViewModel(get(), get()) }
viewModel { CreateDiscussionViewModel(get(), get()) }
viewModel { HomeViewModel(get(), get()) }
viewModel { CreatePostViewModel(get(), get(), get()) }
viewModel { PostViewModel(get()) }
viewModel { DetailPostViewModel(get(), get()) }
viewModel { DetailDiscussionViewModel(get()) }
viewModel { CreateDiscussionViewModel(get(), get(), get()) }
viewModel { HomeViewModel(get(), get(), get()) }
viewModel { CreatePostViewModel(get(), get(), get(), get()) }
viewModel { PostViewModel(get(), get()) }
viewModel { DetailPostViewModel(get(), get(), get()) }
viewModel { DetailDiscussionViewModel(get(), get()) }
viewModel { DetailTrendingPolicyViewModel(get()) }
viewModel { EditProfileViewModel(get(), get()) }
viewModel { HelpViewModel(get()) }
Expand Down
12 changes: 8 additions & 4 deletions app/src/main/java/id/ruangopini/ui/base/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,18 @@ class HomeFragment : Fragment() {
}

model.getTrending()
model.getAnotherPopular()

trending = TrendingAdapter(requireContext())
anotherPop = TrendingCategoryAdapter(
requireContext(),
listOf("Korupsi", "Medis", "Transportasi", "BUMN")
)
anotherPop = TrendingCategoryAdapter(requireContext())
concatAdapter = ConcatAdapter(header, trending, headerTwo, anotherPop)
updateAdapter()

model.category.observe(viewLifecycleOwner, {
Log.d("TAG", "trending-another: $it")
anotherPop.addAll(it)
})

model.trending.observe(viewLifecycleOwner, {
Log.d("TAG", "trending-twit: $it")
trending.addAll(it)
Expand Down
Loading

0 comments on commit ea616f3

Please sign in to comment.