mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-03-17 21:31:57 +01:00
Moves to vico chart 2.0
This commit is contained in:
parent
dcb0e31cd6
commit
0f6c3b9a3a
@ -42,7 +42,7 @@ import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ThreadAssemblerTest {
|
||||
class ThreadDualAxisChartAssemblerTest {
|
||||
val db =
|
||||
"""
|
||||
[
|
@ -86,7 +86,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chatrooms.ScheduledFlag
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms.observeAppDefinition
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.HalfPadding
|
||||
@ -386,7 +385,7 @@ fun InnerRenderClassifiedsThumb(
|
||||
card.price?.let {
|
||||
val priceTag =
|
||||
remember(card) {
|
||||
val newAmount = it.amount.toBigDecimalOrNull()?.let { showAmountAxis(it) } ?: it.amount
|
||||
val newAmount = it.amount.toBigDecimalOrNull()?.let { showAmountInteger(it) } ?: it.amount
|
||||
|
||||
if (it.frequency != null && it.currency != null) {
|
||||
"$newAmount ${it.currency}/${it.frequency}"
|
||||
|
@ -74,3 +74,10 @@ fun showAmount(amount: BigDecimal?): String {
|
||||
else -> dfN.get().format(amount)
|
||||
}
|
||||
}
|
||||
|
||||
fun showAmountWithZero(amount: BigDecimal?): String {
|
||||
if (amount == null) return "0"
|
||||
if (amount.abs() < BigDecimal(0.01)) return "0"
|
||||
|
||||
return showAmount(amount)
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.note
|
||||
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
|
||||
private val dfG =
|
||||
object : ThreadLocal<DecimalFormat>() {
|
||||
override fun initialValue() = DecimalFormat("#G")
|
||||
}
|
||||
|
||||
private val dfM =
|
||||
object : ThreadLocal<DecimalFormat>() {
|
||||
override fun initialValue() = DecimalFormat("#M")
|
||||
}
|
||||
|
||||
private val dfK =
|
||||
object : ThreadLocal<DecimalFormat>() {
|
||||
override fun initialValue() = DecimalFormat("#k")
|
||||
}
|
||||
|
||||
private val dfN =
|
||||
object : ThreadLocal<DecimalFormat>() {
|
||||
override fun initialValue() = DecimalFormat("#")
|
||||
}
|
||||
|
||||
fun showAmountInteger(amount: BigDecimal?): String {
|
||||
if (amount == null) return ""
|
||||
if (amount.abs() < BigDecimal(0.01)) return ""
|
||||
|
||||
return when {
|
||||
amount >= OneGiga -> dfG.get().format(amount.div(OneGiga).setScale(0, RoundingMode.HALF_UP))
|
||||
amount >= OneMega -> dfM.get().format(amount.div(OneMega).setScale(0, RoundingMode.HALF_UP))
|
||||
amount >= TenKilo -> dfK.get().format(amount.div(OneKilo).setScale(0, RoundingMode.HALF_UP))
|
||||
else -> dfN.get().format(amount)
|
||||
}
|
||||
}
|
||||
|
||||
fun showAmountIntegerWithZero(amount: BigDecimal?): String {
|
||||
if (amount == null) return "0"
|
||||
if (amount.abs() < BigDecimal(0.01)) return "0"
|
||||
|
||||
return showAmountInteger(amount)
|
||||
}
|
@ -47,7 +47,6 @@ import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.FollowButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.ShowUserButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.UnfollowButton
|
||||
@ -144,7 +143,7 @@ private fun ZapAmount(zapEventNote: Note) {
|
||||
|
||||
LaunchedEffect(key1 = noteState) {
|
||||
launch(Dispatchers.IO) {
|
||||
val newZapAmount = showAmountAxis((noteState?.note?.event as? LnZapEvent)?.amount)
|
||||
val newZapAmount = showAmountInteger((noteState?.note?.event as? LnZapEvent)?.amount)
|
||||
if (zapAmount != newZapAmount) {
|
||||
zapAmount = newZapAmount
|
||||
}
|
||||
|
@ -64,11 +64,11 @@ import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapAmountCommentNotification
|
||||
import com.vitorpamplona.amethyst.ui.note.ZapraiserStatus
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmountInteger
|
||||
import com.vitorpamplona.amethyst.ui.screen.SettingsState
|
||||
import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CardFeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CombinedZap
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.tor.TorSettings
|
||||
import com.vitorpamplona.ammolite.relays.BundledInsert
|
||||
@ -536,7 +536,7 @@ class AccountViewModel(
|
||||
it.request.event
|
||||
?.content
|
||||
?.ifBlank { null },
|
||||
showAmountAxis((it.response.event as? LnZapEvent)?.amount),
|
||||
showAmountInteger((it.response.event as? LnZapEvent)?.amount),
|
||||
)
|
||||
}.toMutableMap()
|
||||
|
||||
@ -569,7 +569,7 @@ class AccountViewModel(
|
||||
ZapAmountCommentNotification(
|
||||
LocalCache.getUserIfExists(cachedPrivateRequest.pubKey) ?: it.request.author,
|
||||
cachedPrivateRequest.content.ifBlank { null },
|
||||
showAmountAxis((it.response.event as? LnZapEvent)?.amount),
|
||||
showAmountInteger((it.response.event as? LnZapEvent)?.amount),
|
||||
)
|
||||
} else {
|
||||
ZapAmountCommentNotification(
|
||||
@ -577,7 +577,7 @@ class AccountViewModel(
|
||||
it.request.event
|
||||
?.content
|
||||
?.ifBlank { null },
|
||||
showAmountAxis((it.response.event as? LnZapEvent)?.amount),
|
||||
showAmountInteger((it.response.event as? LnZapEvent)?.amount),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@ -586,7 +586,7 @@ class AccountViewModel(
|
||||
it.request.event
|
||||
?.content
|
||||
?.ifBlank { null },
|
||||
showAmountAxis((it.response.event as? LnZapEvent)?.amount),
|
||||
showAmountInteger((it.response.event as? LnZapEvent)?.amount),
|
||||
)
|
||||
}
|
||||
}.toImmutableList()
|
||||
@ -603,7 +603,7 @@ class AccountViewModel(
|
||||
ZapAmountCommentNotification(
|
||||
LocalCache.getUserIfExists(cachedPrivateRequest.pubKey) ?: it.first.author,
|
||||
cachedPrivateRequest.content.ifBlank { null },
|
||||
showAmountAxis((it.second?.event as? LnZapEvent)?.amount),
|
||||
showAmountInteger((it.second?.event as? LnZapEvent)?.amount),
|
||||
)
|
||||
} else {
|
||||
ZapAmountCommentNotification(
|
||||
@ -611,7 +611,7 @@ class AccountViewModel(
|
||||
it.first.event
|
||||
?.content
|
||||
?.ifBlank { null },
|
||||
showAmountAxis((it.second?.event as? LnZapEvent)?.amount),
|
||||
showAmountInteger((it.second?.event as? LnZapEvent)?.amount),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@ -620,7 +620,7 @@ class AccountViewModel(
|
||||
it.first.event
|
||||
?.content
|
||||
?.ifBlank { null },
|
||||
showAmountAxis((it.second?.event as? LnZapEvent)?.amount),
|
||||
showAmountInteger((it.second?.event as? LnZapEvent)?.amount),
|
||||
)
|
||||
}
|
||||
}.toImmutableList()
|
||||
@ -642,7 +642,7 @@ class AccountViewModel(
|
||||
it.first.event
|
||||
?.content
|
||||
?.ifBlank { null },
|
||||
showAmountAxis((it.second?.event as? LnZapEvent)?.amount),
|
||||
showAmountInteger((it.second?.event as? LnZapEvent)?.amount),
|
||||
)
|
||||
}.toMutableMap()
|
||||
|
||||
@ -687,7 +687,7 @@ class AccountViewModel(
|
||||
ZapAmountCommentNotification(
|
||||
newAuthor,
|
||||
decryptedContent.content.ifBlank { null },
|
||||
showAmountAxis(amount),
|
||||
showAmountInteger(amount),
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -698,7 +698,7 @@ class AccountViewModel(
|
||||
ZapAmountCommentNotification(
|
||||
zapRequest.author,
|
||||
zapRequest.event?.content?.ifBlank { null },
|
||||
showAmountAxis(amount),
|
||||
showAmountInteger(amount),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -22,16 +22,16 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.patrykandpatrick.vico.core.chart.composed.ComposedChartEntryModel
|
||||
import com.patrykandpatrick.vico.core.entry.ChartEntryModel
|
||||
import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer
|
||||
import com.patrykandpatrick.vico.core.entry.composed.plus
|
||||
import com.patrykandpatrick.vico.core.entry.entryOf
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModel
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.LineCartesianLayerModel
|
||||
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
||||
import com.patrykandpatrick.vico.core.common.data.MutableExtraStore
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmountInteger
|
||||
import com.vitorpamplona.amethyst.ui.note.showCount
|
||||
import com.vitorpamplona.ammolite.relays.BundledInsert
|
||||
import com.vitorpamplona.quartz.nip01Core.HexKey
|
||||
@ -52,37 +52,30 @@ import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
val ShowDecimals = ExtraStore.Key<Boolean>()
|
||||
val BottomAxisLabelKey = ExtraStore.Key<List<String>>()
|
||||
|
||||
@Stable
|
||||
class NotificationSummaryState(
|
||||
val account: Account,
|
||||
) {
|
||||
val user: User = account.userProfile()
|
||||
|
||||
private var _reactions = MutableStateFlow<Map<String, Int>>(emptyMap())
|
||||
private var _boosts = MutableStateFlow<Map<String, Int>>(emptyMap())
|
||||
private var _zaps = MutableStateFlow<Map<String, BigDecimal>>(emptyMap())
|
||||
private var _replies = MutableStateFlow<Map<String, Int>>(emptyMap())
|
||||
|
||||
private var _chartModel = MutableStateFlow<ComposedChartEntryModel<ChartEntryModel>?>(null)
|
||||
private var _axisLabels = MutableStateFlow<List<String>>(emptyList())
|
||||
|
||||
val reactions = _reactions.asStateFlow()
|
||||
val boosts = _boosts.asStateFlow()
|
||||
val zaps = _zaps.asStateFlow()
|
||||
val replies = _replies.asStateFlow()
|
||||
private var reactions = MutableStateFlow<Map<String, Int>>(emptyMap())
|
||||
private var boosts = MutableStateFlow<Map<String, Int>>(emptyMap())
|
||||
private var zaps = MutableStateFlow<Map<String, BigDecimal>>(emptyMap())
|
||||
private var replies = MutableStateFlow<Map<String, Int>>(emptyMap())
|
||||
|
||||
private var _chartModel = MutableStateFlow<CartesianChartModel?>(null)
|
||||
val chartModel = _chartModel.asStateFlow()
|
||||
val axisLabels = _axisLabels.asStateFlow()
|
||||
|
||||
private var takenIntoAccount = setOf<HexKey>()
|
||||
private val sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd") // SimpleDateFormat()
|
||||
|
||||
val todaysReplyCount = _replies.map { showCount(it[today()]) }.distinctUntilChanged()
|
||||
val todaysBoostCount = _boosts.map { showCount(it[today()]) }.distinctUntilChanged()
|
||||
val todaysReactionCount = _reactions.map { showCount(it[today()]) }.distinctUntilChanged()
|
||||
val todaysZapAmount = _zaps.map { showAmountAxis(it[today()]) }.distinctUntilChanged()
|
||||
|
||||
var shouldShowDecimalsInAxis = false
|
||||
val todaysReplyCount = replies.map { showCount(it[today()]) }.distinctUntilChanged()
|
||||
val todaysBoostCount = boosts.map { showCount(it[today()]) }.distinctUntilChanged()
|
||||
val todaysReactionCount = reactions.map { showCount(it[today()]) }.distinctUntilChanged()
|
||||
val todaysZapAmount = zaps.map { showAmountInteger(it[today()]) }.distinctUntilChanged()
|
||||
|
||||
fun formatDate(createAt: Long): String =
|
||||
sdf.format(
|
||||
@ -146,10 +139,10 @@ class NotificationSummaryState(
|
||||
}
|
||||
|
||||
this.takenIntoAccount = takenIntoAccount
|
||||
this._reactions.emit(reactions)
|
||||
this._replies.emit(replies)
|
||||
this._zaps.emit(zaps)
|
||||
this._boosts.emit(boosts)
|
||||
this.reactions.emit(reactions)
|
||||
this.replies.emit(replies)
|
||||
this.zaps.emit(zaps)
|
||||
this.boosts.emit(boosts)
|
||||
|
||||
refreshChartModel()
|
||||
}
|
||||
@ -159,10 +152,10 @@ class NotificationSummaryState(
|
||||
|
||||
val currentUser = user.pubkeyHex
|
||||
|
||||
val reactions = this._reactions.value.toMutableMap()
|
||||
val boosts = this._boosts.value.toMutableMap()
|
||||
val zaps = this._zaps.value.toMutableMap()
|
||||
val replies = this._replies.value.toMutableMap()
|
||||
val reactions = this.reactions.value.toMutableMap()
|
||||
val boosts = this.boosts.value.toMutableMap()
|
||||
val zaps = this.zaps.value.toMutableMap()
|
||||
val replies = this.replies.value.toMutableMap()
|
||||
val takenIntoAccount = this.takenIntoAccount.toMutableSet()
|
||||
var hasNewElements = false
|
||||
|
||||
@ -217,10 +210,10 @@ class NotificationSummaryState(
|
||||
|
||||
if (hasNewElements) {
|
||||
this.takenIntoAccount = takenIntoAccount
|
||||
this._reactions.emit(reactions)
|
||||
this._replies.emit(replies)
|
||||
this._zaps.emit(zaps)
|
||||
this._boosts.emit(boosts)
|
||||
this.reactions.emit(reactions)
|
||||
this.replies.emit(replies)
|
||||
this.zaps.emit(zaps)
|
||||
this.boosts.emit(boosts)
|
||||
|
||||
refreshChartModel()
|
||||
}
|
||||
@ -229,59 +222,42 @@ class NotificationSummaryState(
|
||||
private suspend fun refreshChartModel() {
|
||||
checkNotInMainThread()
|
||||
|
||||
val day = 24 * 60 * 60L
|
||||
val now = LocalDateTime.now()
|
||||
val displayAxisFormatter = DateTimeFormatter.ofPattern("EEE")
|
||||
|
||||
val dataAxisLabels = listOf(6, 5, 4, 3, 2, 1, 0).map { sdf.format(now.minusSeconds(day * it)) }
|
||||
val dataAxisLabelIndexes = listOf(-6, -5, -4, -3, -2, -1, 0)
|
||||
val dataAxisLabels = dataAxisLabelIndexes.map { sdf.format(now.plusDays(it.toLong())) }
|
||||
|
||||
val listOfCountCurves =
|
||||
listOf(
|
||||
dataAxisLabels.mapIndexed { index, dateStr ->
|
||||
entryOf(index, _replies.value[dateStr]?.toFloat() ?: 0f)
|
||||
},
|
||||
dataAxisLabels.mapIndexed { index, dateStr ->
|
||||
entryOf(index, _boosts.value[dateStr]?.toFloat() ?: 0f)
|
||||
},
|
||||
dataAxisLabels.mapIndexed { index, dateStr ->
|
||||
entryOf(index, _reactions.value[dateStr]?.toFloat() ?: 0f)
|
||||
},
|
||||
)
|
||||
|
||||
val listOfValueCurves =
|
||||
listOf(
|
||||
dataAxisLabels.mapIndexed { index, dateStr ->
|
||||
entryOf(index, _zaps.value[dateStr]?.toFloat() ?: 0f)
|
||||
},
|
||||
)
|
||||
|
||||
val chartEntryModelProducer1 = ChartEntryModelProducer(listOfCountCurves).getModel()
|
||||
val chartEntryModelProducer2 = ChartEntryModelProducer(listOfValueCurves).getModel()
|
||||
|
||||
chartEntryModelProducer1?.let { chart1 ->
|
||||
chartEntryModelProducer2?.let { chart2 ->
|
||||
this.shouldShowDecimalsInAxis = shouldShowDecimals(chart2.minY, chart2.maxY)
|
||||
|
||||
this._axisLabels.emit(
|
||||
listOf(6, 5, 4, 3, 2, 1, 0).map {
|
||||
displayAxisFormatter.format(now.minusSeconds(day * it))
|
||||
},
|
||||
)
|
||||
this._chartModel.emit(chart1.plus(chart2))
|
||||
val chart1 =
|
||||
LineCartesianLayerModel.build {
|
||||
series(dataAxisLabelIndexes, dataAxisLabels.map { replies.value[it]?.toFloat() ?: 0f })
|
||||
series(dataAxisLabelIndexes, dataAxisLabels.map { boosts.value[it]?.toFloat() ?: 0f })
|
||||
series(dataAxisLabelIndexes, dataAxisLabels.map { reactions.value[it]?.toFloat() ?: 0f })
|
||||
}
|
||||
}
|
||||
|
||||
val chart2 =
|
||||
LineCartesianLayerModel.build {
|
||||
series(dataAxisLabelIndexes, dataAxisLabels.map { zaps.value[it]?.toFloat() ?: 0f })
|
||||
}
|
||||
|
||||
val model = CartesianChartModel(chart1, chart2)
|
||||
|
||||
val mutableStore = MutableExtraStore()
|
||||
|
||||
mutableStore[ShowDecimals] = shouldShowDecimals(chart2.minY, chart2.maxY)
|
||||
|
||||
this._chartModel.emit(model.copy(mutableStore))
|
||||
}
|
||||
|
||||
// determine if the min max are so close that they render to the same number.
|
||||
fun shouldShowDecimals(
|
||||
min: Float,
|
||||
max: Float,
|
||||
min: Double,
|
||||
max: Double,
|
||||
): Boolean {
|
||||
val step = (max - min) / 8
|
||||
|
||||
var previous = showAmountAxis(min.toBigDecimal())
|
||||
var previous = showAmountInteger(min.toBigDecimal())
|
||||
for (i in 1..7) {
|
||||
val current = showAmountAxis((min + (i * step)).toBigDecimal())
|
||||
val current = showAmountInteger((min + (i * step)).toBigDecimal())
|
||||
if (previous == current) {
|
||||
return true
|
||||
}
|
||||
|
@ -30,47 +30,17 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.patrykandpatrick.vico.compose.axis.axisLabelComponent
|
||||
import com.patrykandpatrick.vico.compose.axis.horizontal.rememberBottomAxis
|
||||
import com.patrykandpatrick.vico.compose.axis.vertical.rememberEndAxis
|
||||
import com.patrykandpatrick.vico.compose.axis.vertical.rememberStartAxis
|
||||
import com.patrykandpatrick.vico.compose.chart.Chart
|
||||
import com.patrykandpatrick.vico.compose.chart.line.lineChart
|
||||
import com.patrykandpatrick.vico.compose.component.shape.shader.fromBrush
|
||||
import com.patrykandpatrick.vico.compose.style.ProvideChartStyle
|
||||
import com.patrykandpatrick.vico.core.DefaultAlpha
|
||||
import com.patrykandpatrick.vico.core.axis.AxisPosition
|
||||
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
|
||||
import com.patrykandpatrick.vico.core.chart.composed.plus
|
||||
import com.patrykandpatrick.vico.core.chart.line.LineChart
|
||||
import com.patrykandpatrick.vico.core.chart.values.ChartValues
|
||||
import com.patrykandpatrick.vico.core.component.shape.shader.DynamicShaders
|
||||
import com.vitorpamplona.amethyst.ui.note.OneGiga
|
||||
import com.vitorpamplona.amethyst.ui.note.OneKilo
|
||||
import com.vitorpamplona.amethyst.ui.note.OneMega
|
||||
import com.vitorpamplona.amethyst.ui.note.TenKilo
|
||||
import com.patrykandpatrick.vico.compose.common.ProvideVicoTheme
|
||||
import com.vitorpamplona.amethyst.ui.note.UserReactionsRow
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||
import com.vitorpamplona.amethyst.ui.note.showCount
|
||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||
import com.vitorpamplona.amethyst.ui.theme.RoyalBlue
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.chart.ShowChart
|
||||
import com.vitorpamplona.amethyst.ui.theme.chartStyle
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
fun SummaryBar(state: NotificationSummaryState) {
|
||||
@ -83,137 +53,24 @@ fun SummaryBar(state: NotificationSummaryState) {
|
||||
enter = slideInVertically() + expandVertically(),
|
||||
exit = slideOutVertically() + shrinkVertically(),
|
||||
) {
|
||||
val lineChartCount =
|
||||
lineChart(
|
||||
lines =
|
||||
listOf(RoyalBlue, Color.Green, Color.Red).map { lineChartColor ->
|
||||
LineChart.LineSpec(
|
||||
lineColor = lineChartColor.toArgb(),
|
||||
lineBackgroundShader =
|
||||
DynamicShaders.fromBrush(
|
||||
Brush.verticalGradient(
|
||||
listOf(
|
||||
lineChartColor.copy(DefaultAlpha.LINE_BACKGROUND_SHADER_START),
|
||||
lineChartColor.copy(DefaultAlpha.LINE_BACKGROUND_SHADER_END),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
targetVerticalAxisPosition = AxisPosition.Vertical.Start,
|
||||
)
|
||||
|
||||
val lineChartZaps =
|
||||
lineChart(
|
||||
lines =
|
||||
listOf(BitcoinOrange).map { lineChartColor ->
|
||||
LineChart.LineSpec(
|
||||
lineColor = lineChartColor.toArgb(),
|
||||
lineBackgroundShader =
|
||||
DynamicShaders.fromBrush(
|
||||
Brush.verticalGradient(
|
||||
listOf(
|
||||
lineChartColor.copy(DefaultAlpha.LINE_BACKGROUND_SHADER_START),
|
||||
lineChartColor.copy(DefaultAlpha.LINE_BACKGROUND_SHADER_END),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
targetVerticalAxisPosition = AxisPosition.Vertical.End,
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(vertical = 0.dp, horizontal = 20.dp)
|
||||
.clickable(onClick = { showChart = !showChart }),
|
||||
) {
|
||||
ProvideChartStyle(
|
||||
chartStyle = MaterialTheme.colorScheme.chartStyle,
|
||||
) {
|
||||
ObserveAndShowChart(state, lineChartCount, lineChartZaps)
|
||||
ProvideVicoTheme(MaterialTheme.colorScheme.chartStyle) {
|
||||
ObserveAndShowChart(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ObserveAndShowChart(
|
||||
state: NotificationSummaryState,
|
||||
lineChartCount: LineChart,
|
||||
lineChartZaps: LineChart,
|
||||
) {
|
||||
val axisModel = state.axisLabels.collectAsStateWithLifecycle()
|
||||
private fun ObserveAndShowChart(state: NotificationSummaryState) {
|
||||
val chartModel by state.chartModel.collectAsStateWithLifecycle()
|
||||
|
||||
chartModel?.let {
|
||||
Chart(
|
||||
chart = remember(lineChartCount, lineChartZaps) { lineChartCount.plus(lineChartZaps) },
|
||||
model = it,
|
||||
startAxis =
|
||||
rememberStartAxis(
|
||||
valueFormatter = CountAxisValueFormatter(),
|
||||
),
|
||||
endAxis =
|
||||
rememberEndAxis(
|
||||
label = axisLabelComponent(color = BitcoinOrange),
|
||||
valueFormatter = AmountAxisValueFormatter(state.shouldShowDecimalsInAxis),
|
||||
),
|
||||
bottomAxis =
|
||||
rememberBottomAxis(
|
||||
valueFormatter = LabelValueFormatter(axisModel),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class LabelValueFormatter(
|
||||
val axisLabels: State<List<String>>,
|
||||
) : AxisValueFormatter<AxisPosition.Horizontal.Bottom> {
|
||||
override fun formatValue(
|
||||
value: Float,
|
||||
chartValues: ChartValues,
|
||||
): String = axisLabels.value[value.roundToInt()]
|
||||
}
|
||||
|
||||
@Stable
|
||||
class CountAxisValueFormatter : AxisValueFormatter<AxisPosition.Vertical.Start> {
|
||||
override fun formatValue(
|
||||
value: Float,
|
||||
chartValues: ChartValues,
|
||||
): String = showCount(value.roundToInt())
|
||||
}
|
||||
|
||||
@Stable
|
||||
class AmountAxisValueFormatter(
|
||||
val showDecimals: Boolean,
|
||||
) : AxisValueFormatter<AxisPosition.Vertical.End> {
|
||||
override fun formatValue(
|
||||
value: Float,
|
||||
chartValues: ChartValues,
|
||||
): String =
|
||||
if (showDecimals) {
|
||||
showAmount(value.toBigDecimal())
|
||||
} else {
|
||||
showAmountAxis(value.toBigDecimal())
|
||||
}
|
||||
}
|
||||
|
||||
var dfG: DecimalFormat = DecimalFormat("#G")
|
||||
var dfM: DecimalFormat = DecimalFormat("#M")
|
||||
var dfK: DecimalFormat = DecimalFormat("#k")
|
||||
var dfN: DecimalFormat = DecimalFormat("#")
|
||||
|
||||
fun showAmountAxis(amount: BigDecimal?): String {
|
||||
if (amount == null) return ""
|
||||
if (amount.abs() < BigDecimal(0.01)) return ""
|
||||
|
||||
return when {
|
||||
amount >= OneGiga -> dfG.format(amount.div(OneGiga).setScale(0, RoundingMode.HALF_UP))
|
||||
amount >= OneMega -> dfM.format(amount.div(OneMega).setScale(0, RoundingMode.HALF_UP))
|
||||
amount >= TenKilo -> dfK.format(amount.div(OneKilo).setScale(0, RoundingMode.HALF_UP))
|
||||
else -> dfN.format(amount)
|
||||
ShowChart(it)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.chart
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.patrykandpatrick.vico.core.cartesian.CartesianMeasuringContext
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.Axis
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmountIntegerWithZero
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmountWithZero
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.ShowDecimals
|
||||
|
||||
@Stable
|
||||
class AmountValueFormatter : CartesianValueFormatter {
|
||||
override fun format(
|
||||
context: CartesianMeasuringContext,
|
||||
value: Double,
|
||||
verticalAxisPosition: Axis.Position.Vertical?,
|
||||
): CharSequence =
|
||||
if (context.model.extraStore[ShowDecimals]) {
|
||||
showAmountWithZero(value.toBigDecimal())
|
||||
} else {
|
||||
showAmountIntegerWithZero(value.toBigDecimal())
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.chart
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.patrykandpatrick.vico.core.cartesian.CartesianMeasuringContext
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.Axis
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Stable
|
||||
class CountAxisValueFormatter : CartesianValueFormatter {
|
||||
private fun showCountChart(count: Int?): String {
|
||||
if (count == null) return "0"
|
||||
|
||||
return when {
|
||||
count >= 1000000000 -> "${(count / 1000000000f).roundToInt()}G"
|
||||
count >= 1000000 -> "${(count / 1000000f).roundToInt()}M"
|
||||
count >= 10000 -> "${(count / 1000f).roundToInt()}k"
|
||||
else -> "$count"
|
||||
}
|
||||
}
|
||||
|
||||
override fun format(
|
||||
context: CartesianMeasuringContext,
|
||||
value: Double,
|
||||
verticalAxisPosition: Axis.Position.Vertical?,
|
||||
): CharSequence = showCountChart(value.roundToInt())
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.chart
|
||||
|
||||
import android.util.LruCache
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.patrykandpatrick.vico.core.cartesian.CartesianMeasuringContext
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.Axis
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Stable
|
||||
class LastWeekLabelFormatter : CartesianValueFormatter {
|
||||
private val displayAxisFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("EEE")
|
||||
private val now = LocalDateTime.now()
|
||||
|
||||
private val cache = LruCache<Int, String>(10)
|
||||
|
||||
override fun format(
|
||||
context: CartesianMeasuringContext,
|
||||
value: Double,
|
||||
verticalAxisPosition: Axis.Position.Vertical?,
|
||||
): CharSequence {
|
||||
val key = value.roundToInt()
|
||||
cache[key]?.let { return it }
|
||||
|
||||
val text = displayAxisFormatter.format(now.plusDays(key.toLong()))
|
||||
cache.put(key, text)
|
||||
return text
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.chart
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
|
||||
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisLabelComponent
|
||||
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottom
|
||||
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberEnd
|
||||
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStart
|
||||
import com.patrykandpatrick.vico.compose.cartesian.rememberCartesianChart
|
||||
import com.patrykandpatrick.vico.compose.common.fill
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.Axis
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.HorizontalAxis
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.VerticalAxis
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModel
|
||||
import com.patrykandpatrick.vico.core.cartesian.layer.LineCartesianLayer
|
||||
import com.patrykandpatrick.vico.core.common.shader.ShaderProvider
|
||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||
import com.vitorpamplona.amethyst.ui.theme.RoyalBlue
|
||||
|
||||
fun makeLine(color: Color): LineCartesianLayer.Line =
|
||||
LineCartesianLayer.Line(
|
||||
fill = LineCartesianLayer.LineFill.single(fill(color)),
|
||||
areaFill =
|
||||
LineCartesianLayer.AreaFill.single(
|
||||
fill(
|
||||
ShaderProvider.verticalGradient(
|
||||
color.copy(alpha = 0.4f).toArgb(),
|
||||
Color.Transparent.toArgb(),
|
||||
),
|
||||
),
|
||||
),
|
||||
pointConnector = LineCartesianLayer.PointConnector.cubic(),
|
||||
)
|
||||
|
||||
val chartLayers =
|
||||
arrayOf(
|
||||
LineCartesianLayer(
|
||||
LineCartesianLayer.LineProvider.series(
|
||||
makeLine(RoyalBlue),
|
||||
makeLine(Color.Green),
|
||||
makeLine(Color.Red),
|
||||
),
|
||||
verticalAxisPosition = Axis.Position.Vertical.Start,
|
||||
),
|
||||
LineCartesianLayer(
|
||||
LineCartesianLayer.LineProvider.series(
|
||||
makeLine(BitcoinOrange),
|
||||
),
|
||||
verticalAxisPosition = Axis.Position.Vertical.End,
|
||||
),
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun ShowChart(model: CartesianChartModel) {
|
||||
val chart =
|
||||
rememberCartesianChart(
|
||||
layers = chartLayers,
|
||||
startAxis =
|
||||
VerticalAxis.rememberStart(
|
||||
valueFormatter = CountAxisValueFormatter(),
|
||||
itemPlacer = VerticalAxis.ItemPlacer.count({ 7 }),
|
||||
),
|
||||
endAxis =
|
||||
VerticalAxis.rememberEnd(
|
||||
label = rememberAxisLabelComponent(color = BitcoinOrange),
|
||||
valueFormatter = AmountValueFormatter(),
|
||||
itemPlacer = VerticalAxis.ItemPlacer.count({ 7 }),
|
||||
),
|
||||
bottomAxis =
|
||||
HorizontalAxis.rememberBottom(
|
||||
valueFormatter = LastWeekLabelFormatter(),
|
||||
),
|
||||
)
|
||||
|
||||
CartesianChartHost(
|
||||
chart = chart,
|
||||
model = model,
|
||||
)
|
||||
}
|
@ -145,6 +145,7 @@ import com.vitorpamplona.amethyst.ui.note.LightningAddressIcon
|
||||
import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote
|
||||
import com.vitorpamplona.amethyst.ui.note.externalLinkForUser
|
||||
import com.vitorpamplona.amethyst.ui.note.payViaIntent
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmountInteger
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrUserAppRecommendationsFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrUserProfileBookmarksFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrUserProfileConversationsFeedViewModel
|
||||
@ -159,7 +160,6 @@ import com.vitorpamplona.amethyst.ui.screen.SaveableGridFeedState
|
||||
import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.HashtagHeader
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.showAmountAxis
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.gallery.RenderGalleryFeed
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.ShowQRDialog
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
@ -729,7 +729,7 @@ private fun ZapTabHeader(baseUser: User) {
|
||||
}
|
||||
}
|
||||
|
||||
Text(text = "${showAmountAxis(zapAmount)} ${stringRes(id = R.string.zaps)}")
|
||||
Text(text = "${showAmountInteger(zapAmount)} ${stringRes(id = R.string.zaps)}")
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -58,8 +58,8 @@ import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.halilibo.richtext.ui.RichTextStyle
|
||||
import com.halilibo.richtext.ui.resolveDefaults
|
||||
import com.patrykandpatrick.vico.compose.style.ChartStyle
|
||||
import com.patrykandpatrick.vico.core.DefaultColors
|
||||
import com.patrykandpatrick.vico.compose.common.VicoTheme
|
||||
import com.patrykandpatrick.vico.compose.common.VicoTheme.CandlestickCartesianLayerColors
|
||||
import com.vitorpamplona.amethyst.model.ThemeType
|
||||
import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel
|
||||
|
||||
@ -441,22 +441,34 @@ val ColorScheme.largeRelayIconModifier: Modifier
|
||||
val ColorScheme.selectedReactionBoxModifier: Modifier
|
||||
get() = if (isLight) LightSelectedReactionBoxModifier else DarkSelectedReactionBoxModifier
|
||||
|
||||
val ColorScheme.chartStyle: ChartStyle
|
||||
get() {
|
||||
val defaultColors = if (isLight) DefaultColors.Light else DefaultColors.Dark
|
||||
return ChartStyle.fromColors(
|
||||
axisLabelColor = Color(defaultColors.axisLabelColor),
|
||||
axisGuidelineColor = Color(defaultColors.axisGuidelineColor),
|
||||
axisLineColor = Color(defaultColors.axisLineColor),
|
||||
entityColors =
|
||||
listOf(
|
||||
defaultColors.entity1Color,
|
||||
defaultColors.entity2Color,
|
||||
defaultColors.entity3Color,
|
||||
).map(::Color),
|
||||
elevationOverlayColor = Color(defaultColors.elevationOverlayColor),
|
||||
)
|
||||
}
|
||||
val chartLightColors =
|
||||
VicoTheme(
|
||||
candlestickCartesianLayerColors =
|
||||
CandlestickCartesianLayerColors(
|
||||
Color(0xff0ac285),
|
||||
Color(0xff000000),
|
||||
Color(0xffe8304f),
|
||||
),
|
||||
columnCartesianLayerColors = listOf(Color(0xff3287ff), Color(0xff0ac285), Color(0xffffab02)),
|
||||
lineColor = Color(0xffbcbfc2),
|
||||
textColor = Color(0xff000000),
|
||||
)
|
||||
|
||||
val chartDarkColors =
|
||||
VicoTheme(
|
||||
candlestickCartesianLayerColors =
|
||||
CandlestickCartesianLayerColors(
|
||||
Color(0xff0ac285),
|
||||
Color(0xffffffff),
|
||||
Color(0xffe8304f),
|
||||
),
|
||||
columnCartesianLayerColors = listOf(Color(0xff3287ff), Color(0xff0ac285), Color(0xffffab02)),
|
||||
lineColor = Color(0xff494c50),
|
||||
textColor = Color(0xffffffff),
|
||||
)
|
||||
|
||||
val ColorScheme.chartStyle: VicoTheme
|
||||
get() = if (isLight) chartLightColors else chartDarkColors
|
||||
|
||||
@Composable
|
||||
fun AmethystTheme(
|
||||
|
@ -46,7 +46,7 @@ torAndroid = "0.4.8.12"
|
||||
translate = "17.0.3"
|
||||
unifiedpush = "2.3.1"
|
||||
urlDetector = "0.1.23"
|
||||
vico-charts = "1.16.0"
|
||||
vico-charts = "2.0.1"
|
||||
zelory = "3.0.1"
|
||||
zoomable = "2.0.0"
|
||||
zxing = "3.5.3"
|
||||
|
Loading…
x
Reference in New Issue
Block a user