Skip to content

Commit

Permalink
NT-1956: Thread view and navigation (#1262)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkariang committed May 27, 2021
1 parent 49faa4d commit 4077bb5
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 3 deletions.
7 changes: 5 additions & 2 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -48,14 +48,17 @@
android:theme="@style/SettingsActivity" />
<activity
android:name=".ui.activities.CommentsActivity"
android:theme="@style/CommentsActivity" />
android:theme="@style/WhiteActivity" />
<activity
android:name=".ui.activities.ThreadActivity"
android:theme="@style/WhiteActivity" />
<activity
android:name=".ui.activities.EditProfileActivity"
android:theme="@style/SettingsActivity" />
<activity
android:name=".ui.activities.DeprecatedCommentsActivity"
android:parentActivityName=".ui.activities.ProjectActivity"
android:theme="@style/CommentsActivity" />
android:theme="@style/WhiteActivity" />
<activity android:name=".ui.activities.CreatorBioActivity" />
<activity
android:name=".ui.activities.CreatePasswordActivity"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/kickstarter/ui/IntentKey.java
Expand Up @@ -37,4 +37,6 @@ private IntentKey() {}
public static final String UPDATE = "com.kickstarter.kickstarter.intent_update";
public static final String URL = "com.kickstarter.kickstarter.intent_url";
public static final String PUSH_NOTIFICATION_ENVELOPE = "com.kickstarter.kickstarter.push_notification_envelope";
public static final String COMMENT = "com.kickstarter.kickstarter.intent_comment";
public static final String REPLY_EXPAND = "com.kickstarter.kickstarter.intent_reply_expand";
}
@@ -1,12 +1,15 @@
package com.kickstarter.ui.activities

import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.core.view.isVisible
import com.kickstarter.R
import com.kickstarter.databinding.ActivityCommentsLayoutBinding
import com.kickstarter.libs.BaseActivity
import com.kickstarter.libs.qualifiers.RequiresActivityViewModel
import com.kickstarter.models.Comment
import com.kickstarter.ui.IntentKey
import com.kickstarter.ui.adapters.CommentsAdapter
import com.kickstarter.ui.viewholders.EmptyCommentsViewHolder
import com.kickstarter.ui.views.OnCommentComposerViewClickedListener
Expand Down Expand Up @@ -104,11 +107,35 @@ class CommentsActivity :
}

override fun onReplyButtonClicked(comment: Comment) {
startThreadActivity(comment, true)
}

override fun onFlagButtonClicked(comment: Comment) {
}

override fun onCommentGuideLinesClicked(comment: Comment) {
}

/**
* Start the Thread activity with
* @param comment the selected comment to reply
* @param openKeyboard
* true: he focus needs to be on the composer view and set the keyboard open when open the activity
* false: in case we just need to open the replies screen
*
* // TODO: Once the viewReplies UI is completed call this method with openKeyboard = false
* // TODO: https://kickstarter.atlassian.net/browse/NT-1955
*/
private fun startThreadActivity(comment: Comment, openKeyboard: Boolean) {
val threadIntent = Intent(this, ThreadActivity::class.java).apply {
putExtra(IntentKey.COMMENT, comment)
putExtra(IntentKey.REPLY_EXPAND, openKeyboard)
}

startActivityWithTransition(
threadIntent,
R.anim.slide_in_right,
R.anim.fade_out_slide_out_left
)
}
}
54 changes: 54 additions & 0 deletions app/src/main/java/com/kickstarter/ui/activities/ThreadActivity.kt
@@ -0,0 +1,54 @@
package com.kickstarter.ui.activities

import android.os.Bundle
import com.kickstarter.databinding.ActivityThreadLayoutBinding
import com.kickstarter.libs.BaseActivity
import com.kickstarter.libs.KSString
import com.kickstarter.libs.qualifiers.RequiresActivityViewModel
import com.kickstarter.libs.utils.DateTimeUtils
import com.kickstarter.models.Comment
import com.kickstarter.ui.extensions.hideKeyboard
import com.kickstarter.viewmodels.ThreadViewModel
import rx.android.schedulers.AndroidSchedulers

@RequiresActivityViewModel(ThreadViewModel.ViewModel::class)
class ThreadActivity : BaseActivity<ThreadViewModel.ViewModel>() {

private lateinit var binding: ActivityThreadLayoutBinding
private lateinit var ksString: KSString

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding = ActivityThreadLayoutBinding.inflate(layoutInflater)
setContentView(binding.root)
ksString = environment().ksString()

this.viewModel.getRootComment()
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { comment ->
configureRootCommentView(comment)
}

this.viewModel.shouldFocusOnCompose()
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { shouldOpenKeyboard ->
// TODO: Once compose view is integrated we can set focus and open the keyboard
}
}

override fun onStop() {
super.onStop()
hideKeyboard()
}

private fun configureRootCommentView(comment: Comment) {
binding.commentsCardView.setCommentUserName(comment.author().name())
binding.commentsCardView.setCommentBody(comment.body())
binding.commentsCardView.setCommentPostTime(DateTimeUtils.relative(this, ksString, comment.createdAt()))
binding.commentsCardView.setCommentUserName(comment.author().name())
binding.commentsCardView.setAvatarUrl(comment.author().avatar().medium())
}
}
54 changes: 54 additions & 0 deletions app/src/main/java/com/kickstarter/viewmodels/ThreadViewModel.kt
@@ -0,0 +1,54 @@
package com.kickstarter.viewmodels

import androidx.annotation.NonNull
import com.kickstarter.libs.ActivityViewModel
import com.kickstarter.libs.CurrentUserType
import com.kickstarter.libs.Environment
import com.kickstarter.libs.utils.ObjectUtils
import com.kickstarter.models.Comment
import com.kickstarter.services.ApolloClientType
import com.kickstarter.ui.IntentKey
import com.kickstarter.ui.activities.ThreadActivity
import rx.Observable
import rx.subjects.BehaviorSubject

interface ThreadViewModel {

interface Inputs
interface Outputs {
/** The anchored root comment */
fun getRootComment(): Observable<Comment>

/** Will tell to the compose view if should open the keyboard */
fun shouldFocusOnCompose(): Observable<Boolean>
}

class ViewModel(@NonNull val environment: Environment) : ActivityViewModel<ThreadActivity>(environment), Inputs, Outputs {
private val apolloClient: ApolloClientType = environment.apolloClient()
private val currentUser: CurrentUserType = environment.currentUser()

private val rootComment = BehaviorSubject.create<Comment>()
private val focusOnCompose = BehaviorSubject.create<Boolean>()
val inputs = this
val outputs = this

init {
intent()
.map { it.getParcelableExtra(IntentKey.COMMENT) as Comment? }
.distinctUntilChanged()
.filter { ObjectUtils.isNotNull(it) }
.map { requireNotNull(it) }
.compose(bindToLifecycle())
.subscribe(this.rootComment)

intent()
.map { it.getBooleanExtra(IntentKey.REPLY_EXPAND, false) }
.distinctUntilChanged()
.compose(bindToLifecycle())
.subscribe(this.focusOnCompose)
}

override fun getRootComment(): Observable<Comment> = this.rootComment
override fun shouldFocusOnCompose(): Observable<Boolean> = this.focusOnCompose
}
}
55 changes: 55 additions & 0 deletions app/src/main/res/layout/activity_thread_layout.xml
@@ -0,0 +1,55 @@
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/root"
tools:context="com.kickstarter.ui.activities.ThreadActivity">

<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent">

<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/fpo_replies" />
</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"
android:focusable="true"
tools:context="com.kickstarter.ui.activities.ThreadActivity"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:orientation="vertical">

<com.kickstarter.ui.views.CommentCard
android:id="@+id/comments_card_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Expand Up @@ -88,4 +88,5 @@
<string name="learn_more_about_comment_guidelines">Learn more about comment guidelines</string>
<string name="failed_to_post_retry">Failed to post. Tap to retry</string>
<string name="reply">Reply</string>
<string name="fpo_replies">Replies</string>
</resources>
3 changes: 2 additions & 1 deletion app/src/main/res/values/styles.xml
Expand Up @@ -39,8 +39,9 @@
<!-- Activities -->
<style name="ActivityFeedActivity" parent="KSTheme" />

<style name="CommentsActivity" parent="KSTheme">
<style name="WhiteActivity" parent="KSTheme">
<item name="android:windowBackground">@color/kds_white</item>
<item name="android:windowContentTransitions">true</item>
</style>

<style name="DiscoveryBase" parent="KSTheme">
Expand Down
@@ -0,0 +1,55 @@
package com.kickstarter.viewmodels

import android.content.Intent
import com.kickstarter.KSRobolectricTestCase
import com.kickstarter.libs.Environment
import com.kickstarter.mock.factories.AvatarFactory
import com.kickstarter.mock.factories.CommentFactory
import com.kickstarter.models.Comment
import com.kickstarter.ui.IntentKey
import org.junit.Test
import rx.observers.TestSubscriber

class ThreadViewModelTest : KSRobolectricTestCase() {

private lateinit var vm: ThreadViewModel.ViewModel
private val getComment = TestSubscriber<Comment>()
private val focusCompose = TestSubscriber<Boolean>()

private fun setUpEnvironment() {
setUpEnvironment(environment())
}

private fun setUpEnvironment(environment: Environment) {
this.vm = ThreadViewModel.ViewModel(environment)
this.vm.getRootComment().subscribe(getComment)
this.vm.shouldFocusOnCompose().subscribe(focusCompose)
}

@Test
fun testGetRootComment() {
setUpEnvironment()

val comment = CommentFactory.comment(avatar = AvatarFactory.avatar())

this.vm.intent(Intent().putExtra(IntentKey.COMMENT, comment))
getComment.assertValue(comment)

this.vm.intent(Intent().putExtra("Some other Key", comment))
getComment.assertValue(comment)
}

@Test
fun testShouldFocusCompose() {
setUpEnvironment()

this.vm.intent(Intent().putExtra(IntentKey.REPLY_EXPAND, false))
focusCompose.assertValue(false)

this.vm.intent(Intent().putExtra("Some other Key", false))
focusCompose.assertValues(false)

this.vm.intent(Intent().putExtra(IntentKey.REPLY_EXPAND, true))
focusCompose.assertValues(false, true)
}
}

0 comments on commit 4077bb5

Please sign in to comment.