23 Commits

Author SHA1 Message Date
087b732fa5 Merge pull request 'dev' (#22) from dev into main
All checks were successful
Gitea Android Builder / Build (push) Successful in 3m32s
Reviewed-on: #22
2025-03-08 15:50:58 +03:00
08df502b1f Some minor fixes (manifest, text typos, gradle app ver etc.) 2025-03-08 17:48:53 +05:00
28196510a3 .idea dir removed from the repo 2025-03-08 17:37:03 +05:00
3691477e92 dependencies updated 2025-03-08 17:28:12 +05:00
580c5b6611 Merge pull request 'removed dynamic color, cause we are controlling colors by ourself' (#21) from dev into main
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m36s
Reviewed-on: #21
2025-03-08 11:45:03 +03:00
8f0ffb7041 removed dynamic color, cause we are controlling colors by ourself 2025-03-08 11:44:29 +03:00
0494efc2ad Merge pull request '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' (#20) from dev into main
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m27s
Reviewed-on: #20
2025-03-07 16:13:29 +03:00
09871e8727 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 2025-03-07 18:10:43 +05:00
d220a03a89 Merge pull request 'Update .gitignore' (#19) from dev into main
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m18s
Reviewed-on: #19
2025-03-06 17:40:05 +03:00
95b2c1e70b Merge pull request 'CI/CD branching fix' (#18) from pipeline-test into main
Reviewed-on: #18
2025-03-05 19:42:02 +03:00
4005a39696 CI/CD branching fix
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m18s
2025-03-05 21:40:07 +05:00
407a5d32a5 Merge pull request 'pipeline-test' (#17) from pipeline-test into main
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m18s
Reviewed-on: #17
2025-03-05 19:34:40 +03:00
81ab379e0e CI/CD branching update
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m25s
2025-03-05 21:30:26 +05:00
5a4d30b9f8 CI/CD image update revert
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m17s
2025-03-05 21:18:04 +05:00
5c92f74ceb CI/CD image update fix
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m23s
2025-03-05 21:14:13 +05:00
0906b95273 CI/CD image update
Some checks failed
Gitea Android Builder / Build (push) Failing after 20s
2025-03-05 21:11:15 +05:00
4c9c7a3aa4 Update .gitignore 2025-03-05 15:53:47 +03:00
07ad6cb59d Merge pull request 'dev' (#16) from dev into main
All checks were successful
Gitea Android Builder / Build (push) Successful in 1m56s
Reviewed-on: #16
2025-03-05 03:51:27 +03:00
fcd27175ac Update app/src/main/java/ru/vendetti/bitcoin_summarizer/TickerResponse.kt 2025-03-05 03:50:25 +03:00
a9c5282bdc Update app/src/main/java/ru/vendetti/bitcoin_summarizer/GlobalResponse.kt 2025-03-05 03:50:08 +03:00
52386c1987 Update app/src/main/java/ru/vendetti/bitcoin_summarizer/MainActivity.kt 2025-03-05 03:49:25 +03:00
fb59407f8b Update gradle/libs.versions.toml 2025-03-05 03:48:52 +03:00
1261b80346 Update app/build.gradle.kts 2025-03-05 03:48:26 +03:00
24 changed files with 356 additions and 302 deletions

View File

@ -3,12 +3,11 @@ run-name: ${{ gitea.actor }} is building an Android application
on:
push:
branches:
- main
- pipeline-test
jobs:
Build:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Checkout the repo
uses: actions/checkout@v4

View File

@ -0,0 +1,40 @@
name: Gitea Android Builder
run-name: ${{ gitea.actor }} is building an Android application
on:
push:
tags:
- "*"
jobs:
Build:
runs-on: ubuntu-24.04
steps:
- name: Checkout the repo
uses: actions/checkout@v4
- name: Set up JDK 23
uses: actions/setup-java@v4
with:
java-version: '23'
distribution: 'temurin'
- name: Set up Android SDK
uses: android-actions/setup-android@v3
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- name: Build with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: assembleDebug
- name: Upload .apk Artifact
uses: actions/upload-artifact@v3
with:
name: android-app-apk
path: app/build/outputs/apk/debug/*.apk
- name: Status
run: echo "This job's status is ${{ job.status }}."

7
.gitignore vendored
View File

@ -1,12 +1,7 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
/.idea
.DS_Store
/build
/captures

3
.idea/.gitignore generated vendored
View File

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name generated
View File

@ -1 +0,0 @@
Bitcoin summarizer

View File

@ -1,123 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

6
.idea/compiler.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

20
.idea/gradle.xml generated
View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

6
.idea/kotlinc.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="2.0.0" />
</component>
</project>

10
.idea/migrations.xml generated
View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

10
.idea/misc.xml generated
View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -12,8 +12,8 @@ android {
applicationId = "ru.vendetti.bitcoin_summarizer"
minSdk = 29
targetSdk = 35
versionCode = 1
versionName = "1.0"
versionCode = 2
versionName = "1.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@ -61,5 +61,6 @@ dependencies {
implementation(libs.converter.gson)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.vico.compose.m3)
}

View File

@ -3,13 +3,13 @@
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:supportsRtl="false"
android:theme="@style/Theme.BitcoinSummarizer"
tools:targetApi="31">
<activity

View File

@ -4,8 +4,8 @@ import com.google.gson.annotations.SerializedName
// Данные
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("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 = "0.0"
)

View File

@ -1,26 +1,85 @@
package ru.vendetti.bitcoin_summarizer
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.Spacer
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.magnifier
import androidx.compose.foundation.rememberScrollState
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.MediumTopAppBar
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
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.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?) {
@ -33,53 +92,218 @@ class MainActivity : ComponentActivity() {
}
}
@SuppressLint("MutableCollectionMutableState", "SimpleDateFormat")
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun CryptoScreen() {
// Создаем репозиторий для работы с API
val cryptoRepository = remember { CryptoRepository(RetrofitClient.apiService) }
// Состояния для хранения результатов запросов
var bitcoinTicker by remember { mutableStateOf("Загрузка Bitcoin Ticker...") }
var globalData by remember { mutableStateOf("Загрузка глобальных данных...") }
var fearGreedData by remember { mutableStateOf("Загрузка индекса страха и жадности...") }
var bitcoinTicker by remember { mutableStateOf(TickerData()) }
var globalData by remember { mutableStateOf(GlobalResponse()) }
var fearGreedDataList by remember { mutableStateOf(ArrayList<FearAndGreedData>()) }
var fearGreedIndexDaysCount by remember { mutableIntStateOf(30) }
// Запускаем корутину для выполнения сетевых запросов
LaunchedEffect(Unit) {
LaunchedEffect(fearGreedIndexDaysCount) {
// Запрос Bitcoin Ticker
val tickerResponse = cryptoRepository.fetchBitcoinTicker()
bitcoinTicker = tickerResponse?.joinToString(separator = "\n") { data ->
"Название: ${data.name}, Цена: ${data.priceUsd}, Обновлено: ${data.lastUpdated}"
} ?: "Ошибка загрузки Bitcoin Ticker"
bitcoinTicker = tickerResponse!!.first()
// Запрос глобальных данных
val globalResponse = cryptoRepository.fetchGlobalData()
globalData = globalResponse?.let { data ->
"Активных криптовалют: ${data.activeCryptocurrencies}\nРыночная капитализация: ${data.totalMarketCapUsd}\n24h Объем: ${data.total24hVolumeUsd}"
} ?: "Ошибка загрузки глобальных данных"
globalData = globalResponse!!
// Запрос индекса страха и жадности
val fearResponse = cryptoRepository.fetchFearAndGreedData(30)
fearGreedData = fearResponse?.dataList?.joinToString(separator = "\n") { data ->
"Время: ${data.timestamp}, Значение: ${data.value}, Классификация: ${data.valueClassification}"
} ?: "Ошибка загрузки данных страха и жадности"
val fearResponse = cryptoRepository.fetchFearAndGreedData(fearGreedIndexDaysCount)
fearGreedDataList = fearResponse?.dataList as ArrayList<FearAndGreedData>
}
// Отображаем результаты в виде простой страницы
Column(
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(fearGreedDataList) {
modelProducer.runTransaction {
var numberValues = Array<Int>(fearGreedDataList.count()) {
index ->
fearGreedDataList[fearGreedDataList.count() - index - 1]
.value.toInt()
}
if(numberValues.isEmpty())
numberValues = Array<Int>(1) {0}
lineSeries { series(numberValues.toList()) }
}
}
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
val zoomState = rememberVicoZoomState(
zoomEnabled = false,
initialZoom = Zoom.x(fearGreedIndexDaysCount.toDouble()))
// Отображаем результаты на странице
Scaffold (
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
MediumTopAppBar(
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
scrolledContainerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.onPrimary,
navigationIconContentColor = MaterialTheme.colorScheme.onPrimary,
actionIconContentColor = MaterialTheme.colorScheme.onPrimary,
),
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
.background(Color.Transparent)
.padding(innerPadding)
.verticalScroll(rememberScrollState())
) {
Text(text = "Bitcoin Ticker Data", style = MaterialTheme.typography.bodyMedium)
Text(text = bitcoinTicker)
Spacer(modifier = Modifier.height(16.dp))
Column(
modifier = Modifier
.padding(16.dp, 16.dp, 16.dp, 36.dp)
) {
/* Fear Greed Chart Start */
CartesianChartHost(
zoomState = zoomState,
chart = rememberCartesianChart(
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(
title = "FGI",
titleComponent = rememberTextComponent(MaterialTheme.colorScheme.onPrimary),
line = rememberAxisLineComponent(fill(MaterialTheme.colorScheme.onPrimary)),
label = rememberAxisLabelComponent(MaterialTheme.colorScheme.onPrimary)
),
bottomAxis = HorizontalAxis.rememberBottom(
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 = { 25.toDouble() },
line = LineComponent(fill(Flame), 2f),
labelComponent = TextComponent(
background =
shapeComponent(
fill(Flame),
CorneredShape.rounded(
topLeft = 4.dp,
topRight = 4.dp
)
),
),
label = { "Fear" },
verticalLabelPosition = Position.Vertical.Top
)
},
remember {
HorizontalLine(
y = { 70.toDouble() },
line = LineComponent(fill(Green2), 2f),
labelComponent = TextComponent(
background =
shapeComponent(
fill(Green2),
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
)
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 Сутки: ${formatter.format(bitcoinTicker.percentChange24h.toFloat())}% " +
"\n Неделю: ${formatter.format(bitcoinTicker.percentChange7d.toFloat())}%\n"
)
Text(text = "Global Data", style = MaterialTheme.typography.bodyMedium)
Text(text = globalData)
Spacer(modifier = Modifier.height(16.dp))
var humanDate = ""
Text(text = "Fear & Greed Index", style = MaterialTheme.typography.bodyMedium)
Text(text = fearGreedData)
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(
"Глобальные данные",
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 ${formatter.format(globalData.bitcoinPercentageOfMarketCap.toFloat())}%\n")
}
}
}
}

View File

@ -7,19 +7,19 @@ typealias TickerResponse = List<TickerData>
// Сами данные
data class TickerData(
val id: String,
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("last_updated") val lastUpdated: String
val id: String = "",
val name: String = "",
val symbol: String = "",
val rank: 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 = ""
)

View File

@ -9,3 +9,11 @@ val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
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)

View File

@ -9,43 +9,45 @@ 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
fun BitcoinSummarizerTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}

View File

@ -1,17 +1,18 @@
[versions]
agp = "8.8.2"
agp = "8.9.0"
converterGson = "2.9.0"
kotlin = "2.0.0"
coreKtx = "1.15.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
kotlinxCoroutinesAndroid = "1.7.3"
kotlinxCoroutinesCore = "1.7.3"
kotlinxCoroutinesAndroid = "1.10.1"
kotlinxCoroutinesCore = "1.10.1"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.10.1"
composeBom = "2025.02.00"
retrofit = "2.9.0"
vico = "2.0.2"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -32,6 +33,7 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3"
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
vico-compose-m3 = { group = "com.patrykandpatrick.vico", name = "compose-m3", version.ref = "vico" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }

View File

@ -1,6 +1,6 @@
#Wed Feb 26 23:45:23 YEKT 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists