From 09871e8727bf0630008d377edbdf29bf4634a6a5 Mon Sep 17 00:00:00 2001 From: b3s23 Date: Fri, 7 Mar 2025 18:10:43 +0500 Subject: [PATCH] Fixed the design, added full color schemes for light and dark themes. Fixed number formatting with bitcoin data, as well as the line chart being fully visible on the vertical axis now! :3 --- .idea/misc.xml | 1 - .../bitcoin_summarizer/GlobalResponse.kt | 2 +- .../bitcoin_summarizer/MainActivity.kt | 109 +++++++++++++----- .../bitcoin_summarizer/TickerResponse.kt | 20 ++-- .../bitcoin_summarizer/ui/theme/Color.kt | 10 +- .../bitcoin_summarizer/ui/theme/Theme.kt | 31 +++-- 6 files changed, 121 insertions(+), 52 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 74dd639..b2c751a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/app/src/main/java/ru/vendetti/bitcoin_summarizer/GlobalResponse.kt b/app/src/main/java/ru/vendetti/bitcoin_summarizer/GlobalResponse.kt index 56878d1..b62fc37 100644 --- a/app/src/main/java/ru/vendetti/bitcoin_summarizer/GlobalResponse.kt +++ b/app/src/main/java/ru/vendetti/bitcoin_summarizer/GlobalResponse.kt @@ -7,5 +7,5 @@ data class GlobalResponse( @SerializedName("active_currencies") val activeCryptocurrencies: String = "", @SerializedName("total_market_cap_usd") val totalMarketCapUsd: String = "", @SerializedName("total_24h_volume_usd") val total24hVolumeUsd: String = "", - @SerializedName("bitcoin_percentage_of_market_cap") val bitcoinPercentageOfMarketCap: String = "" + @SerializedName("bitcoin_percentage_of_market_cap") val bitcoinPercentageOfMarketCap: String = "0.0" ) \ No newline at end of file diff --git a/app/src/main/java/ru/vendetti/bitcoin_summarizer/MainActivity.kt b/app/src/main/java/ru/vendetti/bitcoin_summarizer/MainActivity.kt index 419ac15..0061377 100644 --- a/app/src/main/java/ru/vendetti/bitcoin_summarizer/MainActivity.kt +++ b/app/src/main/java/ru/vendetti/bitcoin_summarizer/MainActivity.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -42,28 +43,43 @@ import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost +import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisLabelComponent +import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisLineComponent import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottom import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStart +import com.patrykandpatrick.vico.compose.cartesian.layer.rememberLine import com.patrykandpatrick.vico.compose.cartesian.layer.rememberLineCartesianLayer import com.patrykandpatrick.vico.compose.cartesian.rememberCartesianChart import com.patrykandpatrick.vico.compose.cartesian.rememberVicoZoomState +import com.patrykandpatrick.vico.compose.common.component.rememberLineComponent import com.patrykandpatrick.vico.compose.common.component.rememberTextComponent import com.patrykandpatrick.vico.compose.common.component.shapeComponent import com.patrykandpatrick.vico.compose.common.fill import com.patrykandpatrick.vico.compose.common.shape.rounded +import com.patrykandpatrick.vico.compose.common.vicoTheme import com.patrykandpatrick.vico.core.cartesian.Zoom +import com.patrykandpatrick.vico.core.cartesian.axis.BaseAxis import com.patrykandpatrick.vico.core.cartesian.axis.HorizontalAxis import com.patrykandpatrick.vico.core.cartesian.axis.VerticalAxis import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer +import com.patrykandpatrick.vico.core.cartesian.data.CartesianLayerRangeProvider import com.patrykandpatrick.vico.core.cartesian.data.lineSeries import com.patrykandpatrick.vico.core.cartesian.decoration.HorizontalLine +import com.patrykandpatrick.vico.core.cartesian.layer.LineCartesianLayer import com.patrykandpatrick.vico.core.common.Position import com.patrykandpatrick.vico.core.common.component.LineComponent import com.patrykandpatrick.vico.core.common.component.TextComponent import com.patrykandpatrick.vico.core.common.shape.CorneredShape import ru.vendetti.bitcoin_summarizer.ui.theme.BitcoinSummarizerTheme +import ru.vendetti.bitcoin_summarizer.ui.theme.EnglishViolet +import ru.vendetti.bitcoin_summarizer.ui.theme.Flame +import ru.vendetti.bitcoin_summarizer.ui.theme.Green2 import java.text.DateFormat +import java.text.DecimalFormat +import java.text.SimpleDateFormat import java.time.format.DateTimeFormatter +import java.util.Date +import kotlin.math.roundToInt class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -76,7 +92,7 @@ class MainActivity : ComponentActivity() { } } -@SuppressLint("MutableCollectionMutableState") +@SuppressLint("MutableCollectionMutableState", "SimpleDateFormat") @OptIn(ExperimentalMaterial3Api::class) @Preview @Composable @@ -109,15 +125,24 @@ fun CryptoScreen() { LaunchedEffect(fearGreedDataList) { modelProducer.runTransaction { - var numberValues = Array(fearGreedDataList.count()) { index -> fearGreedDataList[index].value.toInt() } + var numberValues = Array(fearGreedDataList.count()) { + index -> + fearGreedDataList[fearGreedDataList.count() - index - 1] + .value.toInt() + } + if(numberValues.isEmpty()) numberValues = Array(1) {0} + lineSeries { series(numberValues.toList()) } } } val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) - val zoomState = rememberVicoZoomState(initialZoom = Zoom.x(fearGreedIndexDaysCount.toDouble())) + val zoomState = rememberVicoZoomState( + zoomEnabled = false, + initialZoom = Zoom.x(fearGreedIndexDaysCount.toDouble())) + // Отображаем результаты на странице Scaffold ( modifier = Modifier @@ -126,8 +151,11 @@ fun CryptoScreen() { topBar = { MediumTopAppBar( colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.primaryContainer, - titleContentColor = MaterialTheme.colorScheme.primary, + containerColor = MaterialTheme.colorScheme.primary, + scrolledContainerColor = MaterialTheme.colorScheme.primary, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary, + actionIconContentColor = MaterialTheme.colorScheme.onPrimary, ), title = { Text( @@ -159,7 +187,7 @@ fun CryptoScreen() { { innerPadding -> Box( modifier = Modifier - .fillMaxSize() + .background(Color.Transparent) .padding(innerPadding) .verticalScroll(rememberScrollState()) ) { @@ -171,27 +199,44 @@ fun CryptoScreen() { CartesianChartHost( zoomState = zoomState, chart = rememberCartesianChart( - rememberLineCartesianLayer(), + rememberLineCartesianLayer( + lineProvider = LineCartesianLayer.LineProvider.series( + vicoTheme.lineCartesianLayerColors.map{ + _ -> + LineCartesianLayer + .rememberLine( + LineCartesianLayer.LineFill.single( + fill(MaterialTheme.colorScheme.onPrimary) + ) + ) + } + ), + rangeProvider = remember { CartesianLayerRangeProvider.fixed(minY = 0.0, maxY = 100.0)} + ), startAxis = VerticalAxis.rememberStart( - titleComponent = rememberTextComponent(), - title = "FGI" + title = "FGI", + titleComponent = rememberTextComponent(MaterialTheme.colorScheme.onPrimary), + line = rememberAxisLineComponent(fill(MaterialTheme.colorScheme.onPrimary)), + label = rememberAxisLabelComponent(MaterialTheme.colorScheme.onPrimary) ), bottomAxis = HorizontalAxis.rememberBottom( - titleComponent = rememberTextComponent(), - title = "last $fearGreedIndexDaysCount days" + title = "last $fearGreedIndexDaysCount days", + titleComponent = rememberTextComponent(MaterialTheme.colorScheme.onPrimary), + line = rememberAxisLineComponent(fill(MaterialTheme.colorScheme.onPrimary)), + label = rememberAxisLabelComponent(MaterialTheme.colorScheme.onPrimary) ), decorations = listOf( remember { HorizontalLine( - y = { 15.toDouble() }, - line = LineComponent(fill(Color.Red), 2f), + y = { 25.toDouble() }, + line = LineComponent(fill(Flame), 2f), labelComponent = TextComponent( background = shapeComponent( - fill(Color.Red), + fill(Flame), CorneredShape.rounded( - bottomLeft = 4.dp, - bottomRight = 4.dp + topLeft = 4.dp, + topRight = 4.dp ) ), ), @@ -201,12 +246,12 @@ fun CryptoScreen() { }, remember { HorizontalLine( - y = { 60.toDouble() }, - line = LineComponent(fill(Color.Green), 2f), + y = { 70.toDouble() }, + line = LineComponent(fill(Green2), 2f), labelComponent = TextComponent( background = shapeComponent( - fill(Color.Green), + fill(Green2), CorneredShape.rounded( bottomLeft = 4.dp, bottomRight = 4.dp @@ -229,15 +274,23 @@ fun CryptoScreen() { .align(alignment = Alignment.CenterHorizontally), fontSize = 24.sp ) - Text("Текущая цена: \n ${bitcoinTicker.priceUsd}\n") - Text("Суточный оборот: \n ${bitcoinTicker.volume24hUsd}\n") - Text("Капитализация: \n ${bitcoinTicker.marketCapUsd}\n") + val formatter = DecimalFormat("0.00") + Text("Текущая цена: \n \$ ${formatter.format(bitcoinTicker.priceUsd.toFloat())}\n") + Text("Суточный оборот: \n \$ ${bitcoinTicker.volume24hUsd}\n") + Text("Капитализация: \n \$ ${bitcoinTicker.marketCapUsd}\n") Text( "Изменение курса за: " + - "\n Сутки: ${bitcoinTicker.percentChange24h} " + - "\n Неделю: ${bitcoinTicker.percentChange7d}\n" + "\n Сутки: ${formatter.format(bitcoinTicker.percentChange24h.toFloat())}% " + + "\n Неделю: ${formatter.format(bitcoinTicker.percentChange7d.toFloat())}%\n" ) - Text("Дата последнего обновления: \n ${bitcoinTicker.lastUpdated}\n") + + var humanDate = "" + + if(bitcoinTicker.lastUpdated.isNotEmpty()) + humanDate = DateTimeFormatter.ISO_INSTANT + .format(java.time.Instant.ofEpochSecond(bitcoinTicker.lastUpdated.toLong())) + + Text("Дата последнего обновления: \n ${humanDate}\n") HorizontalDivider(thickness = 2.dp) Text( @@ -246,10 +299,10 @@ fun CryptoScreen() { .align(alignment = Alignment.CenterHorizontally), fontSize = 24.sp ) - Text("Общая капитализация крипторынка: \n ${globalData.totalMarketCapUsd}\n") + Text("Общая капитализация крипторынка: \n \$ ${globalData.totalMarketCapUsd}\n") Text("Всего видов криптовалют: \n ${globalData.activeCryptocurrencies}\n") - Text("Суточный оборот других криптовалют: \n ${globalData.total24hVolumeUsd}\n") - Text("Процент доминации Биткоина: \n ${globalData.bitcoinPercentageOfMarketCap}\n") + Text("Суточный оборот других криптовалют: \n \$ ${globalData.total24hVolumeUsd}\n") + Text("Процент доминации Биткоина: \n ${formatter.format(globalData.bitcoinPercentageOfMarketCap.toFloat())}%\n") } } } diff --git a/app/src/main/java/ru/vendetti/bitcoin_summarizer/TickerResponse.kt b/app/src/main/java/ru/vendetti/bitcoin_summarizer/TickerResponse.kt index a845db9..30b0dfa 100644 --- a/app/src/main/java/ru/vendetti/bitcoin_summarizer/TickerResponse.kt +++ b/app/src/main/java/ru/vendetti/bitcoin_summarizer/TickerResponse.kt @@ -11,15 +11,15 @@ data class TickerData( val name: String = "", val symbol: String = "", val rank: String = "", - @SerializedName("price_usd") val priceUsd: String = "", - @SerializedName("price_btc") val priceBtc: String = "", - @SerializedName("24h_volume_usd") val volume24hUsd: String = "", - @SerializedName("market_cap_usd") val marketCapUsd: String = "", - @SerializedName("available_supply") val availableSupply: String = "", - @SerializedName("total_supply") val totalSupply: String = "", - @SerializedName("max_supply") val maxSupply: String? = "", - @SerializedName("percent_change_1h") val percentChange1h: String = "", - @SerializedName("percent_change_24h") val percentChange24h: String = "", - @SerializedName("percent_change_7d") val percentChange7d: String = "", + @SerializedName("price_usd") val priceUsd: String = "0.0", + @SerializedName("price_btc") val priceBtc: String = "0.0", + @SerializedName("24h_volume_usd") val volume24hUsd: String = "0", + @SerializedName("market_cap_usd") val marketCapUsd: String = "0", + @SerializedName("available_supply") val availableSupply: String = "0", + @SerializedName("total_supply") val totalSupply: String = "0", + @SerializedName("max_supply") val maxSupply: String? = "0", + @SerializedName("percent_change_1h") val percentChange1h: String = "0", + @SerializedName("percent_change_24h") val percentChange24h: String = "0.0", + @SerializedName("percent_change_7d") val percentChange7d: String = "0.0", @SerializedName("last_updated") val lastUpdated: String = "" ) \ No newline at end of file diff --git a/app/src/main/java/ru/vendetti/bitcoin_summarizer/ui/theme/Color.kt b/app/src/main/java/ru/vendetti/bitcoin_summarizer/ui/theme/Color.kt index 3dc063b..9a3f2ed 100644 --- a/app/src/main/java/ru/vendetti/bitcoin_summarizer/ui/theme/Color.kt +++ b/app/src/main/java/ru/vendetti/bitcoin_summarizer/ui/theme/Color.kt @@ -8,4 +8,12 @@ val Pink80 = Color(0xFFEFB8C8) val Purple40 = Color(0xFF6650a4) val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file +val Pink40 = Color(0xFF7D5260) + +val EnglishViolet = Color(0xFF44355B) +val DarkPurple = Color(0xFF31263E) +val RaisinBlack = Color(0xFF221E22) +val HunyadiYellow = Color(0xFFECA72C) +val Flame = Color(0xFFEE5622) + +val Green2 = Color(0xFFB1E434) \ No newline at end of file diff --git a/app/src/main/java/ru/vendetti/bitcoin_summarizer/ui/theme/Theme.kt b/app/src/main/java/ru/vendetti/bitcoin_summarizer/ui/theme/Theme.kt index fa7ac0a..b922d15 100644 --- a/app/src/main/java/ru/vendetti/bitcoin_summarizer/ui/theme/Theme.kt +++ b/app/src/main/java/ru/vendetti/bitcoin_summarizer/ui/theme/Theme.kt @@ -9,28 +9,37 @@ import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 + primary = RaisinBlack, + secondary = DarkPurple, + tertiary = EnglishViolet, + + // Other default colors to override + background = DarkPurple, + surface = Color(0xFFFFFBFE), + onPrimary = HunyadiYellow, + onSecondary = HunyadiYellow, + onTertiary = HunyadiYellow, + onBackground = HunyadiYellow, + onSurface = Color(0xFF1C1B1F), ) private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 + primary = HunyadiYellow, + secondary = Flame, + tertiary = EnglishViolet, - /* Other default colors to override - background = Color(0xFFFFFBFE), + // Other default colors to override + background = Color.White, surface = Color(0xFFFFFBFE), - onPrimary = Color.White, + onPrimary = RaisinBlack, onSecondary = Color.White, onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), + onBackground = RaisinBlack, onSurface = Color(0xFF1C1B1F), - */ ) @Composable -- 2.47.2