Additive rendering of statistics
This commit is contained in:
@@ -8,6 +8,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
@@ -18,6 +19,7 @@ import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.dal.VideoFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrGlobalFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel
|
||||
@@ -37,6 +39,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.ProfileScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ThreadScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.VideoScreen
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
@@ -50,7 +54,8 @@ fun AppNavigation(
|
||||
|
||||
// Avoids creating ViewModels for performance reasons (up to 1 second delays)
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
val account = remember(accountState) { accountState?.account } ?: return
|
||||
val accountHex = remember(accountState) { accountState?.account?.userProfile()?.pubkeyHex }
|
||||
|
||||
HomeNewThreadFeedFilter.account = account
|
||||
HomeConversationsFeedFilter.account = account
|
||||
@@ -67,6 +72,16 @@ fun AppNavigation(
|
||||
NotificationFeedFilter.account = account
|
||||
val notifFeedViewModel: NotificationViewModel = viewModel()
|
||||
|
||||
val userReactionsStatsModel: UserReactionsViewModel = viewModel()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(accountHex) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
userReactionsStatsModel.load(account.userProfile())
|
||||
userReactionsStatsModel.initializeSuspend()
|
||||
}
|
||||
}
|
||||
|
||||
NavHost(navController, startDestination = Route.Home.route) {
|
||||
Route.Video.let { route ->
|
||||
composable(route.route, route.arguments, content = {
|
||||
@@ -135,6 +150,7 @@ fun AppNavigation(
|
||||
|
||||
NotificationScreen(
|
||||
notifFeedViewModel = notifFeedViewModel,
|
||||
userReactionsStatsModel = userReactionsStatsModel,
|
||||
accountViewModel = accountViewModel,
|
||||
navController = navController,
|
||||
scrollToTop = scrollToTop
|
||||
|
||||
@@ -25,8 +25,15 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.NavController
|
||||
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.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.HexKey
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.model.LnZapEvent
|
||||
import com.vitorpamplona.amethyst.service.model.ReactionEvent
|
||||
@@ -34,7 +41,6 @@ import com.vitorpamplona.amethyst.service.model.RepostEvent
|
||||
import com.vitorpamplona.amethyst.service.model.TextNoteEvent
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -63,7 +69,7 @@ fun UserReactionsRow(model: UserReactionsViewModel, accountViewModel: AccountVie
|
||||
}
|
||||
|
||||
Row(verticalAlignment = CenterVertically, modifier = Modifier.weight(1f)) {
|
||||
UserLikeReaction(model.replies[model.today])
|
||||
UserLikeReaction(model.reactions[model.today])
|
||||
}
|
||||
|
||||
Row(verticalAlignment = CenterVertically, modifier = Modifier.weight(1f)) {
|
||||
@@ -80,22 +86,21 @@ class UserReactionsViewModel : ViewModel() {
|
||||
var zaps by mutableStateOf<Map<String, BigDecimal>>(emptyMap())
|
||||
var replies by mutableStateOf<Map<String, Int>>(emptyMap())
|
||||
|
||||
var takenIntoAccount = setOf<HexKey>()
|
||||
|
||||
val sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd") // SimpleDateFormat()
|
||||
val today = sdf.format(LocalDateTime.now())
|
||||
|
||||
var chartModel by mutableStateOf<ComposedChartEntryModel<ChartEntryModel>?>(null)
|
||||
var axisLabels by mutableStateOf<List<String>>(emptyList())
|
||||
|
||||
fun load(baseUser: User) {
|
||||
user = baseUser
|
||||
reactions = emptyMap()
|
||||
boosts = emptyMap()
|
||||
zaps = emptyMap()
|
||||
replies = emptyMap()
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
scope.launch {
|
||||
refreshSuspended()
|
||||
}
|
||||
takenIntoAccount = emptySet()
|
||||
}
|
||||
|
||||
fun formatDate(createAt: Long): String {
|
||||
@@ -106,46 +111,133 @@ class UserReactionsViewModel : ViewModel() {
|
||||
)
|
||||
}
|
||||
|
||||
fun refreshSuspended() {
|
||||
fun initializeSuspend() {
|
||||
val currentUser = user?.pubkeyHex ?: return
|
||||
|
||||
val reactions = mutableMapOf<String, Int>()
|
||||
val boosts = mutableMapOf<String, Int>()
|
||||
val zaps = mutableMapOf<String, BigDecimal>()
|
||||
val replies = mutableMapOf<String, Int>()
|
||||
val takenIntoAccount = mutableSetOf<HexKey>()
|
||||
|
||||
LocalCache.notes.values.forEach {
|
||||
val noteEvent = it.event
|
||||
if (noteEvent is ReactionEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser)) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
reactions[netDate] = (reactions[netDate] ?: 0) + 1
|
||||
}
|
||||
}
|
||||
if (noteEvent is RepostEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser)) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
boosts[netDate] = (boosts[netDate] ?: 0) + 1
|
||||
}
|
||||
}
|
||||
if (noteEvent is LnZapEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser)) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + (noteEvent.amount ?: BigDecimal.ZERO)
|
||||
}
|
||||
}
|
||||
if (noteEvent is TextNoteEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser)) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
replies[netDate] = (replies[netDate] ?: 0) + 1
|
||||
if (noteEvent != null && !takenIntoAccount.contains(noteEvent.id())) {
|
||||
if (noteEvent is ReactionEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
reactions[netDate] = (reactions[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
}
|
||||
} else if (noteEvent is RepostEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
boosts[netDate] = (boosts[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
}
|
||||
} else if (noteEvent is LnZapEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + (noteEvent.amount ?: BigDecimal.ZERO)
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
}
|
||||
} else if (noteEvent is TextNoteEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
replies[netDate] = (replies[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.takenIntoAccount = takenIntoAccount
|
||||
this.reactions = reactions
|
||||
this.replies = replies
|
||||
this.zaps = zaps
|
||||
this.boosts = boosts
|
||||
|
||||
refreshChartModel()
|
||||
}
|
||||
|
||||
fun addToStatsSuspend(newNotes: Set<Note>) {
|
||||
val currentUser = user?.pubkeyHex ?: return
|
||||
|
||||
val reactions = this.reactions.toMutableMap()
|
||||
val boosts = this.boosts.toMutableMap()
|
||||
val zaps = this.zaps.toMutableMap()
|
||||
val replies = this.replies.toMutableMap()
|
||||
val takenIntoAccount = this.takenIntoAccount.toMutableSet()
|
||||
var hasNewElements = false
|
||||
|
||||
newNotes.forEach {
|
||||
val noteEvent = it.event
|
||||
if (noteEvent != null && !takenIntoAccount.contains(noteEvent.id())) {
|
||||
if (noteEvent is ReactionEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
reactions[netDate] = (reactions[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
hasNewElements = true
|
||||
}
|
||||
} else if (noteEvent is RepostEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
boosts[netDate] = (boosts[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
hasNewElements = true
|
||||
}
|
||||
} else if (noteEvent is LnZapEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
zaps[netDate] = (zaps[netDate] ?: BigDecimal.ZERO) + (noteEvent.amount ?: BigDecimal.ZERO)
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
hasNewElements = true
|
||||
}
|
||||
} else if (noteEvent is TextNoteEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
replies[netDate] = (replies[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
hasNewElements = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNewElements) {
|
||||
this.takenIntoAccount = takenIntoAccount
|
||||
this.reactions = reactions
|
||||
this.replies = replies
|
||||
this.zaps = zaps
|
||||
this.boosts = boosts
|
||||
|
||||
refreshChartModel()
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshChartModel() {
|
||||
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 listOfCountCurves = listOf(
|
||||
dataAxisLabels.mapIndexed { index, dateStr -> entryOf(index, replies[dateStr]?.toFloat() ?: 0f) },
|
||||
dataAxisLabels.mapIndexed { index, dateStr -> entryOf(index, boosts[dateStr]?.toFloat() ?: 0f) },
|
||||
dataAxisLabels.mapIndexed { index, dateStr -> entryOf(index, reactions[dateStr]?.toFloat() ?: 0f) }
|
||||
)
|
||||
|
||||
val listOfValueCurves = listOf(
|
||||
dataAxisLabels.mapIndexed { index, dateStr -> entryOf(index, zaps[dateStr]?.toFloat() ?: 0f) }
|
||||
)
|
||||
|
||||
val chartEntryModelProducer1 = ChartEntryModelProducer(listOfCountCurves).getModel()
|
||||
val chartEntryModelProducer2 = ChartEntryModelProducer(listOfValueCurves).getModel()
|
||||
|
||||
this.axisLabels = listOf(6, 5, 4, 3, 2, 1, 0).map { displayAxisFormatter.format(now.minusSeconds(day * it)) }
|
||||
this.chartModel = chartEntryModelProducer1.plus(chartEntryModelProducer2)
|
||||
}
|
||||
|
||||
var collectorJob: Job? = null
|
||||
@@ -153,7 +245,7 @@ class UserReactionsViewModel : ViewModel() {
|
||||
init {
|
||||
collectorJob = viewModelScope.launch(Dispatchers.IO) {
|
||||
LocalCache.live.newEventBundles.collect { newNotes ->
|
||||
refresh()
|
||||
addToStatsSuspend(newNotes)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +283,7 @@ fun UserBoostReaction(
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_retweeted),
|
||||
null,
|
||||
modifier = Modifier.size(20.dp),
|
||||
modifier = Modifier.size(24.dp),
|
||||
tint = Color.Unspecified
|
||||
)
|
||||
|
||||
@@ -231,7 +323,7 @@ fun UserZapReaction(
|
||||
Icon(
|
||||
imageVector = Icons.Default.Bolt,
|
||||
contentDescription = stringResource(R.string.zaps),
|
||||
modifier = Modifier.size(20.dp),
|
||||
modifier = Modifier.size(24.dp),
|
||||
tint = BitcoinOrange
|
||||
)
|
||||
|
||||
|
||||
+28
-53
@@ -13,7 +13,6 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
@@ -35,34 +34,32 @@ 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.ComposedChartEntryModel
|
||||
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.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.vitorpamplona.amethyst.service.NostrAccountDataSource
|
||||
import com.vitorpamplona.amethyst.ui.dal.NotificationFeedFilter
|
||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||
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.UserReactionsRow
|
||||
import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel
|
||||
import com.vitorpamplona.amethyst.ui.note.showAmount
|
||||
import com.vitorpamplona.amethyst.ui.note.showCount
|
||||
import com.vitorpamplona.amethyst.ui.screen.CardFeedView
|
||||
import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
fun NotificationScreen(
|
||||
notifFeedViewModel: NotificationViewModel,
|
||||
userReactionsStatsModel: UserReactionsViewModel,
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavController,
|
||||
scrollToTop: Boolean = false
|
||||
@@ -100,7 +97,7 @@ fun NotificationScreen(
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
SummaryBar(accountViewModel, navController)
|
||||
SummaryBar(userReactionsStatsModel, accountViewModel, navController)
|
||||
CardFeedView(
|
||||
viewModel = notifFeedViewModel,
|
||||
accountViewModel = accountViewModel,
|
||||
@@ -114,49 +111,11 @@ fun NotificationScreen(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SummaryBar(accountViewModel: AccountViewModel, navController: NavController) {
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val accountUser = remember(accountState) { accountState?.account?.userProfile() } ?: return
|
||||
|
||||
val model: UserReactionsViewModel = viewModel()
|
||||
|
||||
var chartModel by remember(accountState) { mutableStateOf<ComposedChartEntryModel<ChartEntryModel>?>(null) }
|
||||
var axisLabels by remember(accountState) { mutableStateOf<List<String>>(emptyList()) }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
fun SummaryBar(model: UserReactionsViewModel, accountViewModel: AccountViewModel, navController: NavController) {
|
||||
var showChart by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
LaunchedEffect(accountUser.pubkeyHex) {
|
||||
scope.launch {
|
||||
model.load(accountUser)
|
||||
model.refreshSuspended()
|
||||
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 { model.sdf.format(now.minusSeconds(day * it)) }
|
||||
axisLabels = listOf(6, 5, 4, 3, 2, 1, 0).map { displayAxisFormatter.format(now.minusSeconds(day * it)) }
|
||||
|
||||
val listOfCountCurves = listOf(
|
||||
dataAxisLabels.mapIndexed { index, dateStr -> entryOf(index, model.replies[dateStr]?.toFloat() ?: 0f) },
|
||||
dataAxisLabels.mapIndexed { index, dateStr -> entryOf(index, model.boosts[dateStr]?.toFloat() ?: 0f) },
|
||||
dataAxisLabels.mapIndexed { index, dateStr -> entryOf(index, model.reactions[dateStr]?.toFloat() ?: 0f) }
|
||||
)
|
||||
|
||||
val listOfValueCurves = listOf(
|
||||
dataAxisLabels.mapIndexed { index, dateStr -> entryOf(index, model.zaps[dateStr]?.toFloat() ?: 0f) }
|
||||
)
|
||||
|
||||
val chartEntryModelProducer1 = ChartEntryModelProducer(listOfCountCurves).getModel()
|
||||
val chartEntryModelProducer2 = ChartEntryModelProducer(listOfValueCurves).getModel()
|
||||
|
||||
chartModel = chartEntryModelProducer1.plus(chartEntryModelProducer2)
|
||||
}
|
||||
}
|
||||
|
||||
UserReactionsRow(model, accountViewModel, navController) {
|
||||
showChart = !showChart
|
||||
}
|
||||
@@ -197,9 +156,13 @@ fun SummaryBar(accountViewModel: AccountViewModel, navController: NavController)
|
||||
targetVerticalAxisPosition = AxisPosition.Vertical.End
|
||||
)
|
||||
|
||||
chartModel?.let {
|
||||
model.chartModel?.let {
|
||||
if (showChart) {
|
||||
Row(modifier = Modifier.padding(vertical = 10.dp, horizontal = 20.dp).clickable(onClick = { showChart = !showChart })) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 10.dp, horizontal = 20.dp)
|
||||
.clickable(onClick = { showChart = !showChart })
|
||||
) {
|
||||
ProvideChartStyle() {
|
||||
Chart(
|
||||
chart = remember(lineChartCount, lineChartZaps) {
|
||||
@@ -213,7 +176,7 @@ fun SummaryBar(accountViewModel: AccountViewModel, navController: NavController)
|
||||
valueFormatter = AmountAxisValueFormatter()
|
||||
),
|
||||
bottomAxis = bottomAxis(
|
||||
valueFormatter = LabelValueFormatter(axisLabels)
|
||||
valueFormatter = LabelValueFormatter(model.axisLabels)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -249,6 +212,18 @@ class AmountAxisValueFormatter() : AxisValueFormatter<AxisPosition.Vertical.End>
|
||||
value: Float,
|
||||
chartValues: ChartValues
|
||||
): String {
|
||||
return showAmount(value.toBigDecimal())
|
||||
return showAmountAxis(value.toBigDecimal())
|
||||
}
|
||||
}
|
||||
|
||||
fun showAmountAxis(amount: BigDecimal?): String {
|
||||
if (amount == null) return ""
|
||||
if (amount.abs() < BigDecimal(0.01)) return ""
|
||||
|
||||
return when {
|
||||
amount >= OneGiga -> "%.0fG".format(amount.div(OneGiga).setScale(0, RoundingMode.HALF_UP))
|
||||
amount >= OneMega -> "%.0fM".format(amount.div(OneMega).setScale(0, RoundingMode.HALF_UP))
|
||||
amount >= OneKilo -> "%.0fk".format(amount.div(OneKilo).setScale(0, RoundingMode.HALF_UP))
|
||||
else -> "%.0f".format(amount)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user