Skip to content

Commit

Permalink
FE-1564 Feature/fe 1498 refactor rangeselectorview as a composable (#474
Browse files Browse the repository at this point in the history
)

* [WIP] Range selector view as composable

* Fix issue of charts not loading properly when API replies very fast
  • Loading branch information
PavlosTze committed Feb 3, 2025
1 parent dcef4f4 commit 5f6e783
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 149 deletions.
1 change: 1 addition & 0 deletions app/src/main/java/com/weatherxm/ui/common/Contracts.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.weatherxm.ui.common

object Contracts {
const val LOADING_DELAY = 200L
const val EMPTY_VALUE = "?"
const val DEGREES_MARK = "°"
const val NOT_AVAILABLE_VALUE = "N/A"
Expand Down
54 changes: 0 additions & 54 deletions app/src/main/java/com/weatherxm/ui/components/RangeSelectorView.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.weatherxm.ui.components.compose

import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.weatherxm.R

@Suppress("FunctionNaming")
@Preview
@Composable
fun RangeSelectorView(
selectedChipLabelResId: Int = R.string.seven_days_abbr,
enabledToggle: Boolean = true,
onSelectedChanged: (Int) -> Unit = {},
) {
val sevenDaysAbbrResId = R.string.seven_days_abbr
val oneMonthAbbrResId = R.string.one_month_abbr
Card(
colors = CardDefaults.cardColors(
containerColor = colorResource(R.color.layer1)
),
shape = RoundedCornerShape(dimensionResource(R.dimen.radius_small))
) {
Row(
modifier = Modifier.padding(dimensionResource(R.dimen.padding_extra_small)),
horizontalArrangement = spacedBy(dimensionResource(R.dimen.margin_extra_small))
) {
Chip(
labelResId = sevenDaysAbbrResId,
isSelected = sevenDaysAbbrResId == selectedChipLabelResId,
enabledToggle = enabledToggle,
onSelectionChanged = { onSelectedChanged(it) },
)
Chip(
labelResId = oneMonthAbbrResId,
isSelected = oneMonthAbbrResId == selectedChipLabelResId,
enabledToggle = enabledToggle,
onSelectionChanged = { onSelectedChanged(it) },
)
}
}
}

@Suppress("FunctionNaming")
@Preview
@Composable
fun Chip(
labelResId: Int = R.string.seven_days_abbr,
isSelected: Boolean = false,
enabledToggle: Boolean = true,
onSelectionChanged: (Int) -> Unit = {},
) {
Surface(
shape = RoundedCornerShape(dimensionResource(R.dimen.radius_small)),
color = if (isSelected) colorResource(R.color.layer2) else colorResource(R.color.layer1)
) {
Row(modifier = Modifier
.padding(
dimensionResource(R.dimen.padding_normal),
dimensionResource(R.dimen.padding_small_to_normal)
)
.toggleable(
value = isSelected,
enabled = enabledToggle,
onValueChange = {
onSelectionChanged(labelResId)
}
)
) {
MediumText(
text = stringResource(labelResId),
colorRes = R.color.darkGrey,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.weatherxm.ui.devicesrewards

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
Expand All @@ -18,6 +20,7 @@ import com.weatherxm.ui.common.hide
import com.weatherxm.ui.common.invisible
import com.weatherxm.ui.common.show
import com.weatherxm.ui.common.visible
import com.weatherxm.ui.components.compose.RangeSelectorView
import com.weatherxm.util.NumberUtils.formatTokens
import com.weatherxm.util.initRewardsBreakdownChart
import org.koin.core.component.KoinComponent
Expand Down Expand Up @@ -58,14 +61,22 @@ class DeviceRewardsAdapter(
val adapter = DeviceRewardsBoostAdapter()
private var ignoreRangeChipListener = false

private val selectedRangeChip = mutableIntStateOf(R.string.seven_days_abbr)
private val enabledRangeToggle = mutableStateOf(true)

fun bind(item: DeviceTotalRewards) {
binding.headerCard.setOnClickListener {
onExpandClick(item)
}

binding.chartRangeSelector.listener {
if (!ignoreRangeChipListener) {
onFetchNewData.invoke(item.id, absoluteAdapterPosition, it)
binding.chartRangeSelector.setContent {
RangeSelectorView(
selectedChipLabelResId = selectedRangeChip.intValue,
enabledToggle = enabledRangeToggle.value
) {
if (!ignoreRangeChipListener && selectedRangeChip.intValue != it) {
onFetchNewData.invoke(item.id, absoluteAdapterPosition, it)
}
}
}

Expand All @@ -87,7 +98,7 @@ class DeviceRewardsAdapter(
onError(item.id)
}
Status.LOADING -> {
binding.chartRangeSelector.disable()
enabledRangeToggle.value = false
binding.detailsContainer.invisible()
binding.earnedBy.invisible()
binding.retryCard.visible(false)
Expand All @@ -99,8 +110,8 @@ class DeviceRewardsAdapter(
private fun preCheckMode(mode: RewardsSummaryMode?) {
ignoreRangeChipListener = true
when (mode) {
RewardsSummaryMode.WEEK -> binding.chartRangeSelector.checkWeek()
RewardsSummaryMode.MONTH -> binding.chartRangeSelector.checkMonth()
RewardsSummaryMode.WEEK -> selectedRangeChip.intValue = R.string.seven_days_abbr
RewardsSummaryMode.MONTH -> selectedRangeChip.intValue = R.string.one_month_abbr
else -> throw NotImplementedError("Unknown rewards mode $mode")
}.also {
ignoreRangeChipListener = false
Expand All @@ -126,7 +137,7 @@ class DeviceRewardsAdapter(
binding.othersRewardsLegend.visible(details.otherChartData.isDataValid())
binding.retryCard.visible(false)
binding.detailsStatus.visible(false)
binding.chartRangeSelector.enable()
enabledRangeToggle.value = true
binding.earnedBy.visible(true)
binding.detailsContainer.visible(true)
}
Expand Down Expand Up @@ -159,7 +170,7 @@ class DeviceRewardsAdapter(
onFetchNewData.invoke(
item.id,
absoluteAdapterPosition,
binding.chartRangeSelector.checkedChipId()
selectedRangeChip.intValue
)
} else {
binding.detailsWithLoadingContainer.show()
Expand Down Expand Up @@ -187,11 +198,11 @@ class DeviceRewardsAdapter(
onFetchNewData.invoke(
deviceId,
absoluteAdapterPosition,
binding.chartRangeSelector.checkedChipId()
selectedRangeChip.intValue
)
}
}
binding.chartRangeSelector.enable()
enabledRangeToggle.value = true
binding.retryCard.visible(true)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.weatherxm.ui.common.parcelable
import com.weatherxm.ui.common.visible
import com.weatherxm.ui.components.BaseActivity
import com.weatherxm.ui.components.compose.LargeText
import com.weatherxm.ui.components.compose.RangeSelectorView
import com.weatherxm.util.NumberUtils.formatTokens
import com.weatherxm.util.initTotalEarnedChart
import org.koin.androidx.viewmodel.ext.android.viewModel
Expand All @@ -56,16 +57,22 @@ class DevicesRewardsActivity : BaseActivity() {
navigator.openWebsite(this, getString(R.string.shop_url))
}

binding.totalEarnedRangeSelector.listener {
model.getDevicesRewardsByRangeTotals(it)
binding.totalEarnedRangeSelector.setContent {
RangeSelectorView(
selectedChipLabelResId = model.totalSelectedRangeChip(),
enabledToggle = model.totalRangeChipsToggleEnabled()
) {
if (model.totalSelectedRangeChip() != it) {
model.getDevicesRewardsByRangeTotals(it)
}
}
}

model.onRewardsByRange().observe(this) {
when (it.status) {
Status.SUCCESS -> {
binding.totalEarnedStatus.visible(false)
binding.retryCard.visible(false)
binding.totalEarnedRangeSelector.enable()
binding.totalEarned.text =
getString(R.string.wxm_amount, formatTokens(it.data?.total))
it.data?.let { data ->
Expand All @@ -81,7 +88,6 @@ class DevicesRewardsActivity : BaseActivity() {
onError()
}
Status.LOADING -> {
binding.totalEarnedRangeSelector.disable()
binding.totalEarnedChart.invisible()
binding.totalEarned.invisible()
binding.retryCard.visible(false)
Expand Down Expand Up @@ -119,7 +125,6 @@ class DevicesRewardsActivity : BaseActivity() {

adapter.submitList(model.rewards.devices)

binding.totalEarnedRangeSelector.checkWeek()
model.getDevicesRewardsByRangeTotals()
model.getDeviceRewardsByRange(model.rewards.devices[0].id, 0)
} else {
Expand All @@ -133,15 +138,12 @@ class DevicesRewardsActivity : BaseActivity() {
}

private fun onError() {
binding.totalEarnedRangeSelector.enable()
binding.totalEarnedChart.invisible()
binding.totalEarned.invisible()
binding.totalEarnedStatus.visible(false)
binding.retryCard.setContent {
RetryCard {
model.getDevicesRewardsByRangeTotals(
binding.totalEarnedRangeSelector.checkedChipId()
)
model.getDevicesRewardsByRangeTotals()
}
}
binding.retryCard.visible(true)
Expand Down
Loading

0 comments on commit 5f6e783

Please sign in to comment.