From c9b432d3ac998993d6a14bd1cc8e81982d3aac31 Mon Sep 17 00:00:00 2001 From: Izzy Oji Date: Mon, 19 Aug 2019 11:21:56 -0400 Subject: [PATCH] removing circle indicators and adding count footer to rewards (#591) --- .../libs/utils/RewardDecoration.kt | 75 +------------------ .../ui/fragments/RewardsFragment.kt | 19 +++-- .../viewmodels/RewardsFragmentViewModel.kt | 16 +++- app/src/main/res/layout/fragment_rewards.xml | 20 ++++- .../RewardsFragmentViewModelTest.kt | 20 ++++- 5 files changed, 62 insertions(+), 88 deletions(-) diff --git a/app/src/main/java/com/kickstarter/libs/utils/RewardDecoration.kt b/app/src/main/java/com/kickstarter/libs/utils/RewardDecoration.kt index c67cae023b..702067a4a4 100644 --- a/app/src/main/java/com/kickstarter/libs/utils/RewardDecoration.kt +++ b/app/src/main/java/com/kickstarter/libs/utils/RewardDecoration.kt @@ -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) @@ -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 } diff --git a/app/src/main/java/com/kickstarter/ui/fragments/RewardsFragment.kt b/app/src/main/java/com/kickstarter/ui/fragments/RewardsFragment.kt index 232b3a5449..b39eedd7a3 100644 --- a/app/src/main/java/com/kickstarter/ui/fragments/RewardsFragment.kt +++ b/app/src/main/java/com/kickstarter/ui/fragments/RewardsFragment.kt @@ -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 @@ -48,6 +48,11 @@ class RewardsFragment : BaseFragment(), Nati .compose(observeForUI()) .subscribe { showPledgeFragment(it) } + this.viewModel.outputs.rewardsCount() + .compose(bindToLifecycle()) + .compose(observeForUI()) + .subscribe { setRewardsCount(it) } + } private fun scrollToReward(position: Int) { @@ -61,6 +66,12 @@ class RewardsFragment : BaseFragment(), 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 @@ -75,12 +86,8 @@ class RewardsFragment : BaseFragment(), 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() { diff --git a/app/src/main/java/com/kickstarter/viewmodels/RewardsFragmentViewModel.kt b/app/src/main/java/com/kickstarter/viewmodels/RewardsFragmentViewModel.kt index 45ca796dd2..212eb7eb20 100644 --- a/app/src/main/java/com/kickstarter/viewmodels/RewardsFragmentViewModel.kt +++ b/app/src/main/java/com/kickstarter/viewmodels/RewardsFragmentViewModel.kt @@ -31,17 +31,21 @@ class RewardsFragmentViewModel { /** Emits the current project. */ fun project(): Observable + /** Emits the count of the current project's rewards. */ + fun rewardsCount(): Observable + /** Emits when we should show the [com.kickstarter.ui.fragments.PledgeFragment]. */ fun showPledgeFragment(): Observable } - class ViewModel(@NonNull environment: Environment) : FragmentViewModel(environment), Inputs, Outputs { + class ViewModel(@NonNull val environment: Environment) : FragmentViewModel(environment), Inputs, Outputs { private val projectInput = PublishSubject.create() private val rewardClicked = PublishSubject.create>() private val backedRewardPosition = PublishSubject.create() private val project = BehaviorSubject.create() + private val rewardsCount = BehaviorSubject.create() private val showPledgeFragment = PublishSubject.create() val inputs: Inputs = this @@ -61,9 +65,14 @@ class RewardsFragmentViewModel { this.projectInput .compose>>(Transformers.takePairWhen(this.rewardClicked)) - .map { 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 { @@ -92,6 +101,9 @@ class RewardsFragmentViewModel { @NonNull override fun project(): Observable = this.project + @NonNull + override fun rewardsCount(): Observable = this.rewardsCount + @NonNull override fun showPledgeFragment(): Observable = this.showPledgeFragment } diff --git a/app/src/main/res/layout/fragment_rewards.xml b/app/src/main/res/layout/fragment_rewards.xml index 7398634e18..605f33c7f1 100644 --- a/app/src/main/res/layout/fragment_rewards.xml +++ b/app/src/main/res/layout/fragment_rewards.xml @@ -1,15 +1,29 @@ - - + + + + + + diff --git a/app/src/test/java/com/kickstarter/viewmodels/RewardsFragmentViewModelTest.kt b/app/src/test/java/com/kickstarter/viewmodels/RewardsFragmentViewModelTest.kt index 63a8ff91cc..b491dc5d28 100644 --- a/app/src/test/java/com/kickstarter/viewmodels/RewardsFragmentViewModelTest.kt +++ b/app/src/test/java/com/kickstarter/viewmodels/RewardsFragmentViewModelTest.kt @@ -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() private val project = TestSubscriber.create() + private val rewardsCount = TestSubscriber.create() private val showPledgeFragment = TestSubscriber() 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) } @@ -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) @@ -65,7 +66,7 @@ class RewardsFragmentViewModelTest: KSRobolectricTestCase() { } @Test - fun testProjectViewModel_ShowPledgeFragment() { + fun testShowPledgeFragment() { val project = ProjectFactory.project() setUpEnvironment(environment()) @@ -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) + } }