Skip to content

Commit

Permalink
removing circle indicators and adding count footer to rewards (#591)
Browse files Browse the repository at this point in the history
  • Loading branch information
eoji authored Aug 19, 2019
1 parent c25d4f2 commit c9b432d
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 88 deletions.
75 changes: 1 addition & 74 deletions app/src/main/java/com/kickstarter/libs/utils/RewardDecoration.kt
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
package com.kickstarter.libs.utils

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.Interpolator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class RewardDecoration(private val margin: Int, private val colorActive: Int, private val colorInactive: Int,
private val radius: Float, private val padding: Float,
class RewardDecoration(private val margin: Int,
val interpolator: Interpolator = AccelerateDecelerateInterpolator()) : RecyclerView.ItemDecoration() {

private val height = margin * 2 + radius * 2
private val paint = Paint()

init {
paint.style = Paint.Style.FILL
paint.isAntiAlias = true
}

override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)

Expand All @@ -36,67 +24,6 @@ class RewardDecoration(private val margin: Int, private val colorActive: Int, pr
else -> margin / 2
}
top = margin
bottom = (height * 3/2).toInt()
}
}

override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)

paint.color = colorInactive

val dividerY = parent.height - height
c.drawLine(0f, dividerY, parent.width.toFloat(), dividerY, paint)

val itemCount = state.itemCount

if (itemCount == 0) {
return
}

val widthOfCircles = radius * 2 * itemCount
val paddingBetweenCircles = (itemCount - 1) * padding
val indicatorWidth = widthOfCircles + paddingBetweenCircles
val remainingWidth = parent.width - indicatorWidth

if (remainingWidth < 0) {
return
}

val indicatorX = remainingWidth / 2
val indicatorY = parent.height - height / 2f

drawPositions(c, indicatorX, indicatorY, itemCount)

val layoutManager = parent.layoutManager as LinearLayoutManager
val currentPosition = layoutManager.findFirstCompletelyVisibleItemPosition()
if (currentPosition == RecyclerView.NO_POSITION) {
return
}

drawCurrentPosition(c, indicatorX, indicatorY, currentPosition)
}

private fun drawPositions(c: Canvas, indicatorX: Float, indicatorY: Float, itemCount: Int) {
var x = indicatorX
(0 until itemCount).forEach { _ ->
drawCircleFromLeftEdge(c, x, indicatorY)

x += getCircleWidth() + padding
}
}

private fun drawCurrentPosition(c: Canvas, indicatorX: Float, indicatorY: Float, position: Int) {
paint.color = colorActive

val x = indicatorX + (getCircleWidth() + padding) * position

drawCircleFromLeftEdge(c, x, indicatorY)
}

private fun drawCircleFromLeftEdge(c: Canvas, x: Float, indicatorY: Float) {
c.drawCircle(x + radius, indicatorY, radius, paint)
}

private fun getCircleWidth() = radius * 2
}
19 changes: 13 additions & 6 deletions app/src/main/java/com/kickstarter/ui/fragments/RewardsFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.kickstarter.R
import com.kickstarter.libs.BaseFragment
import com.kickstarter.libs.qualifiers.RequiresFragmentViewModel
import com.kickstarter.libs.rx.transformers.Transformers.observeForUI
import com.kickstarter.libs.utils.NumberUtils
import com.kickstarter.libs.utils.RewardDecoration
import com.kickstarter.models.Project
import com.kickstarter.models.Reward
Expand Down Expand Up @@ -48,6 +48,11 @@ class RewardsFragment : BaseFragment<RewardsFragmentViewModel.ViewModel>(), Nati
.compose(observeForUI())
.subscribe { showPledgeFragment(it) }

this.viewModel.outputs.rewardsCount()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe { setRewardsCount(it) }

}

private fun scrollToReward(position: Int) {
Expand All @@ -61,6 +66,12 @@ class RewardsFragment : BaseFragment<RewardsFragmentViewModel.ViewModel>(), Nati
}
}

private fun setRewardsCount(count: Int) {
val rewardsCountString = this.viewModel.environment.ksString().format("Rewards_count_rewards", count,
"rewards_count", NumberUtils.format(count))
rewards_count.text = rewardsCountString
}

override fun onDetach() {
super.onDetach()
rewards_recycler?.adapter = null
Expand All @@ -75,12 +86,8 @@ class RewardsFragment : BaseFragment<RewardsFragmentViewModel.ViewModel>(), Nati
}

private fun addItemDecorator() {
val radius = resources.getDimensionPixelSize(R.dimen.circle_radius).toFloat()
val inactiveColor = ContextCompat.getColor(rewards_recycler.context, R.color.ksr_dark_grey_400)
val activeColor = ContextCompat.getColor(rewards_recycler.context, R.color.ksr_soft_black)
val margin = resources.getDimension(R.dimen.reward_margin).toInt()
val padding = radius * 2
rewards_recycler.addItemDecoration(RewardDecoration(margin, activeColor, inactiveColor, radius, padding))
rewards_recycler.addItemDecoration(RewardDecoration(margin))
}

private fun setupRecyclerView() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,21 @@ class RewardsFragmentViewModel {
/** Emits the current project. */
fun project(): Observable<Project>

/** Emits the count of the current project's rewards. */
fun rewardsCount(): Observable<Int>

/** Emits when we should show the [com.kickstarter.ui.fragments.PledgeFragment]. */
fun showPledgeFragment(): Observable<PledgeData>
}

class ViewModel(@NonNull environment: Environment) : FragmentViewModel<RewardsFragment>(environment), Inputs, Outputs {
class ViewModel(@NonNull val environment: Environment) : FragmentViewModel<RewardsFragment>(environment), Inputs, Outputs {

private val projectInput = PublishSubject.create<Project>()
private val rewardClicked = PublishSubject.create<Pair<ScreenLocation, Reward>>()

private val backedRewardPosition = PublishSubject.create<Int>()
private val project = BehaviorSubject.create<Project>()
private val rewardsCount = BehaviorSubject.create<Int>()
private val showPledgeFragment = PublishSubject.create<PledgeData>()

val inputs: Inputs = this
Expand All @@ -61,9 +65,14 @@ class RewardsFragmentViewModel {

this.projectInput
.compose<Pair<Project, Pair<ScreenLocation, Reward>>>(Transformers.takePairWhen(this.rewardClicked))
.map<PledgeData> { PledgeData(it.second.first, it.second.second, it.first) }
.map { PledgeData(it.second.first, it.second.second, it.first) }
.compose(bindToLifecycle())
.subscribe(this.showPledgeFragment)

this.projectInput
.map { it.rewards()?.size?: 0 }
.compose(bindToLifecycle())
.subscribe(this.rewardsCount)
}

private fun indexOfBackedReward(project: Project): Int {
Expand Down Expand Up @@ -92,6 +101,9 @@ class RewardsFragmentViewModel {
@NonNull
override fun project(): Observable<Project> = this.project

@NonNull
override fun rewardsCount(): Observable<Int> = this.rewardsCount

@NonNull
override fun showPledgeFragment(): Observable<PledgeData> = this.showPledgeFragment
}
Expand Down
20 changes: 17 additions & 3 deletions app/src/main/res/layout/fragment_rewards.xml
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/ksr_grey_400"
android:orientation="vertical"
android:paddingTop="?android:attr/actionBarSize">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rewards_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:overScrollMode="never"
android:scrollbars="horizontal"
tools:listitem="@layout/item_reward" />
</FrameLayout>

<include layout="@layout/horizontal_line_1dp_view" />

<TextView
android:id="@+id/rewards_count"
style="@style/FootnoteSecondary"
android:layout_width="match_parent"
android:layout_height="@dimen/grid_7"
android:gravity="center"
tools:text="24 rewards" />

</LinearLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ import com.kickstarter.ui.data.PledgeData
import com.kickstarter.ui.data.ScreenLocation
import org.junit.Test
import rx.observers.TestSubscriber
import java.util.*

class RewardsFragmentViewModelTest: KSRobolectricTestCase() {

private lateinit var vm: RewardsFragmentViewModel.ViewModel
private val backedRewardPosition = TestSubscriber.create<Int>()
private val project = TestSubscriber.create<Project>()
private val rewardsCount = TestSubscriber.create<Int>()
private val showPledgeFragment = TestSubscriber<PledgeData>()

private fun setUpEnvironment(@NonNull environment: Environment) {
this.vm = RewardsFragmentViewModel.ViewModel(environment)
this.vm.outputs.backedRewardPosition().subscribe(this.backedRewardPosition)
this.vm.outputs.project().subscribe(this.project)
this.vm.outputs.rewardsCount().subscribe(this.rewardsCount)
this.vm.outputs.showPledgeFragment().subscribe(this.showPledgeFragment)
}

Expand All @@ -42,7 +43,7 @@ class RewardsFragmentViewModelTest: KSRobolectricTestCase() {
.toBuilder()
.rewardId(reward.id())
.build())
.rewards(Arrays.asList(RewardFactory.noReward(), reward))
.rewards(listOf(RewardFactory.noReward(), reward))
.build()
this.vm.inputs.project(backedProject)
this.backedRewardPosition.assertValue(1)
Expand All @@ -65,7 +66,7 @@ class RewardsFragmentViewModelTest: KSRobolectricTestCase() {
}

@Test
fun testProjectViewModel_ShowPledgeFragment() {
fun testShowPledgeFragment() {
val project = ProjectFactory.project()
setUpEnvironment(environment())

Expand All @@ -76,4 +77,17 @@ class RewardsFragmentViewModelTest: KSRobolectricTestCase() {
this.vm.inputs.rewardClicked(screenLocation, reward)
this.showPledgeFragment.assertValue(PledgeData(screenLocation, reward, project))
}

@Test
fun testRewardsCount() {
val project = ProjectFactory.project()
.toBuilder()
.rewards(listOf(RewardFactory.noReward(), RewardFactory.reward()))
.build()
setUpEnvironment(environment())

this.vm.inputs.project(project)

this.rewardsCount.assertValue(2)
}
}

0 comments on commit c9b432d

Please sign in to comment.