Skip to content

Commit

Permalink
NT-1943: UI/UX – Empty state (#1258)
Browse files Browse the repository at this point in the history
* refactored commentsviewmodel and test

* removed wild card imports

* fixed lint errors

* refactored viewmodel

Co-authored-by: Sunday Onoriode <sunday-onoriode@Sunday-Onoriode-MacBook-Pro.local>
Co-authored-by: Isabel Martin <arkariang@gmail.com>
  • Loading branch information
3 people committed May 25, 2021
1 parent 0615810 commit 0ce20f9
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 43 deletions.
@@ -0,0 +1,24 @@
package com.kickstarter.mock.factories

import com.kickstarter.services.apiresponses.commentresponse.CommentEnvelope

class CommentEnvelopeFactory {

companion object {
fun emptyCommentsEnvelope(): CommentEnvelope {
return CommentEnvelope.builder()
.totalCount(0)
.comments(listOf())
.pageInfoEnvelope(null)
.build()
}

fun commentsEnvelope(): CommentEnvelope {
return CommentEnvelope.builder()
.totalCount(1)
.comments(listOf(CommentFactory.comment()))
.pageInfoEnvelope(PageInfoEnvelopeFactory.pageInfoEnvelope())
.build()
}
}
}
@@ -0,0 +1,15 @@
package com.kickstarter.mock.factories

import com.kickstarter.services.apiresponses.commentresponse.PageInfoEnvelope

class PageInfoEnvelopeFactory {

companion object {
fun pageInfoEnvelope(): PageInfoEnvelope {
return PageInfoEnvelope.builder()
.endCursor("WzMyNDk1MzMzXQ==")
.startCursor("WzMyNDk1MzMzXQ==")
.build()
}
}
}
Expand Up @@ -12,6 +12,7 @@ import com.kickstarter.mock.factories.CheckoutFactory
import com.kickstarter.mock.factories.CommentFactory
import com.kickstarter.mock.factories.CreatorDetailsFactory
import com.kickstarter.mock.factories.ErroredBackingFactory
import com.kickstarter.mock.factories.PageInfoEnvelopeFactory
import com.kickstarter.mock.factories.RewardFactory
import com.kickstarter.mock.factories.StoredCardFactory
import com.kickstarter.models.Backing
Expand All @@ -26,7 +27,6 @@ import com.kickstarter.models.StoredCard
import com.kickstarter.models.User
import com.kickstarter.services.ApolloClientType
import com.kickstarter.services.apiresponses.commentresponse.CommentEnvelope
import com.kickstarter.services.apiresponses.commentresponse.PageInfoEnvelope
import com.kickstarter.services.mutations.CreateBackingData
import com.kickstarter.services.mutations.PostCommentData
import com.kickstarter.services.mutations.SavePaymentMethodData
Expand Down Expand Up @@ -62,10 +62,7 @@ open class MockApolloClient : ApolloClientType {
return Observable.just(
CommentEnvelope.builder()
.pageInfoEnvelope(
PageInfoEnvelope.builder()
.endCursor("WzMyNDk1MzMzXQ==")
.startCursor("WzMyNDk1MzMzXQ==")
.build()
PageInfoEnvelopeFactory.pageInfoEnvelope()
)
.comments(listOf(CommentFactory.comment()))
.totalCount(1)
Expand Down
Expand Up @@ -53,12 +53,30 @@ class CommentsActivity :
binding.commentComposer.isVisible = true
}

viewModel.outputs.setEmptyState()
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::setEmptyState)

binding.commentComposer.setCommentComposerActionClickListener(object : OnCommentComposerViewClickedListener {
override fun onClickActionListener(string: String) {
}
})
}

fun setEmptyState(visibility: Boolean) {
val d = visibility
binding.commentsSwipeRefreshLayout.visibility = when (visibility) {
true -> View.GONE
else -> View.VISIBLE
}

binding.noComments.visibility = when (visibility) {
true -> View.VISIBLE
else -> View.GONE
}
}

override fun emptyCommentsLoginClicked(viewHolder: EmptyCommentsViewHolder?) {
}

Expand Down
Expand Up @@ -29,6 +29,7 @@ interface CommentsViewModel {
fun enableCommentComposer(): Observable<Boolean>
fun showCommentComposer(): Observable<Void>
fun commentsList(): Observable<List<Comment>>
fun setEmptyState(): Observable<Boolean>
}

class ViewModel(@NonNull val environment: Environment) : ActivityViewModel<CommentsActivity>(environment), Inputs, Outputs {
Expand All @@ -44,6 +45,8 @@ interface CommentsViewModel {
private val showCommentComposer = BehaviorSubject.create<Void>()
private val commentsList = BehaviorSubject.create<List<Comment>?>()

private val setEmptyState = BehaviorSubject.create<Boolean>()

init {

val loggedInUser = this.currentUser.loggedInUser()
Expand Down Expand Up @@ -112,11 +115,13 @@ interface CommentsViewModel {
.share()

commentEnvelope
.map { it.comments }
.filter { ObjectUtils.isNotNull(it) }
.compose(bindToLifecycle())
.subscribe {
commentsList.onNext(it)
it.totalCount?.let { count ->
this.setEmptyState.onNext(count < 1)
commentsList.onNext(it.comments)
}
}
}

Expand All @@ -127,5 +132,7 @@ interface CommentsViewModel {
override fun enableCommentComposer(): Observable<Boolean> = enableCommentComposer
override fun showCommentComposer(): Observable<Void> = showCommentComposer
override fun commentsList(): Observable<List<Comment>> = commentsList

override fun setEmptyState(): Observable<Boolean> = setEmptyState
}
}
128 changes: 92 additions & 36 deletions app/src/main/res/layout/activity_comments_layout.xml
@@ -1,44 +1,100 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:background="@color/comment_background"
tools:context="com.kickstarter.ui.activities.CommentsActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:orientation="vertical">
android:layout_height="match_parent">

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/comments_swipe_refresh_layout"
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/separtor"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
android:layout_height="wrap_content">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/comments_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/kds_white"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/comment_card" />

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

<View
android:id="@+id/separtor"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="@color/kds_support_200"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/comment_composer" />

<com.kickstarter.ui.views.CommentComposerView
android:id="@+id/comment_composer"
<com.kickstarter.ui.toolbars.KSToolbar
style="@style/Toolbar"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">

<com.kickstarter.ui.views.IconButton
android:id="@+id/back_button"
style="@style/ToolbarIconBackButton" />

<TextView
style="@style/ToolbarTitle"
android:text="@string/project_menu_buttons_comments" />
</RelativeLayout>

</com.kickstarter.ui.toolbars.KSToolbar>
</com.google.android.material.appbar.AppBarLayout>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:composer_disabled="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
android:layout_height="match_parent"
android:focusable="true"
tools:context="com.kickstarter.ui.activities.CommentsActivity"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:orientation="vertical">

<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/no_comments"
android:visibility="gone"
android:layout_marginTop="@dimen/grid_11"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="wrap_content"
android:text="@string/No_comments_yet"
style="@style/CalloutSecondary"
android:layout_height="wrap_content"/>

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/comments_swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/separtor"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/comments_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/kds_white"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/comment_card" />

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

<View
android:id="@+id/separtor"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="@color/kds_support_200"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/comment_composer" />

<com.kickstarter.ui.views.CommentComposerView
android:id="@+id/comment_composer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:composer_disabled="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>



3 changes: 3 additions & 0 deletions app/src/main/res/values/colors.xml
Expand Up @@ -76,4 +76,7 @@
<color name="facebook_blue">#1877F2</color>

<color name="retry_color">#FF5151</color>

<!-- comments -->
<color name="comment_background">#FBFBFA</color>
</resources>
Expand Up @@ -4,6 +4,7 @@ import android.content.Intent
import com.kickstarter.KSRobolectricTestCase
import com.kickstarter.libs.MockCurrentUser
import com.kickstarter.mock.factories.AvatarFactory
import com.kickstarter.mock.factories.CommentEnvelopeFactory
import com.kickstarter.mock.factories.ProjectFactory
import com.kickstarter.mock.factories.UpdateFactory
import com.kickstarter.mock.factories.UserFactory
Expand All @@ -18,6 +19,7 @@ import rx.observers.TestSubscriber
class CommentsViewModelTest : KSRobolectricTestCase() {
private val enableCommentComposer = TestSubscriber<Boolean>()
private val showCommentComposer = TestSubscriber<Void>()
private val showEmptyState = TestSubscriber<Boolean>()

@Test
fun testCommentsViewModel_showCommentComposer_isLogInUser() {
Expand Down Expand Up @@ -159,4 +161,40 @@ class CommentsViewModelTest : KSRobolectricTestCase() {
// Comments should emit.
commentsList.assertValueCount(1)
}

/*
* test when no comment available
*/
@Test
fun testCommentsViewModel_EmptyCommentState() {
val env = environment().toBuilder().apolloClient(object : MockApolloClient() {
override fun getProjectComments(slug: String, cursor: String?, limit: Int): Observable<CommentEnvelope> {
return Observable.just(CommentEnvelopeFactory.emptyCommentsEnvelope())
}
}).build()
val vm = CommentsViewModel.ViewModel(env)
vm.outputs.setEmptyState().subscribe(showEmptyState)

// Start the view model with an update.
vm.intent(Intent().putExtra(IntentKey.UPDATE, UpdateFactory.update()))
showEmptyState.assertValue(true)
}

/*
* test when comment(s) available
*/
@Test
fun testCommentsViewModel_CommentsAvailableState() {
val env = environment().toBuilder().apolloClient(object : MockApolloClient() {
override fun getProjectComments(slug: String, cursor: String?, limit: Int): Observable<CommentEnvelope> {
return Observable.just(CommentEnvelopeFactory.commentsEnvelope())
}
}).build()
val vm = CommentsViewModel.ViewModel(env)
vm.outputs.setEmptyState().subscribe(showEmptyState)

// Start the view model with an update.
vm.intent(Intent().putExtra(IntentKey.UPDATE, UpdateFactory.update()))
showEmptyState.assertValue(false)
}
}

0 comments on commit 0ce20f9

Please sign in to comment.