Update app/src/main/java/ru/vendetti/bitcoin_summarizer/MainActivity.kt
This commit is contained in:
		| @@ -1,26 +1,69 @@ | |||||||
| package ru.vendetti.bitcoin_summarizer | package ru.vendetti.bitcoin_summarizer | ||||||
|  |  | ||||||
|  | import android.annotation.SuppressLint | ||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
| import androidx.activity.ComponentActivity | import androidx.activity.ComponentActivity | ||||||
| import androidx.activity.compose.setContent | import androidx.activity.compose.setContent | ||||||
|  | import androidx.compose.foundation.layout.Box | ||||||
| import androidx.compose.foundation.layout.Column | import androidx.compose.foundation.layout.Column | ||||||
| import androidx.compose.foundation.layout.Spacer | import androidx.compose.foundation.layout.PaddingValues | ||||||
| import androidx.compose.foundation.layout.fillMaxSize | import androidx.compose.foundation.layout.fillMaxSize | ||||||
| import androidx.compose.foundation.layout.height |  | ||||||
| import androidx.compose.foundation.layout.padding | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.foundation.magnifier | ||||||
| import androidx.compose.foundation.rememberScrollState | import androidx.compose.foundation.rememberScrollState | ||||||
| import androidx.compose.foundation.verticalScroll | import androidx.compose.foundation.verticalScroll | ||||||
|  | import androidx.compose.material.icons.Icons | ||||||
|  | import androidx.compose.material.icons.filled.Menu | ||||||
|  | import androidx.compose.material.icons.filled.MoreVert | ||||||
|  | import androidx.compose.material3.ExperimentalMaterial3Api | ||||||
|  | import androidx.compose.material3.HorizontalDivider | ||||||
|  | import androidx.compose.material3.Icon | ||||||
|  | import androidx.compose.material3.IconButton | ||||||
| import androidx.compose.material3.MaterialTheme | import androidx.compose.material3.MaterialTheme | ||||||
|  | import androidx.compose.material3.MediumTopAppBar | ||||||
|  | import androidx.compose.material3.Scaffold | ||||||
| import androidx.compose.material3.Text | import androidx.compose.material3.Text | ||||||
|  | import androidx.compose.material3.TopAppBarDefaults | ||||||
|  | import androidx.compose.material3.rememberTopAppBarState | ||||||
| import androidx.compose.runtime.Composable | import androidx.compose.runtime.Composable | ||||||
| import androidx.compose.runtime.LaunchedEffect | import androidx.compose.runtime.LaunchedEffect | ||||||
| import androidx.compose.runtime.getValue | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.mutableIntStateOf | ||||||
| import androidx.compose.runtime.mutableStateOf | import androidx.compose.runtime.mutableStateOf | ||||||
| import androidx.compose.runtime.remember | import androidx.compose.runtime.remember | ||||||
| import androidx.compose.runtime.setValue | import androidx.compose.runtime.setValue | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
| import androidx.compose.ui.Modifier | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.graphics.Color | ||||||
|  | import androidx.compose.ui.input.nestedscroll.nestedScroll | ||||||
|  | import androidx.compose.ui.text.style.TextOverflow | ||||||
|  | import androidx.compose.ui.tooling.preview.Preview | ||||||
|  | import androidx.compose.ui.unit.TextUnit | ||||||
| import androidx.compose.ui.unit.dp | 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.rememberBottom | ||||||
|  | import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStart | ||||||
|  | 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.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.core.cartesian.Zoom | ||||||
|  | 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.lineSeries | ||||||
|  | import com.patrykandpatrick.vico.core.cartesian.decoration.HorizontalLine | ||||||
|  | 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.BitcoinSummarizerTheme | ||||||
|  | import java.text.DateFormat | ||||||
|  | import java.time.format.DateTimeFormatter | ||||||
|  |  | ||||||
| class MainActivity : ComponentActivity() { | class MainActivity : ComponentActivity() { | ||||||
|     override fun onCreate(savedInstanceState: Bundle?) { |     override fun onCreate(savedInstanceState: Bundle?) { | ||||||
| @@ -33,53 +76,181 @@ class MainActivity : ComponentActivity() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @SuppressLint("MutableCollectionMutableState") | ||||||
|  | @OptIn(ExperimentalMaterial3Api::class) | ||||||
|  | @Preview | ||||||
| @Composable | @Composable | ||||||
| fun CryptoScreen() { | fun CryptoScreen() { | ||||||
|     // Создаем репозиторий для работы с API |     // Создаем репозиторий для работы с API | ||||||
|     val cryptoRepository = remember { CryptoRepository(RetrofitClient.apiService) } |     val cryptoRepository = remember { CryptoRepository(RetrofitClient.apiService) } | ||||||
|  |  | ||||||
|     // Состояния для хранения результатов запросов |     // Состояния для хранения результатов запросов | ||||||
|     var bitcoinTicker by remember { mutableStateOf("Загрузка Bitcoin Ticker...") } |     var bitcoinTicker by remember { mutableStateOf(TickerData()) } | ||||||
|     var globalData by remember { mutableStateOf("Загрузка глобальных данных...") } |     var globalData by remember { mutableStateOf(GlobalResponse()) } | ||||||
|     var fearGreedData by remember { mutableStateOf("Загрузка индекса страха и жадности...") } |     var fearGreedDataList by remember { mutableStateOf(ArrayList<FearAndGreedData>()) } | ||||||
|  |  | ||||||
|  |     var fearGreedIndexDaysCount by remember { mutableIntStateOf(30) } | ||||||
|  |  | ||||||
|     // Запускаем корутину для выполнения сетевых запросов |     // Запускаем корутину для выполнения сетевых запросов | ||||||
|     LaunchedEffect(Unit) { |     LaunchedEffect(fearGreedIndexDaysCount) { | ||||||
|         // Запрос Bitcoin Ticker |         // Запрос Bitcoin Ticker | ||||||
|         val tickerResponse = cryptoRepository.fetchBitcoinTicker() |         val tickerResponse = cryptoRepository.fetchBitcoinTicker() | ||||||
|         bitcoinTicker = tickerResponse?.joinToString(separator = "\n") { data -> |         bitcoinTicker = tickerResponse!!.first() | ||||||
|             "Название: ${data.name}, Цена: ${data.priceUsd}, Обновлено: ${data.lastUpdated}" |  | ||||||
|         } ?: "Ошибка загрузки Bitcoin Ticker" |  | ||||||
|  |  | ||||||
|         // Запрос глобальных данных |         // Запрос глобальных данных | ||||||
|         val globalResponse = cryptoRepository.fetchGlobalData() |         val globalResponse = cryptoRepository.fetchGlobalData() | ||||||
|         globalData = globalResponse?.let { data -> |         globalData = globalResponse!! | ||||||
|             "Активных криптовалют: ${data.activeCryptocurrencies}\nРыночная капитализация: ${data.totalMarketCapUsd}\n24h Объем: ${data.total24hVolumeUsd}" |  | ||||||
|         } ?: "Ошибка загрузки глобальных данных" |  | ||||||
|  |  | ||||||
|         // Запрос индекса страха и жадности |         // Запрос индекса страха и жадности | ||||||
|         val fearResponse = cryptoRepository.fetchFearAndGreedData(30) |         val fearResponse = cryptoRepository.fetchFearAndGreedData(fearGreedIndexDaysCount) | ||||||
|         fearGreedData = fearResponse?.dataList?.joinToString(separator = "\n") { data -> |         fearGreedDataList = fearResponse?.dataList as ArrayList<FearAndGreedData> | ||||||
|             "Время: ${data.timestamp}, Значение: ${data.value}, Классификация: ${data.valueClassification}" |  | ||||||
|         } ?: "Ошибка загрузки данных страха и жадности" |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Отображаем результаты в виде простой страницы |     val modelProducer = remember { CartesianChartModelProducer() } | ||||||
|     Column( |  | ||||||
|  |     LaunchedEffect(fearGreedDataList) { | ||||||
|  |         modelProducer.runTransaction { | ||||||
|  |             var numberValues = Array<Int>(fearGreedDataList.count()) { index -> fearGreedDataList[index].value.toInt() } | ||||||
|  |             if(numberValues.isEmpty()) | ||||||
|  |                 numberValues = Array<Int>(1) {0} | ||||||
|  |             lineSeries { series(numberValues.toList()) } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) | ||||||
|  |     val zoomState = rememberVicoZoomState(initialZoom = Zoom.x(fearGreedIndexDaysCount.toDouble())) | ||||||
|  |     // Отображаем результаты на странице | ||||||
|  |     Scaffold ( | ||||||
|         modifier = Modifier |         modifier = Modifier | ||||||
|             .fillMaxSize() |             .nestedScroll(scrollBehavior.nestedScrollConnection), | ||||||
|             .padding(16.dp) |  | ||||||
|             .verticalScroll(rememberScrollState()) |  | ||||||
|     ) { |  | ||||||
|         Text(text = "Bitcoin Ticker Data", style = MaterialTheme.typography.bodyMedium) |  | ||||||
|         Text(text = bitcoinTicker) |  | ||||||
|         Spacer(modifier = Modifier.height(16.dp)) |  | ||||||
|  |  | ||||||
|         Text(text = "Global Data", style = MaterialTheme.typography.bodyMedium) |         topBar = { | ||||||
|         Text(text = globalData) |             MediumTopAppBar( | ||||||
|         Spacer(modifier = Modifier.height(16.dp)) |                 colors = TopAppBarDefaults.topAppBarColors( | ||||||
|  |                     containerColor = MaterialTheme.colorScheme.primaryContainer, | ||||||
|  |                     titleContentColor = MaterialTheme.colorScheme.primary, | ||||||
|  |                 ), | ||||||
|  |                 title = { | ||||||
|  |                     Text( | ||||||
|  |                         "Bitcoin Summarizer!", | ||||||
|  |                         maxLines = 1, | ||||||
|  |                         overflow = TextOverflow.Ellipsis | ||||||
|  |                     ) | ||||||
|  |                 }, | ||||||
|  |                 navigationIcon = { | ||||||
|  |                     IconButton(onClick = {}) { | ||||||
|  |                         Icon( | ||||||
|  |                             imageVector = Icons.Filled.Menu, | ||||||
|  |                             contentDescription = "Navigation hamburger menu" | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 actions = { | ||||||
|  |                     IconButton(onClick = {}) { | ||||||
|  |                         Icon( | ||||||
|  |                             imageVector = Icons.Filled.MoreVert, | ||||||
|  |                             contentDescription = "Actions" | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 scrollBehavior = scrollBehavior | ||||||
|  |             ) | ||||||
|  |         }, | ||||||
|  |     ) | ||||||
|  |     { innerPadding -> | ||||||
|  |         Box( | ||||||
|  |             modifier = Modifier | ||||||
|  |                 .fillMaxSize() | ||||||
|  |                 .padding(innerPadding) | ||||||
|  |                 .verticalScroll(rememberScrollState()) | ||||||
|  |         ) { | ||||||
|  |             Column( | ||||||
|  |                 modifier = Modifier | ||||||
|  |                     .padding(16.dp, 16.dp, 16.dp, 36.dp) | ||||||
|  |             ) { | ||||||
|  |                 /* Fear Greed Chart Start */ | ||||||
|  |                 CartesianChartHost( | ||||||
|  |                     zoomState = zoomState, | ||||||
|  |                     chart = rememberCartesianChart( | ||||||
|  |                         rememberLineCartesianLayer(), | ||||||
|  |                         startAxis = VerticalAxis.rememberStart( | ||||||
|  |                             titleComponent = rememberTextComponent(), | ||||||
|  |                             title = "FGI" | ||||||
|  |                         ), | ||||||
|  |                         bottomAxis = HorizontalAxis.rememberBottom( | ||||||
|  |                             titleComponent = rememberTextComponent(), | ||||||
|  |                             title = "last $fearGreedIndexDaysCount days" | ||||||
|  |                         ), | ||||||
|  |                         decorations = listOf( | ||||||
|  |                             remember { | ||||||
|  |                                 HorizontalLine( | ||||||
|  |                                     y = { 15.toDouble() }, | ||||||
|  |                                     line = LineComponent(fill(Color.Red), 2f), | ||||||
|  |                                     labelComponent = TextComponent( | ||||||
|  |                                         background = | ||||||
|  |                                         shapeComponent( | ||||||
|  |                                             fill(Color.Red), | ||||||
|  |                                             CorneredShape.rounded( | ||||||
|  |                                                 bottomLeft = 4.dp, | ||||||
|  |                                                 bottomRight = 4.dp | ||||||
|  |                                             ) | ||||||
|  |                                         ), | ||||||
|  |                                     ), | ||||||
|  |                                     label = { "Fear" }, | ||||||
|  |                                     verticalLabelPosition = Position.Vertical.Top | ||||||
|  |                                 ) | ||||||
|  |                             }, | ||||||
|  |                             remember { | ||||||
|  |                                 HorizontalLine( | ||||||
|  |                                     y = { 60.toDouble() }, | ||||||
|  |                                     line = LineComponent(fill(Color.Green), 2f), | ||||||
|  |                                     labelComponent = TextComponent( | ||||||
|  |                                         background = | ||||||
|  |                                         shapeComponent( | ||||||
|  |                                             fill(Color.Green), | ||||||
|  |                                             CorneredShape.rounded( | ||||||
|  |                                                 bottomLeft = 4.dp, | ||||||
|  |                                                 bottomRight = 4.dp | ||||||
|  |                                             ) | ||||||
|  |                                         ), | ||||||
|  |                                     ), | ||||||
|  |                                     label = { "Greed" }, | ||||||
|  |                                     verticalLabelPosition = Position.Vertical.Bottom | ||||||
|  |                                 ) | ||||||
|  |                             } | ||||||
|  |                         ), | ||||||
|  |                     ), | ||||||
|  |                     modelProducer = modelProducer, | ||||||
|  |                 ) | ||||||
|  |                 /* Fear Greed Chart End */ | ||||||
|  |                 HorizontalDivider(thickness = 2.dp) | ||||||
|  |                 Text( | ||||||
|  |                     "Данные о Биткойне", | ||||||
|  |                     modifier = Modifier | ||||||
|  |                         .align(alignment = Alignment.CenterHorizontally), | ||||||
|  |                     fontSize = 24.sp | ||||||
|  |                 ) | ||||||
|  |                 Text("Текущая цена: \n ${bitcoinTicker.priceUsd}\n") | ||||||
|  |                 Text("Суточный оборот: \n ${bitcoinTicker.volume24hUsd}\n") | ||||||
|  |                 Text("Капитализация: \n ${bitcoinTicker.marketCapUsd}\n") | ||||||
|  |                 Text( | ||||||
|  |                     "Изменение курса за: " + | ||||||
|  |                             "\n Сутки: ${bitcoinTicker.percentChange24h} " + | ||||||
|  |                             "\n Неделю: ${bitcoinTicker.percentChange7d}\n" | ||||||
|  |                 ) | ||||||
|  |                 Text("Дата последнего обновления: \n ${bitcoinTicker.lastUpdated}\n") | ||||||
|  |  | ||||||
|         Text(text = "Fear & Greed Index", style = MaterialTheme.typography.bodyMedium) |                 HorizontalDivider(thickness = 2.dp) | ||||||
|         Text(text = fearGreedData) |                 Text( | ||||||
|  |                     "Глобальные данные", | ||||||
|  |                     modifier = Modifier | ||||||
|  |                         .align(alignment = Alignment.CenterHorizontally), | ||||||
|  |                     fontSize = 24.sp | ||||||
|  |                 ) | ||||||
|  |                 Text("Общая капитализация крипторынка: \n ${globalData.totalMarketCapUsd}\n") | ||||||
|  |                 Text("Всего видов криптовалют: \n ${globalData.activeCryptocurrencies}\n") | ||||||
|  |                 Text("Суточный оборот других криптовалют: \n ${globalData.total24hVolumeUsd}\n") | ||||||
|  |                 Text("Процент доминации Биткоина: \n ${globalData.bitcoinPercentageOfMarketCap}\n") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user