Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit 668d521

Browse files
committed
Implement new market layout
1 parent 6b9bbb5 commit 668d521

13 files changed

Lines changed: 2216 additions & 57 deletions

File tree

‎data/services/store/schemas/com.gemwallet.android.data.service.store.database.GemDatabase/65.json‎

Lines changed: 2010 additions & 0 deletions
Large diffs are not rendered by default.

‎data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/GemDatabase.kt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import com.gemwallet.android.data.service.store.database.entities.DbTxSwapMetada
3737
import com.gemwallet.android.data.service.store.database.entities.DbWallet
3838

3939
@Database(
40-
version = 64,
40+
version = 65,
4141
entities = [
4242
DbWallet::class,
4343
DbAccount::class,

‎data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/di/DatabaseModule.kt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ object DatabaseModule {
6161
.addMigrations(Migration_61_62)
6262
.addMigrations(Migration_62_63)
6363
.addMigrations(Migration_63_64(context, passwordStore))
64+
.addMigrations(Migration_64_65)
6465
.build()
6566

6667
@Singleton
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.gemwallet.android.data.service.store.database.di
2+
3+
import androidx.room.migration.Migration
4+
import androidx.sqlite.db.SupportSQLiteDatabase
5+
6+
object Migration_64_65 : Migration(64, 65) {
7+
override fun migrate(db: SupportSQLiteDatabase) {
8+
db.execSQL(""" ALTER TABLE asset_market ADD COLUMN allTimeHigh REAL""".trimIndent())
9+
db.execSQL(""" ALTER TABLE asset_market ADD COLUMN allTimeHighDate INTEGER""".trimIndent())
10+
db.execSQL(""" ALTER TABLE asset_market ADD COLUMN allTimeHighChangePercentage REAL""".trimIndent())
11+
db.execSQL(""" ALTER TABLE asset_market ADD COLUMN allTimeLow REAL""".trimIndent())
12+
db.execSQL(""" ALTER TABLE asset_market ADD COLUMN allTimeLowDate INTEGER""".trimIndent())
13+
db.execSQL(""" ALTER TABLE asset_market ADD COLUMN allTimeLowChangePercentage REAL""".trimIndent())
14+
}
15+
}

‎data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/entities/DbAsset.kt‎

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.wallet.core.primitives.AssetType
1818
import com.wallet.core.primitives.Chain
1919
import kotlinx.coroutines.flow.Flow
2020
import kotlinx.coroutines.flow.map
21+
import kotlin.Double
2122

2223
@Entity(tableName = "asset", primaryKeys = ["id"])
2324
data class DbAsset(
@@ -61,7 +62,13 @@ data class DbAssetMarket(
6162
val totalVolume: Double? = null,
6263
val circulatingSupply: Double? = null,
6364
val totalSupply: Double? = null,
64-
val maxSupply: Double? = null
65+
val maxSupply: Double? = null,
66+
val allTimeHigh: Double? = null,
67+
val allTimeHighDate: Long? = null,
68+
val allTimeHighChangePercentage: Double? = null,
69+
val allTimeLow: Double? = null,
70+
val allTimeLowDate: Long? = null,
71+
val allTimeLowChangePercentage: Double? = null
6572
)
6673

6774
@Entity(
@@ -125,9 +132,9 @@ fun AssetFull.toRecord() = DbAsset(
125132
symbol = asset.symbol,
126133
decimals = asset.decimals,
127134
type = asset.type,
128-
isBuyEnabled = properties.isBuyable == true,
129-
isSellEnabled = properties.isSellable == true,
130-
isStakeEnabled = properties.isStakeable == true,
135+
isBuyEnabled = properties.isBuyable,
136+
isSellEnabled = properties.isSellable,
137+
isStakeEnabled = properties.isStakeable,
131138
isSwapEnabled = asset.chain.isSwapSupport(),
132139
stakingApr = properties.stakingApr,
133140
rank = score.rank,
@@ -140,9 +147,9 @@ fun AssetBasic.toRecord() = DbAsset(
140147
symbol = asset.symbol,
141148
decimals = asset.decimals,
142149
type = asset.type,
143-
isBuyEnabled = properties.isBuyable == true,
144-
isSellEnabled = properties.isSellable == true,
145-
isStakeEnabled = properties.isStakeable == true,
150+
isBuyEnabled = properties.isBuyable,
151+
isSellEnabled = properties.isSellable,
152+
isStakeEnabled = properties.isStakeable,
146153
isSwapEnabled = asset.chain.isSwapSupport(),
147154
stakingApr = properties.stakingApr,
148155
rank = score.rank,
@@ -173,6 +180,12 @@ fun AssetMarket.toRecord(assetId: AssetId) = DbAssetMarket(
173180
circulatingSupply = circulatingSupply,
174181
totalSupply = totalSupply,
175182
maxSupply = maxSupply,
183+
allTimeHigh = allTimeHigh,
184+
allTimeHighDate = allTimeHighDate,
185+
allTimeHighChangePercentage = allTimeHighChangePercentage,
186+
allTimeLow = allTimeLow,
187+
allTimeLowDate = allTimeLowDate,
188+
allTimeLowChangePercentage = allTimeLowChangePercentage,
176189
)
177190

178191
fun DbAssetMarket.toDTO() = AssetMarket(
@@ -183,4 +196,10 @@ fun DbAssetMarket.toDTO() = AssetMarket(
183196
circulatingSupply = circulatingSupply,
184197
totalSupply = totalSupply,
185198
maxSupply = maxSupply,
199+
allTimeHigh = allTimeHigh,
200+
allTimeHighDate = allTimeHighDate,
201+
allTimeHighChangePercentage = allTimeHighChangePercentage,
202+
allTimeLow = allTimeLow,
203+
allTimeLowDate = allTimeLowDate,
204+
allTimeLowChangePercentage = allTimeLowChangePercentage,
186205
)

‎features/activities/viewmodels/src/main/kotlin/com/gemwallet/android/features/activities/viewmodels/TransactionsViewModel.kt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class TransactionsViewModel @Inject constructor(
6060
.distinctUntilChanged()
6161
.stateIn(viewModelScope, started = SharingStarted.Eagerly, emptyList())
6262

63-
val ticker = tickerFlow(true, 5 * DateUtils.SECOND_IN_MILLIS) {
63+
val ticker = tickerFlow(true, 5 * DateUtils.MINUTE_IN_MILLIS) {
6464
if (it.complete) refresh()
6565
}
6666
.stateIn(viewModelScope, started = WhileSubscribed(5000), null)

‎features/asset/presents/src/main/kotlin/com/gemwallet/features/asset/presents/chart/AssetChartScene.kt‎

Lines changed: 119 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ package com.gemwallet.features.asset.presents.chart
22

33
import androidx.compose.foundation.clickable
44
import androidx.compose.foundation.combinedClickable
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.defaultMinSize
57
import androidx.compose.foundation.layout.padding
68
import androidx.compose.foundation.lazy.LazyColumn
79
import androidx.compose.foundation.lazy.LazyListScope
810
import androidx.compose.foundation.lazy.itemsIndexed
911
import androidx.compose.runtime.Composable
1012
import androidx.compose.runtime.getValue
13+
import androidx.compose.ui.Alignment
1114
import androidx.compose.ui.Modifier
1215
import androidx.compose.ui.platform.LocalClipboard
1316
import androidx.compose.ui.platform.LocalContext
@@ -18,21 +21,29 @@ import androidx.compose.ui.unit.dp
1821
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
1922
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2023
import com.gemwallet.android.domains.asset.chain
24+
import com.gemwallet.android.domains.percentage.formatAsPercentage
25+
import com.gemwallet.android.domains.price.getPriceState
2126
import com.gemwallet.android.model.compactFormatter
2227
import com.gemwallet.android.ui.R
2328
import com.gemwallet.android.ui.components.clipboard.setPlainText
2429
import com.gemwallet.android.ui.components.image.AsyncImage
2530
import com.gemwallet.android.ui.components.list_item.Badge
31+
import com.gemwallet.android.ui.components.list_item.ListItem
32+
import com.gemwallet.android.ui.components.list_item.ListItemSupportText
33+
import com.gemwallet.android.ui.components.list_item.ListItemTitleText
2634
import com.gemwallet.android.ui.components.list_item.SubheaderItem
35+
import com.gemwallet.android.ui.components.list_item.color
2736
import com.gemwallet.android.ui.components.list_item.property.DataBadgeChevron
2837
import com.gemwallet.android.ui.components.list_item.property.PropertyDataText
2938
import com.gemwallet.android.ui.components.list_item.property.PropertyItem
3039
import com.gemwallet.android.ui.components.list_item.property.PropertyTitleText
40+
import com.gemwallet.android.ui.components.list_item.property.itemsPositioned
3141
import com.gemwallet.android.ui.components.screen.LoadingScene
3242
import com.gemwallet.android.ui.components.screen.Scene
3343
import com.gemwallet.android.ui.models.ListPosition
3444
import com.gemwallet.android.ui.open
3545
import com.gemwallet.android.ui.theme.trailingIconMedium
46+
import com.gemwallet.features.asset.viewmodels.chart.models.AllTimeUIModel
3647
import com.gemwallet.features.asset.viewmodels.chart.models.AssetMarketUIModel
3748
import com.gemwallet.features.asset.viewmodels.chart.models.MarketInfoUIModel
3849
import com.gemwallet.features.asset.viewmodels.chart.viewmodels.AssetChartViewModel
@@ -41,6 +52,8 @@ import com.wallet.core.primitives.AssetId
4152
import com.wallet.core.primitives.AssetMarket
4253
import com.wallet.core.primitives.Currency
4354
import uniffi.gemstone.Explorer
55+
import java.text.DateFormat
56+
import java.util.Date
4457

4558
@Composable
4659
fun AssetChartScene(
@@ -109,47 +122,89 @@ private fun LazyListScope.links(links: List<AssetMarketUIModel.Link>) {
109122
}
110123

111124
private fun LazyListScope.assetMarket(currency: Currency, asset: Asset, marketInfo: AssetMarket?, explorerName: String) {
112-
val items = marketInfo?.let {
113-
mutableListOf<MarketInfoUIModel>().apply {
114-
it.marketCap?.let {
115-
add(
116-
MarketInfoUIModel(
117-
type = MarketInfoUIModel.MarketInfoTypeUIModel.MarketCap,
118-
value = currency.compactFormatter(it),
119-
badge = marketInfo.marketCapRank?.takeIf { it > 0 }
120-
.let { "#${marketInfo.marketCapRank}" }
121-
)
125+
marketInfo ?: return
126+
val marketItems = mutableListOf<MarketInfoUIModel>().apply {
127+
marketInfo.marketCap?.let {
128+
add(
129+
MarketInfoUIModel(
130+
type = MarketInfoUIModel.MarketInfoTypeUIModel.MarketCap,
131+
value = currency.compactFormatter(it),
132+
badge = marketInfo.marketCapRank?.takeIf { it > 0 }
133+
.let { "#${marketInfo.marketCapRank}" }
122134
)
123-
}
124-
it.circulatingSupply?.let {
125-
add(
126-
MarketInfoUIModel(
127-
type = MarketInfoUIModel.MarketInfoTypeUIModel.CirculatingSupply,
128-
value = currency.compactFormatter(it),
129-
)
135+
)
136+
}
137+
marketInfo.marketCapFdv?.let {
138+
add(
139+
MarketInfoUIModel(
140+
type = MarketInfoUIModel.MarketInfoTypeUIModel.FDV,
141+
value = currency.compactFormatter(it),
130142
)
131-
}
132-
it.totalSupply?.let {
133-
add(
134-
MarketInfoUIModel(
135-
type = MarketInfoUIModel.MarketInfoTypeUIModel.TotalSupply,
136-
value = currency.compactFormatter(it),
137-
)
143+
)
144+
}
145+
}
146+
147+
val supplyItems = mutableListOf<MarketInfoUIModel>().apply {
148+
marketInfo.circulatingSupply?.let {
149+
add(
150+
MarketInfoUIModel(
151+
type = MarketInfoUIModel.MarketInfoTypeUIModel.CirculatingSupply,
152+
value = currency.compactFormatter(it),
138153
)
139-
}
140-
asset.id.tokenId?.let {
141-
add(
142-
MarketInfoUIModel(
143-
type = MarketInfoUIModel.MarketInfoTypeUIModel.Contract,
144-
value = it,
145-
)
154+
)
155+
}
156+
marketInfo.totalSupply?.let {
157+
add(
158+
MarketInfoUIModel(
159+
type = MarketInfoUIModel.MarketInfoTypeUIModel.TotalSupply,
160+
value = currency.compactFormatter(it),
146161
)
147-
}
162+
)
163+
}
164+
165+
marketInfo.maxSupply?.let {
166+
add(
167+
MarketInfoUIModel(
168+
type = MarketInfoUIModel.MarketInfoTypeUIModel.MaxSupply,
169+
value = currency.compactFormatter(it),
170+
)
171+
)
148172
}
149-
} ?: emptyList()
150-
itemsIndexed(items) { index, item ->
151-
val position = ListPosition.getPosition(index, items.size)
173+
asset.id.tokenId?.let {
174+
add(
175+
MarketInfoUIModel(
176+
type = MarketInfoUIModel.MarketInfoTypeUIModel.Contract,
177+
value = it,
178+
)
179+
)
180+
}
181+
}
182+
183+
val allTime = mutableListOf<AllTimeUIModel>().apply {
184+
if (marketInfo.allTimeHigh != null && marketInfo.allTimeHighDate != null && marketInfo.allTimeHighChangePercentage != null) {
185+
add(
186+
AllTimeUIModel.High(marketInfo.allTimeHighDate!!, marketInfo.allTimeHigh!!, marketInfo.allTimeHighChangePercentage!!)
187+
)
188+
}
189+
if (marketInfo.allTimeLow != null && marketInfo.allTimeLowDate != null && marketInfo.allTimeLowChangePercentage != null) {
190+
add(
191+
AllTimeUIModel.Low(marketInfo.allTimeLowDate!!, marketInfo.allTimeLow!!, marketInfo.allTimeLowChangePercentage!!)
192+
)
193+
}
194+
}
195+
196+
marketProperties(asset, explorerName, marketItems)
197+
marketProperties(asset, explorerName, supplyItems)
198+
allTimeProperties(asset, currency, allTime)
199+
}
200+
201+
private fun LazyListScope.marketProperties(asset: Asset, explorerName: String, items: List<MarketInfoUIModel>) {
202+
itemsPositioned(items) { position, item ->
152203
when (item.type) {
204+
MarketInfoUIModel.MarketInfoTypeUIModel.FDV,
205+
MarketInfoUIModel.MarketInfoTypeUIModel.CirculatingSupply,
206+
MarketInfoUIModel.MarketInfoTypeUIModel.TotalSupply,
207+
MarketInfoUIModel.MarketInfoTypeUIModel.MaxSupply -> PropertyItem(item.type.label, item.value, listPosition = position)
153208
MarketInfoUIModel.MarketInfoTypeUIModel.MarketCap -> PropertyItem(
154209
title = {
155210
PropertyTitleText(
@@ -160,8 +215,6 @@ private fun LazyListScope.assetMarket(currency: Currency, asset: Asset, marketIn
160215
data = { PropertyDataText(item.value) },
161216
listPosition = position
162217
)
163-
MarketInfoUIModel.MarketInfoTypeUIModel.CirculatingSupply -> PropertyItem(item.type.label, item.value, listPosition = position)
164-
MarketInfoUIModel.MarketInfoTypeUIModel.TotalSupply -> PropertyItem(item.type.label, item.value, listPosition = position)
165218
MarketInfoUIModel.MarketInfoTypeUIModel.Contract -> {
166219
val context = LocalContext.current
167220
val clipboardManager = LocalClipboard.current.nativeClipboard
@@ -178,7 +231,9 @@ private fun LazyListScope.assetMarket(currency: Currency, asset: Asset, marketIn
178231
title = { PropertyTitleText(R.string.asset_contract) },
179232
data = {
180233
PropertyDataText(
181-
modifier = Modifier.weight(1f).padding(top = 0.dp, bottom = 2.dp),
234+
modifier = Modifier
235+
.weight(1f)
236+
.padding(top = 0.dp, bottom = 2.dp),
182237
text = item.value,
183238
)
184239
},
@@ -187,4 +242,30 @@ private fun LazyListScope.assetMarket(currency: Currency, asset: Asset, marketIn
187242
}
188243
}
189244
}
245+
}
246+
247+
private fun LazyListScope.allTimeProperties(asset: Asset, currency: Currency, items: List<AllTimeUIModel>) {
248+
val dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM)
249+
250+
itemsPositioned(items) { position, item ->
251+
val title = when (item) {
252+
is AllTimeUIModel.High -> R.string.asset_all_time_high
253+
is AllTimeUIModel.Low -> R.string.asset_all_time_low
254+
}
255+
ListItem(
256+
listPosition = position,
257+
title = @Composable { ListItemTitleText(stringResource(title)) },
258+
subtitle = { ListItemSupportText(dateFormat.format(Date(item.date))) },
259+
trailing = {
260+
Column(
261+
modifier = Modifier.defaultMinSize(40.dp),
262+
horizontalAlignment = Alignment.End
263+
) {
264+
ListItemTitleText(currency.compactFormatter(item.value))
265+
ListItemSupportText(item.percentage.formatAsPercentage(), color = item.percentage.getPriceState().color())
266+
}
267+
},
268+
)
269+
}
270+
190271
}

‎features/asset/presents/src/main/kotlin/com/gemwallet/features/asset/presents/details/components/PriceItem.kt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import androidx.compose.material3.Text
77
import androidx.compose.ui.Modifier
88
import androidx.compose.ui.platform.testTag
99
import com.gemwallet.android.ui.R
10-
import com.gemwallet.android.ui.components.list_item.priceColor
10+
import com.gemwallet.android.ui.components.list_item.color
1111
import com.gemwallet.android.ui.components.list_item.property.DataBadgeChevron
1212
import com.gemwallet.android.ui.components.list_item.property.PropertyDataText
1313
import com.gemwallet.android.ui.components.list_item.property.PropertyItem
@@ -36,7 +36,7 @@ internal fun LazyListScope.price(
3636
DataBadgeChevron {
3737
Text(
3838
text = uiState.priceDayChanges,
39-
color = priceColor(uiState.priceChangedType),
39+
color = uiState.priceChangedType.color(),
4040
style = MaterialTheme.typography.bodyLarge,
4141
)
4242
}

‎features/asset/viewmodels/src/main/kotlin/com/gemwallet/features/asset/viewmodels/chart/models/MarketInfoUIModel.kt‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ class MarketInfoUIModel(
1212
MarketCap(R.string.asset_market_cap),
1313
CirculatingSupply(R.string.asset_circulating_supply),
1414
TotalSupply(R.string.asset_total_supply),
15-
Contract(R.string.asset_contract)
15+
MaxSupply(R.string.info_max_supply_title),
16+
Contract(R.string.asset_contract),
17+
FDV(R.string.info_fully_diluted_valuation_title),
1618
}
19+
}
20+
21+
sealed class AllTimeUIModel(
22+
val date: Long,
23+
val value: Double,
24+
val percentage: Double,
25+
) {
26+
class High(
27+
date: Long,
28+
value: Double,
29+
percentage: Double,
30+
) : AllTimeUIModel(date, value, percentage)
31+
32+
class Low(
33+
date: Long,
34+
value: Double,
35+
percentage: Double,
36+
) : AllTimeUIModel(date, value, percentage)
1737
}

0 commit comments

Comments
 (0)