This commit is contained in:
coco
2026-07-03 15:56:07 +08:00
commit caef23209c
5767 changed files with 1004268 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id "app.cash.paparazzi"
id "com.android.application"
id "kotlin-android"
id "org.jetbrains.kotlin.plugin.compose"
}
android {
defaultConfig {
minSdk library.compose_min_sdk
targetSdk library.target_sdk
compileSdk library.target_sdk
versionCode library.version_code
versionName library.version_name
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
}
}
buildFeatures {
viewBinding true
compose true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
namespace "com.patrykandpatrick.vico"
}
dependencies {
implementation project(":vico:compose-m3")
implementation project(":vico:views")
implementation platform(libs.composeBom)
implementation libs.activityCompose
implementation libs.androidXCore
implementation libs.appcompat
implementation libs.composeMaterial
implementation libs.composeMaterial3
implementation libs.composeNavigation
implementation libs.composePreview
implementation libs.composeUI
implementation libs.composeViewBinding
implementation libs.coroutinesCore
implementation libs.kotlinStdLib
implementation libs.lifecycleRuntime
implementation libs.lifecycleRuntimeCompose
implementation libs.material
implementation libs.systemUIController
implementation libs.viewModelCompose
debugImplementation libs.composeUITooling
testImplementation libs.kotlinTest
}
View File
+37
View File
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2023 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Vico">
<activity
android:name=".sample.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,30 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
internal class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent { VicoApp() }
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample
import androidx.compose.runtime.Composable
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.patrykandpatrick.vico.sample.showcase.ChartListScreen
import com.patrykandpatrick.vico.sample.showcase.ChartScreen
@Composable
internal fun VicoApp() {
val navController = rememberNavController()
VicoTheme {
NavHost(navController = navController, startDestination = "chartList") {
composable("chartList") { ChartListScreen(navController) }
composable(
"chart/{initialChartID}/{uiFrameworkID}",
listOf(
navArgument("initialChartID") { type = NavType.IntType },
navArgument("uiFrameworkID") { type = NavType.IntType },
),
) { backStackEntry ->
val arguments = requireNotNull(backStackEntry.arguments)
ChartScreen(
navController,
arguments.getInt("initialChartID"),
arguments.getInt("uiFrameworkID"),
)
}
}
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
@Composable
fun VicoTheme(useDynamicColor: Boolean = true, content: @Composable () -> Unit) {
val isSystemInDarkTheme = isSystemInDarkTheme()
MaterialTheme(
colorScheme =
when {
useDynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (isSystemInDarkTheme) dynamicDarkColorScheme(context)
else dynamicLightColorScheme(context)
}
isSystemInDarkTheme -> darkColorScheme()
else -> lightColorScheme()
},
content = content,
)
}
@@ -0,0 +1,24 @@
/*
* Copyright 2023 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.previews.annotation
import android.content.res.Configuration
import androidx.compose.ui.tooling.preview.Preview
@Preview(widthDp = 300, heightDp = 200)
@Preview(widthDp = 300, heightDp = 200, uiMode = Configuration.UI_MODE_NIGHT_YES)
public annotation class ChartPreview
@@ -0,0 +1,77 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.previews.composables.column
import androidx.compose.runtime.Composable
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.layer.rememberColumnCartesianLayer
import com.patrykandpatrick.vico.compose.cartesian.rememberCartesianChart
import com.patrykandpatrick.vico.compose.cartesian.rememberVicoScrollState
import com.patrykandpatrick.vico.core.cartesian.AutoScrollCondition
import com.patrykandpatrick.vico.core.cartesian.Scroll
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModel
import com.patrykandpatrick.vico.sample.previews.annotation.ChartPreview
import com.patrykandpatrick.vico.sample.previews.resource.PreviewSurface
import com.patrykandpatrick.vico.sample.previews.resource.mediumColumnModel
import com.patrykandpatrick.vico.sample.previews.resource.shortColumnModel
@ChartPreview
@Composable
public fun DefaultColumnChart(
model: CartesianChartModel = shortColumnModel,
scrollable: Boolean = true,
initialScroll: Scroll.Absolute = Scroll.Absolute.Start,
autoScrollCondition: AutoScrollCondition = AutoScrollCondition.Never,
) {
PreviewSurface {
CartesianChartHost(
chart =
rememberCartesianChart(
rememberColumnCartesianLayer(),
startAxis = rememberStartAxis(),
bottomAxis = rememberBottomAxis(),
),
model = model,
scrollState =
rememberVicoScrollState(
scrollEnabled = scrollable,
initialScroll = initialScroll,
autoScrollCondition = autoScrollCondition,
),
)
}
}
@ChartPreview
@Composable
fun DefaultColumnChartLongScrollable() {
DefaultColumnChart(model = mediumColumnModel)
}
@ChartPreview
@Composable
fun DefaultColumnChartLongScrollableEnd() {
DefaultColumnChart(model = mediumColumnModel, initialScroll = Scroll.Absolute.End)
}
@ChartPreview
@Composable
fun DefaultColumnChartLongNonScrollable() {
DefaultColumnChart(model = mediumColumnModel, scrollable = false)
}
@@ -0,0 +1,70 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.previews.composables.line
import androidx.compose.runtime.Composable
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.layer.rememberLineCartesianLayer
import com.patrykandpatrick.vico.compose.cartesian.rememberCartesianChart
import com.patrykandpatrick.vico.compose.cartesian.rememberVicoScrollState
import com.patrykandpatrick.vico.core.cartesian.Scroll
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModel
import com.patrykandpatrick.vico.sample.previews.annotation.ChartPreview
import com.patrykandpatrick.vico.sample.previews.resource.PreviewSurface
import com.patrykandpatrick.vico.sample.previews.resource.mediumLineModel
import com.patrykandpatrick.vico.sample.previews.resource.shortLineModel
@ChartPreview
@Composable
fun DefaultLineChart(
model: CartesianChartModel = shortLineModel,
scrollable: Boolean = true,
initialScroll: Scroll.Absolute = Scroll.Absolute.Start,
) {
PreviewSurface {
CartesianChartHost(
chart =
rememberCartesianChart(
rememberLineCartesianLayer(),
startAxis = rememberStartAxis(),
bottomAxis = rememberBottomAxis(),
),
model = model,
scrollState = rememberVicoScrollState(scrollable, initialScroll),
)
}
}
@ChartPreview
@Composable
fun DefaultLineChartLongScrollable() {
DefaultLineChart(model = mediumLineModel)
}
@ChartPreview
@Composable
fun DefaultLineChartLongScrollableEnd() {
DefaultLineChart(model = mediumLineModel, initialScroll = Scroll.Absolute.End)
}
@ChartPreview
@Composable
fun DefaultLineChartLongNonScrollable() {
DefaultLineChart(model = mediumLineModel, scrollable = false)
}
@@ -0,0 +1,26 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.previews.resource
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import com.patrykandpatrick.vico.sample.VicoTheme
@Composable
fun PreviewSurface(content: @Composable () -> Unit) {
VicoTheme(useDynamicColor = false) { Surface { content() } }
}
@@ -0,0 +1,35 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.previews.resource
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModel
import com.patrykandpatrick.vico.core.cartesian.data.ColumnCartesianLayerModel
import com.patrykandpatrick.vico.core.cartesian.data.LineCartesianLayerModel
public val shortColumnModel =
CartesianChartModel(ColumnCartesianLayerModel.build { series(1, 2, 4, 8, 3) })
public val mediumColumnModel =
CartesianChartModel(
ColumnCartesianLayerModel.build { series(1, 2, 4, 8, 3, 10, 4, 7, 2, 6, 4, 8) }
)
public val shortLineModel =
CartesianChartModel(LineCartesianLayerModel.build { series(1, 2, 4, 8, 3) })
public val mediumLineModel =
CartesianChartModel(LineCartesianLayerModel.build { series(1, 2, 4, 8, 3, 10, 4, 7, 2, 6, 4, 8) })
@@ -0,0 +1,82 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ListItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.patrykandpatrick.vico.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun ChartListScreen(navController: NavController) {
var uiFramework by rememberSaveable { mutableStateOf(UIFramework.Compose) }
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
Scaffold(
Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
{
TopAppBar(
title = { Text(stringResource(R.string.app_name)) },
scrollBehavior = scrollBehavior,
)
},
) { paddingValues ->
LazyColumn(contentPadding = paddingValues) {
item {
SingleChoiceSegmentedButtonRow(
Modifier.fillMaxWidth().padding(start = 16.dp, end = 16.dp, bottom = 8.dp)
) {
UIFramework.entries.forEachIndexed { index, segmentUIFramework ->
SegmentedButton(
selected = uiFramework == segmentUIFramework,
onClick = { uiFramework = segmentUIFramework },
shape = SegmentedButtonDefaults.itemShape(index, UIFramework.entries.size),
) {
Text(stringResource(segmentUIFramework.labelResourceID))
}
}
}
}
items(charts.size) { chartID ->
ListItem(
{ Text(stringResource(R.string.chart_x, chartID + 1)) },
Modifier.clickable { navController.navigate("chart/$chartID/${uiFramework.ordinal}") },
)
}
}
}
}
@@ -0,0 +1,122 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.navigation.NavController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.patrykandpatrick.vico.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun ChartScreen(navController: NavController, initialChartID: Int, uiFrameworkID: Int) {
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
val nestedNavController = rememberNavController()
val chartID =
nestedNavController.currentBackStackEntryAsState().value?.arguments?.getInt("chartID")
?: initialChartID
val lifecycle = LocalLifecycleOwner.current.lifecycle
val navigateBack = {
if (lifecycle.currentState == Lifecycle.State.RESUMED) navController.popBackStack()
}
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.chart_x, chartID + 1)) },
navigationIcon = {
IconButton(navigateBack) {
Icon(imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
}
},
scrollBehavior = scrollBehavior,
)
},
bottomBar = {
Row(
Modifier.fillMaxWidth().navigationBarsPadding().height(64.dp),
Arrangement.spacedBy(4.dp, Alignment.CenterHorizontally),
Alignment.CenterVertically,
) {
IconButton(
onClick = { nestedNavController.navigate("${chartID - 1}") },
enabled = chartID > 0,
) {
Icon(imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
}
IconButton(
onClick = { nestedNavController.navigate("${chartID + 1}") },
enabled = chartID < charts.lastIndex,
) {
Icon(imageVector = Icons.AutoMirrored.Filled.ArrowForward, contentDescription = null)
}
}
},
) { paddingValues ->
NavHost(
navController = nestedNavController,
startDestination = "{chartID}",
modifier = Modifier.padding(paddingValues),
) {
composable(
"{chartID}",
listOf(
navArgument("chartID") {
type = NavType.IntType
defaultValue = initialChartID
}
),
) { backStackEntry ->
BackHandler(onBack = navigateBack)
val arguments = requireNotNull(backStackEntry.arguments)
charts[arguments.getInt("chartID")](
UIFramework.entries[uiFrameworkID],
Modifier.padding(horizontal = 16.dp),
)
}
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.patrykandpatrick.vico.sample.showcase.charts.Chart1
import com.patrykandpatrick.vico.sample.showcase.charts.Chart10
import com.patrykandpatrick.vico.sample.showcase.charts.Chart2
import com.patrykandpatrick.vico.sample.showcase.charts.Chart3
import com.patrykandpatrick.vico.sample.showcase.charts.Chart4
import com.patrykandpatrick.vico.sample.showcase.charts.Chart5
import com.patrykandpatrick.vico.sample.showcase.charts.Chart6
import com.patrykandpatrick.vico.sample.showcase.charts.Chart7
import com.patrykandpatrick.vico.sample.showcase.charts.Chart8
import com.patrykandpatrick.vico.sample.showcase.charts.Chart9
internal val charts =
listOf<@Composable (UIFramework, Modifier) -> Unit>(
{ uiFramework, modifier -> Chart1(uiFramework, modifier) },
{ uiFramework, modifier -> Chart2(uiFramework, modifier) },
{ uiFramework, modifier -> Chart3(uiFramework, modifier) },
{ uiFramework, modifier -> Chart4(uiFramework, modifier) },
{ uiFramework, modifier -> Chart5(uiFramework, modifier) },
{ uiFramework, modifier -> Chart6(uiFramework, modifier) },
{ uiFramework, modifier -> Chart7(uiFramework, modifier) },
{ uiFramework, modifier -> Chart8(uiFramework, modifier) },
{ uiFramework, modifier -> Chart9(uiFramework, modifier) },
{ uiFramework, modifier -> Chart10(uiFramework, modifier) },
)
@@ -0,0 +1,26 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase
object Defaults {
const val TRANSACTION_INTERVAL_MS = 2000L
const val MULTI_SERIES_COUNT = 3
const val ENTRY_COUNT = 50
const val MAX_Y = 20
const val COLUMN_LAYER_MIN_Y = 2
const val COLUMN_LAYER_RELATIVE_MAX_Y = MAX_Y - COLUMN_LAYER_MIN_Y
}
@@ -0,0 +1,143 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase
import android.text.Layout
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.dp
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisGuidelineComponent
import com.patrykandpatrick.vico.compose.common.component.fixed
import com.patrykandpatrick.vico.compose.common.component.rememberLayeredComponent
import com.patrykandpatrick.vico.compose.common.component.rememberShadow
import com.patrykandpatrick.vico.compose.common.component.rememberShapeComponent
import com.patrykandpatrick.vico.compose.common.component.rememberTextComponent
import com.patrykandpatrick.vico.compose.common.of
import com.patrykandpatrick.vico.compose.common.shape.markerCornered
import com.patrykandpatrick.vico.core.cartesian.CartesianMeasureContext
import com.patrykandpatrick.vico.core.cartesian.HorizontalDimensions
import com.patrykandpatrick.vico.core.cartesian.Insets
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModel
import com.patrykandpatrick.vico.core.cartesian.marker.CartesianMarker
import com.patrykandpatrick.vico.core.cartesian.marker.DefaultCartesianMarker
import com.patrykandpatrick.vico.core.common.Dimensions
import com.patrykandpatrick.vico.core.common.LayeredComponent
import com.patrykandpatrick.vico.core.common.component.Shadow
import com.patrykandpatrick.vico.core.common.component.ShapeComponent
import com.patrykandpatrick.vico.core.common.component.TextComponent
import com.patrykandpatrick.vico.core.common.copyColor
import com.patrykandpatrick.vico.core.common.shape.Corner
import com.patrykandpatrick.vico.core.common.shape.Shape
@Composable
internal fun rememberMarker(
labelPosition: DefaultCartesianMarker.LabelPosition = DefaultCartesianMarker.LabelPosition.Top,
showIndicator: Boolean = true,
): CartesianMarker {
val labelBackgroundShape = Shape.markerCornered(Corner.FullyRounded)
val labelBackground =
rememberShapeComponent(
color = MaterialTheme.colorScheme.surfaceBright,
shape = labelBackgroundShape,
shadow =
rememberShadow(
radius = LABEL_BACKGROUND_SHADOW_RADIUS_DP.dp,
dy = LABEL_BACKGROUND_SHADOW_DY_DP.dp,
),
)
val label =
rememberTextComponent(
color = MaterialTheme.colorScheme.onSurface,
textAlignment = Layout.Alignment.ALIGN_CENTER,
padding = Dimensions.of(8.dp, 4.dp),
background = labelBackground,
minWidth = TextComponent.MinWidth.fixed(40.dp),
)
val indicatorFrontComponent =
rememberShapeComponent(MaterialTheme.colorScheme.surface, Shape.Pill)
val indicatorCenterComponent = rememberShapeComponent(shape = Shape.Pill)
val indicatorRearComponent = rememberShapeComponent(shape = Shape.Pill)
val indicator =
rememberLayeredComponent(
rear = indicatorRearComponent,
front =
rememberLayeredComponent(
rear = indicatorCenterComponent,
front = indicatorFrontComponent,
padding = Dimensions.of(5.dp),
),
padding = Dimensions.of(10.dp),
)
val guideline = rememberAxisGuidelineComponent()
return remember(label, labelPosition, indicator, showIndicator, guideline) {
object :
DefaultCartesianMarker(
label = label,
labelPosition = labelPosition,
indicator =
if (showIndicator) {
{ color ->
LayeredComponent(
rear = ShapeComponent(color.copyColor(alpha = 0.15f), Shape.Pill),
front =
LayeredComponent(
rear =
ShapeComponent(
color = color,
shape = Shape.Pill,
shadow = Shadow(radiusDp = 12f, color = color),
),
front = indicatorFrontComponent,
padding = Dimensions.of(5.dp),
),
padding = Dimensions.of(10.dp),
)
}
} else {
null
},
indicatorSizeDp = 36f,
guideline = guideline,
) {
override fun updateInsets(
context: CartesianMeasureContext,
horizontalDimensions: HorizontalDimensions,
model: CartesianChartModel,
insets: Insets,
) {
with(context) {
val baseShadowInsetDp =
CLIPPING_FREE_SHADOW_RADIUS_MULTIPLIER * LABEL_BACKGROUND_SHADOW_RADIUS_DP
var topInset = (baseShadowInsetDp - LABEL_BACKGROUND_SHADOW_DY_DP).pixels
var bottomInset = (baseShadowInsetDp + LABEL_BACKGROUND_SHADOW_DY_DP).pixels
when (labelPosition) {
LabelPosition.Top,
LabelPosition.AbovePoint -> topInset += label.getHeight(context) + tickSizeDp.pixels
LabelPosition.Bottom -> bottomInset += label.getHeight(context) + tickSizeDp.pixels
LabelPosition.AroundPoint -> {}
}
insets.ensureValuesAtLeast(top = topInset, bottom = bottomInset)
}
}
}
}
}
private const val LABEL_BACKGROUND_SHADOW_RADIUS_DP = 4f
private const val LABEL_BACKGROUND_SHADOW_DY_DP = 2f
private const val CLIPPING_FREE_SHADOW_RADIUS_MULTIPLIER = 1.4f
@@ -0,0 +1,25 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase
import androidx.annotation.StringRes
import com.patrykandpatrick.vico.R
internal enum class UIFramework(@StringRes val labelResourceID: Int) {
Compose(R.string.compose),
Views(R.string.views),
}
@@ -0,0 +1,106 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
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.data.rememberExtraLambda
import com.patrykandpatrick.vico.compose.common.shader.color
import com.patrykandpatrick.vico.core.cartesian.axis.BaseAxis
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
import com.patrykandpatrick.vico.core.cartesian.layer.LineCartesianLayer
import com.patrykandpatrick.vico.core.common.shader.DynamicShader
import com.patrykandpatrick.vico.databinding.Chart1Binding
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Composable
internal fun Chart1(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/line-layer#data. */
lineSeries { series(x, x.map { Random.nextFloat() * 15 }) }
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart1(modelProducer, modifier)
UIFramework.Views -> ViewChart1(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart1(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker()
CartesianChartHost(
chart =
rememberCartesianChart(
rememberLineCartesianLayer(
LineCartesianLayer.LineProvider.series(
rememberLine(DynamicShader.color(Color(0xffa485e0)))
)
),
startAxis = rememberStartAxis(),
bottomAxis = rememberBottomAxis(guideline = null),
marker = marker,
persistentMarkers = rememberExtraLambda(marker) { marker at PERSISTENT_MARKER_X },
),
modelProducer = modelProducer,
modifier = modifier,
zoomState = rememberVicoZoomState(zoomEnabled = false),
)
}
@Composable
private fun ViewChart1(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker()
AndroidViewBinding(
{ inflater, parent, attachToParent ->
Chart1Binding.inflate(inflater, parent, attachToParent).apply {
with(chartView) {
chart?.persistentMarkers = { marker at PERSISTENT_MARKER_X }
this.modelProducer = modelProducer
(chart?.bottomAxis as BaseAxis).guideline = null
chart?.marker = marker
}
}
},
modifier,
)
}
private const val PERSISTENT_MARKER_X = 7f
private val x = (1..50).toList()
@@ -0,0 +1,95 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.fullWidth
import com.patrykandpatrick.vico.compose.cartesian.layer.rememberCandlestickCartesianLayer
import com.patrykandpatrick.vico.compose.cartesian.rememberCartesianChart
import com.patrykandpatrick.vico.core.cartesian.HorizontalLayout
import com.patrykandpatrick.vico.core.cartesian.axis.HorizontalAxis
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.RandomCartesianModelGenerator
import com.patrykandpatrick.vico.databinding.Chart10Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart10(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(key1 = Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/candlestick-layer#data. */
add(RandomCartesianModelGenerator.getRandomCandlestickLayerModelPartial())
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart10(modelProducer, modifier)
UIFramework.Views -> ViewChart10(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart10(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker(showIndicator = false)
CartesianChartHost(
chart =
rememberCartesianChart(
rememberCandlestickCartesianLayer(),
startAxis = rememberStartAxis(),
bottomAxis =
rememberBottomAxis(
guideline = null,
itemPlacer =
remember {
HorizontalAxis.ItemPlacer.default(spacing = 3, addExtremeLabelPadding = true)
},
),
marker = marker,
horizontalLayout = HorizontalLayout.fullWidth(),
),
modelProducer = modelProducer,
modifier = modifier,
)
}
@Composable
private fun ViewChart10(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker(showIndicator = false)
AndroidViewBinding(Chart10Binding::inflate, modifier = modifier) {
chartView.modelProducer = modelProducer
chartView.chart?.marker = marker
}
}
@@ -0,0 +1,178 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.decoration.rememberHorizontalLine
import com.patrykandpatrick.vico.compose.cartesian.fullWidth
import com.patrykandpatrick.vico.compose.cartesian.layer.rememberColumnCartesianLayer
import com.patrykandpatrick.vico.compose.cartesian.rememberCartesianChart
import com.patrykandpatrick.vico.compose.common.component.rememberLineComponent
import com.patrykandpatrick.vico.compose.common.component.rememberShapeComponent
import com.patrykandpatrick.vico.compose.common.component.rememberTextComponent
import com.patrykandpatrick.vico.compose.common.of
import com.patrykandpatrick.vico.core.cartesian.HorizontalLayout
import com.patrykandpatrick.vico.core.cartesian.axis.BaseAxis
import com.patrykandpatrick.vico.core.cartesian.axis.HorizontalAxis
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
import com.patrykandpatrick.vico.core.cartesian.decoration.HorizontalLine
import com.patrykandpatrick.vico.core.cartesian.layer.ColumnCartesianLayer
import com.patrykandpatrick.vico.core.common.Dimensions
import com.patrykandpatrick.vico.core.common.component.LineComponent
import com.patrykandpatrick.vico.core.common.component.ShapeComponent
import com.patrykandpatrick.vico.core.common.component.TextComponent
import com.patrykandpatrick.vico.core.common.shape.Shape
import com.patrykandpatrick.vico.databinding.Chart2Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import java.text.DateFormatSymbols
import java.util.Locale
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart2(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/column-layer#data. */
columnSeries { series(List(47) { 2 + Random.nextFloat() * 18 }) }
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart2(modelProducer, modifier)
UIFramework.Views -> ViewChart2(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart2(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
CartesianChartHost(
chart =
rememberCartesianChart(
rememberColumnCartesianLayer(
ColumnCartesianLayer.ColumnProvider.series(
rememberLineComponent(
color = Color(0xffff5500),
thickness = 16.dp,
shape = remember { Shape.rounded(allPercent = 40) },
)
)
),
startAxis = rememberStartAxis(),
bottomAxis =
rememberBottomAxis(
valueFormatter = bottomAxisValueFormatter,
itemPlacer =
remember {
HorizontalAxis.ItemPlacer.default(spacing = 3, addExtremeLabelPadding = true)
},
),
marker = rememberMarker(),
horizontalLayout = HorizontalLayout.fullWidth(),
decorations = listOf(rememberComposeHorizontalLine()),
),
modelProducer = modelProducer,
modifier = modifier,
)
}
@Composable
private fun ViewChart2(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker()
AndroidViewBinding(
{ inflater, parent, attachToParent ->
Chart2Binding.inflate(inflater, parent, attachToParent).apply {
with(chartView) {
chart?.decorations = listOf(getViewHorizontalLine())
this.modelProducer = modelProducer
(chart?.bottomAxis as BaseAxis).valueFormatter = bottomAxisValueFormatter
chart?.marker = marker
}
}
},
modifier,
)
}
@Composable
private fun rememberComposeHorizontalLine(): HorizontalLine {
val color = Color(HORIZONTAL_LINE_COLOR)
return rememberHorizontalLine(
y = { HORIZONTAL_LINE_Y },
line = rememberLineComponent(color, HORIZONTAL_LINE_THICKNESS_DP.dp),
labelComponent =
rememberTextComponent(
margins = Dimensions.of(HORIZONTAL_LINE_LABEL_MARGIN_DP.dp),
padding =
Dimensions.of(
HORIZONTAL_LINE_LABEL_HORIZONTAL_PADDING_DP.dp,
HORIZONTAL_LINE_LABEL_VERTICAL_PADDING_DP.dp,
),
background = rememberShapeComponent(color, Shape.Pill),
),
)
}
private fun getViewHorizontalLine() =
HorizontalLine(
y = { HORIZONTAL_LINE_Y },
line = LineComponent(HORIZONTAL_LINE_COLOR, HORIZONTAL_LINE_THICKNESS_DP),
labelComponent =
TextComponent(
margins = Dimensions(HORIZONTAL_LINE_LABEL_MARGIN_DP),
padding =
Dimensions(
HORIZONTAL_LINE_LABEL_HORIZONTAL_PADDING_DP,
HORIZONTAL_LINE_LABEL_VERTICAL_PADDING_DP,
),
background = ShapeComponent(HORIZONTAL_LINE_COLOR, Shape.Pill),
),
)
private const val HORIZONTAL_LINE_Y = 14.0
private const val HORIZONTAL_LINE_COLOR = -2893786
private const val HORIZONTAL_LINE_THICKNESS_DP = 2f
private const val HORIZONTAL_LINE_LABEL_HORIZONTAL_PADDING_DP = 8f
private const val HORIZONTAL_LINE_LABEL_VERTICAL_PADDING_DP = 2f
private const val HORIZONTAL_LINE_LABEL_MARGIN_DP = 4f
private val monthNames = DateFormatSymbols.getInstance(Locale.US).shortMonths
private val bottomAxisValueFormatter = CartesianValueFormatter { x, _, _ ->
"${monthNames[x.toInt() % 12]} ${20 + x.toInt() / 12}"
}
@@ -0,0 +1,141 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.R
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.fullWidth
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.rememberFadingEdges
import com.patrykandpatrick.vico.compose.cartesian.rememberVicoZoomState
import com.patrykandpatrick.vico.compose.common.component.rememberShapeComponent
import com.patrykandpatrick.vico.compose.common.component.rememberTextComponent
import com.patrykandpatrick.vico.compose.common.of
import com.patrykandpatrick.vico.compose.common.shader.color
import com.patrykandpatrick.vico.core.cartesian.HorizontalLayout
import com.patrykandpatrick.vico.core.cartesian.axis.VerticalAxis
import com.patrykandpatrick.vico.core.cartesian.data.AxisValueOverrider
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
import com.patrykandpatrick.vico.core.cartesian.layer.LineCartesianLayer
import com.patrykandpatrick.vico.core.cartesian.marker.DefaultCartesianMarker
import com.patrykandpatrick.vico.core.common.Dimensions
import com.patrykandpatrick.vico.core.common.shader.DynamicShader
import com.patrykandpatrick.vico.core.common.shape.Shape
import com.patrykandpatrick.vico.databinding.Chart3Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart3(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/line-layer#data. */
lineSeries { series(List(Defaults.ENTRY_COUNT) { Random.nextFloat() * 20 }) }
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart3(modelProducer, modifier)
UIFramework.Views -> ViewChart3(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart3(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
CartesianChartHost(
chart =
rememberCartesianChart(
rememberLineCartesianLayer(
lineProvider =
LineCartesianLayer.LineProvider.series(rememberLine(DynamicShader.color(lineColor))),
axisValueOverrider = axisValueOverrider,
),
startAxis =
rememberStartAxis(
guideline = null,
horizontalLabelPosition = VerticalAxis.HorizontalLabelPosition.Inside,
titleComponent =
rememberTextComponent(
color = Color.Black,
margins = Dimensions.of(end = 4.dp),
padding = Dimensions.of(8.dp, 2.dp),
background = rememberShapeComponent(lineColor, Shape.Pill),
),
title = stringResource(R.string.y_axis),
),
bottomAxis =
rememberBottomAxis(
titleComponent =
rememberTextComponent(
color = Color.White,
margins = Dimensions.of(top = 4.dp),
padding = Dimensions.of(8.dp, 2.dp),
background = rememberShapeComponent(bottomAxisLabelBackgroundColor, Shape.Pill),
),
title = stringResource(R.string.x_axis),
),
marker = rememberMarker(DefaultCartesianMarker.LabelPosition.AroundPoint),
horizontalLayout = HorizontalLayout.fullWidth(),
fadingEdges = rememberFadingEdges(),
),
modelProducer = modelProducer,
modifier = modifier,
zoomState = rememberVicoZoomState(zoomEnabled = false),
)
}
@Composable
private fun ViewChart3(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker(DefaultCartesianMarker.LabelPosition.AroundPoint)
AndroidViewBinding(Chart3Binding::inflate, modifier) {
with(chartView) {
(chart?.layers?.get(0) as LineCartesianLayer?)?.axisValueOverrider = axisValueOverrider
this.modelProducer = modelProducer
chart?.marker = marker
}
}
}
private val lineColor = Color(0xffffbb00)
private val bottomAxisLabelBackgroundColor = Color(0xff9db591)
private val axisValueOverrider = AxisValueOverrider.adaptiveYValues(yFraction = 1.2f, round = true)
@@ -0,0 +1,130 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberEndAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberTopAxis
import com.patrykandpatrick.vico.compose.cartesian.layer.rememberColumnCartesianLayer
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.shader.color
import com.patrykandpatrick.vico.compose.common.shape.rounded
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
import com.patrykandpatrick.vico.core.cartesian.layer.ColumnCartesianLayer
import com.patrykandpatrick.vico.core.cartesian.layer.LineCartesianLayer
import com.patrykandpatrick.vico.core.common.shader.DynamicShader
import com.patrykandpatrick.vico.core.common.shape.Shape
import com.patrykandpatrick.vico.databinding.Chart4Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart4(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/column-layer#data. */
columnSeries {
repeat(3) {
series(
List(Defaults.ENTRY_COUNT) {
Defaults.COLUMN_LAYER_MIN_Y +
Random.nextFloat() * Defaults.COLUMN_LAYER_RELATIVE_MAX_Y
}
)
}
}
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/line-layer#data. */
lineSeries { series(List(Defaults.ENTRY_COUNT) { Random.nextFloat() * Defaults.MAX_Y }) }
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart4(modelProducer, modifier)
UIFramework.Views -> ViewChart4(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart4(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
CartesianChartHost(
chart =
rememberCartesianChart(
rememberColumnCartesianLayer(
columnProvider =
ColumnCartesianLayer.ColumnProvider.series(
columnColors.map { color ->
rememberLineComponent(color = color, thickness = 8.dp, shape = Shape.rounded(2.dp))
}
)
),
rememberLineCartesianLayer(
LineCartesianLayer.LineProvider.series(
rememberLine(
shader = DynamicShader.color(lineColor),
pointConnector = remember { LineCartesianLayer.PointConnector.cubic(curvature = 0f) },
)
)
),
topAxis = rememberTopAxis(),
endAxis = rememberEndAxis(),
marker = rememberMarker(),
),
modelProducer = modelProducer,
modifier = modifier,
zoomState = rememberVicoZoomState(zoomEnabled = false),
)
}
@Composable
private fun ViewChart4(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker()
AndroidViewBinding(Chart4Binding::inflate, modifier) {
with(chartView) {
this.modelProducer = modelProducer
chart?.marker = marker
}
}
}
private val columnColors = listOf(Color(0xff916cda), Color(0xffd877d8), Color(0xfff094bb))
private val lineColor = Color(0xfffdc8c4)
@@ -0,0 +1,142 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.layer.rememberColumnCartesianLayer
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.core.cartesian.axis.VerticalAxis
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
import com.patrykandpatrick.vico.core.cartesian.layer.ColumnCartesianLayer
import com.patrykandpatrick.vico.core.common.shape.Shape
import com.patrykandpatrick.vico.databinding.Chart5Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart5(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/column-layer#data. */
columnSeries {
repeat(3) {
series(
List(Defaults.ENTRY_COUNT) {
Defaults.COLUMN_LAYER_MIN_Y +
Random.nextFloat() * Defaults.COLUMN_LAYER_RELATIVE_MAX_Y
}
)
}
}
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart5(modelProducer, modifier)
UIFramework.Views -> ViewChart5(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart5(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
CartesianChartHost(
chart =
rememberCartesianChart(
rememberColumnCartesianLayer(
columnProvider =
ColumnCartesianLayer.ColumnProvider.series(
rememberLineComponent(
color = color1,
thickness = COLUMN_THICKNESS_DP.dp,
shape =
Shape.rounded(
bottomLeftPercent = COLUMN_ROUNDNESS_PERCENT,
bottomRightPercent = COLUMN_ROUNDNESS_PERCENT,
),
),
rememberLineComponent(color = color2, thickness = COLUMN_THICKNESS_DP.dp),
rememberLineComponent(
color = color3,
thickness = COLUMN_THICKNESS_DP.dp,
shape =
Shape.rounded(
topLeftPercent = COLUMN_ROUNDNESS_PERCENT,
topRightPercent = COLUMN_ROUNDNESS_PERCENT,
),
),
),
mergeMode = { ColumnCartesianLayer.MergeMode.Stacked },
),
startAxis =
rememberStartAxis(
itemPlacer = startAxisItemPlacer,
labelRotationDegrees = AXIS_LABEL_ROTATION_DEGREES,
),
bottomAxis = rememberBottomAxis(labelRotationDegrees = AXIS_LABEL_ROTATION_DEGREES),
marker = rememberMarker(),
),
modelProducer = modelProducer,
modifier = modifier,
zoomState = rememberVicoZoomState(zoomEnabled = false),
)
}
@Composable
private fun ViewChart5(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker()
AndroidViewBinding(Chart5Binding::inflate, modifier) {
with(chartView) {
this.modelProducer = modelProducer
(chart?.startAxis as VerticalAxis).itemPlacer = startAxisItemPlacer
chart?.marker = marker
}
}
}
private const val COLUMN_ROUNDNESS_PERCENT: Int = 40
private const val COLUMN_THICKNESS_DP: Int = 10
private const val AXIS_LABEL_ROTATION_DEGREES = 45f
private val color1 = Color(0xff6438a7)
private val color2 = Color(0xff3490de)
private val color3 = Color(0xff73e8dc)
private val startAxisItemPlacer = VerticalAxis.ItemPlacer.count({ 3 })
@@ -0,0 +1,177 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.decoration.rememberHorizontalBox
import com.patrykandpatrick.vico.compose.cartesian.layer.rememberColumnCartesianLayer
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.rememberShapeComponent
import com.patrykandpatrick.vico.compose.common.component.rememberTextComponent
import com.patrykandpatrick.vico.compose.common.of
import com.patrykandpatrick.vico.core.cartesian.axis.AxisPosition
import com.patrykandpatrick.vico.core.cartesian.axis.HorizontalAxis
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
import com.patrykandpatrick.vico.core.cartesian.decoration.HorizontalBox
import com.patrykandpatrick.vico.core.cartesian.layer.ColumnCartesianLayer
import com.patrykandpatrick.vico.core.common.Dimensions
import com.patrykandpatrick.vico.core.common.component.ShapeComponent
import com.patrykandpatrick.vico.core.common.component.TextComponent
import com.patrykandpatrick.vico.core.common.copyColor
import com.patrykandpatrick.vico.core.common.shape.Shape
import com.patrykandpatrick.vico.databinding.Chart6Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart6(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/column-layer#data. */
columnSeries {
repeat(Defaults.MULTI_SERIES_COUNT) {
series(
List(Defaults.ENTRY_COUNT) {
Defaults.COLUMN_LAYER_MIN_Y +
Random.nextFloat() * Defaults.COLUMN_LAYER_RELATIVE_MAX_Y
}
)
}
}
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart6(modelProducer, modifier)
UIFramework.Views -> ViewChart6(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart6(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val shape = remember { Shape.cut(topLeftPercent = 50) }
CartesianChartHost(
chart =
rememberCartesianChart(
rememberColumnCartesianLayer(
ColumnCartesianLayer.ColumnProvider.series(
columnColors.map { rememberLineComponent(color = it, thickness = 8.dp, shape = shape) }
)
),
startAxis = rememberStartAxis(),
bottomAxis = rememberBottomAxis(valueFormatter = bottomAxisValueFormatter),
marker = rememberMarker(),
decorations = listOf(rememberComposeHorizontalBox()),
),
modelProducer = modelProducer,
modifier = modifier,
zoomState = rememberVicoZoomState(zoomEnabled = false),
)
}
@Composable
private fun ViewChart6(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker()
AndroidViewBinding(
{ inflater, parent, attachToParent ->
Chart6Binding.inflate(inflater, parent, attachToParent).apply {
with(chartView) {
chart?.decorations = listOf(getViewHorizontalBox())
this.modelProducer = modelProducer
(chart?.bottomAxis as HorizontalAxis<AxisPosition.Horizontal.Bottom>).valueFormatter =
bottomAxisValueFormatter
chart?.marker = marker
}
}
},
modifier,
)
}
@Composable
private fun rememberComposeHorizontalBox(): HorizontalBox {
val color = Color(HORIZONTAL_BOX_COLOR)
return rememberHorizontalBox(
y = { horizontalBoxY },
box = rememberShapeComponent(color = color.copy(HORIZONTAL_BOX_ALPHA)),
labelComponent =
rememberTextComponent(
margins = Dimensions.of(HORIZONTAL_BOX_LABEL_MARGIN_DP.dp),
padding =
Dimensions.of(
HORIZONTAL_BOX_LABEL_HORIZONTAL_PADDING_DP.dp,
HORIZONTAL_BOX_LABEL_VERTICAL_PADDING_DP.dp,
),
background = rememberShapeComponent(color, Shape.Rectangle),
),
)
}
private fun getViewHorizontalBox() =
HorizontalBox(
y = { horizontalBoxY },
box = ShapeComponent(color = HORIZONTAL_BOX_COLOR.copyColor(HORIZONTAL_BOX_ALPHA)),
labelComponent =
TextComponent(
margins = Dimensions(HORIZONTAL_BOX_LABEL_MARGIN_DP),
padding =
Dimensions(
HORIZONTAL_BOX_LABEL_HORIZONTAL_PADDING_DP,
HORIZONTAL_BOX_LABEL_VERTICAL_PADDING_DP,
),
background = ShapeComponent(HORIZONTAL_BOX_COLOR, Shape.Rectangle),
),
)
private const val HORIZONTAL_BOX_COLOR = -1448529
private const val HORIZONTAL_BOX_ALPHA = 0.36f
private const val HORIZONTAL_BOX_LABEL_HORIZONTAL_PADDING_DP = 8f
private const val HORIZONTAL_BOX_LABEL_VERTICAL_PADDING_DP = 2f
private const val HORIZONTAL_BOX_LABEL_MARGIN_DP = 4f
private val columnColors = listOf(Color(0xff3e6558), Color(0xff5e836a), Color(0xffa5ba8e))
private val horizontalBoxY = 7.0..14.0
private val daysOfWeek = listOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
private val bottomAxisValueFormatter = CartesianValueFormatter { x, _, _ ->
daysOfWeek[x.toInt() % daysOfWeek.size]
}
@@ -0,0 +1,164 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.R
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisLabelComponent
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
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.rememberShapeComponent
import com.patrykandpatrick.vico.compose.common.component.rememberTextComponent
import com.patrykandpatrick.vico.compose.common.of
import com.patrykandpatrick.vico.compose.common.rememberLegendItem
import com.patrykandpatrick.vico.compose.common.rememberVerticalLegend
import com.patrykandpatrick.vico.compose.common.shader.color
import com.patrykandpatrick.vico.compose.common.shape.rounded
import com.patrykandpatrick.vico.compose.common.vicoTheme
import com.patrykandpatrick.vico.core.cartesian.CartesianDrawContext
import com.patrykandpatrick.vico.core.cartesian.CartesianMeasureContext
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.layer.LineCartesianLayer
import com.patrykandpatrick.vico.core.common.Dimensions
import com.patrykandpatrick.vico.core.common.shader.DynamicShader
import com.patrykandpatrick.vico.core.common.shape.Shape
import com.patrykandpatrick.vico.databinding.Chart7Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart7(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/line-layer#data. */
lineSeries {
repeat(Defaults.MULTI_SERIES_COUNT) {
series(
List(Defaults.ENTRY_COUNT) {
Defaults.COLUMN_LAYER_MIN_Y +
Random.nextFloat() * Defaults.COLUMN_LAYER_RELATIVE_MAX_Y
}
)
}
}
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart7(modelProducer, modifier)
UIFramework.Views -> ViewChart7(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart7(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
CartesianChartHost(
chart =
rememberCartesianChart(
rememberLineCartesianLayer(
LineCartesianLayer.LineProvider.series(
chartColors.map { color ->
rememberLine(shader = DynamicShader.color(color), backgroundShader = null)
}
)
),
startAxis =
rememberStartAxis(
label = rememberStartAxisLabel(),
horizontalLabelPosition = VerticalAxis.HorizontalLabelPosition.Inside,
),
bottomAxis = rememberBottomAxis(),
marker = rememberMarker(),
legend = rememberLegend(),
),
modelProducer = modelProducer,
modifier = modifier,
zoomState = rememberVicoZoomState(zoomEnabled = false),
)
}
@Composable
private fun ViewChart7(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val startAxisLabel = rememberStartAxisLabel()
val marker = rememberMarker()
val legend = rememberLegend()
AndroidViewBinding(Chart7Binding::inflate, modifier) {
with(chartView) {
this.modelProducer = modelProducer
(chart?.startAxis as VerticalAxis).horizontalLabelPosition =
VerticalAxis.HorizontalLabelPosition.Inside
(chart?.startAxis as VerticalAxis).label = startAxisLabel
chart?.marker = marker
chart?.legend = legend
}
}
}
@Composable
private fun rememberStartAxisLabel() =
rememberAxisLabelComponent(
color = Color.Black,
margins = Dimensions.of(4.dp),
padding = Dimensions.of(8.dp, 2.dp),
background = rememberShapeComponent(Color(0xfffab94d), Shape.rounded(4.dp)),
)
@Composable
private fun rememberLegend() =
rememberVerticalLegend<CartesianMeasureContext, CartesianDrawContext>(
items =
chartColors.mapIndexed { index, chartColor ->
rememberLegendItem(
icon = rememberShapeComponent(chartColor, Shape.Pill),
labelComponent = rememberTextComponent(vicoTheme.textColor),
label = stringResource(R.string.series_x, index + 1),
)
},
iconSize = 8.dp,
iconPadding = 8.dp,
spacing = 4.dp,
padding = Dimensions.of(top = 8.dp),
)
private val chartColors = listOf(Color(0xffb983ff), Color(0xff91b1fd), Color(0xff8fdaff))
@@ -0,0 +1,140 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberEndAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.layer.rememberColumnCartesianLayer
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.shader.color
import com.patrykandpatrick.vico.core.cartesian.axis.AxisPosition
import com.patrykandpatrick.vico.core.cartesian.axis.BaseAxis
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
import com.patrykandpatrick.vico.core.cartesian.layer.ColumnCartesianLayer
import com.patrykandpatrick.vico.core.cartesian.layer.LineCartesianLayer
import com.patrykandpatrick.vico.core.common.shader.DynamicShader
import com.patrykandpatrick.vico.core.common.shape.Shape
import com.patrykandpatrick.vico.databinding.Chart8Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart8(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/column-layer#data. */
columnSeries {
repeat(Defaults.MULTI_SERIES_COUNT) {
series(
List(Defaults.ENTRY_COUNT) {
Defaults.COLUMN_LAYER_MIN_Y +
Random.nextFloat() * Defaults.COLUMN_LAYER_RELATIVE_MAX_Y
}
)
}
}
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/line-layer#data. */
lineSeries { series(List(Defaults.ENTRY_COUNT) { Random.nextFloat() * Defaults.MAX_Y }) }
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart8(modelProducer, modifier)
UIFramework.Views -> ViewChart8(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart8(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
CartesianChartHost(
chart =
rememberCartesianChart(
rememberColumnCartesianLayer(
columnProvider =
ColumnCartesianLayer.ColumnProvider.series(
columnChartColors.map { color ->
rememberLineComponent(color = color, thickness = 8.dp, shape = Shape.rounded(40))
}
),
mergeMode = { ColumnCartesianLayer.MergeMode.Stacked },
verticalAxisPosition = AxisPosition.Vertical.Start,
),
rememberLineCartesianLayer(
lineProvider =
LineCartesianLayer.LineProvider.series(rememberLine(DynamicShader.color(color4))),
verticalAxisPosition = AxisPosition.Vertical.End,
),
startAxis = rememberStartAxis(guideline = null),
endAxis = rememberEndAxis(guideline = null),
bottomAxis = rememberBottomAxis(),
marker = rememberMarker(),
),
modelProducer = modelProducer,
modifier = modifier,
zoomState = rememberVicoZoomState(zoomEnabled = false),
)
}
@Composable
private fun ViewChart8(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker()
AndroidViewBinding(Chart8Binding::inflate, modifier) {
with(chartView) {
(chart?.layers?.get(0) as ColumnCartesianLayer).verticalAxisPosition =
AxisPosition.Vertical.Start
(chart?.layers?.get(1) as LineCartesianLayer).verticalAxisPosition = AxisPosition.Vertical.End
this.modelProducer = modelProducer
(chart?.startAxis as BaseAxis).guideline = null
chart?.marker = marker
}
}
}
private val color1 = Color(0xffa55a5a)
private val color2 = Color(0xffd3756b)
private val color3 = Color(0xfff09b7d)
private val color4 = Color(0xffffc3a1)
private val columnChartColors = listOf(color1, color2, color3)
@@ -0,0 +1,244 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.showcase.charts
import android.graphics.PorterDuff
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import com.patrykandpatrick.vico.R
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberAxisLabelComponent
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottomAxis
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberStartAxis
import com.patrykandpatrick.vico.compose.cartesian.fullWidth
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.common.component.rememberLineComponent
import com.patrykandpatrick.vico.compose.common.component.rememberShapeComponent
import com.patrykandpatrick.vico.compose.common.of
import com.patrykandpatrick.vico.compose.common.shader.color
import com.patrykandpatrick.vico.compose.common.shader.component
import com.patrykandpatrick.vico.compose.common.shader.verticalGradient
import com.patrykandpatrick.vico.compose.common.shape.dashed
import com.patrykandpatrick.vico.core.cartesian.HorizontalLayout
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.lineSeries
import com.patrykandpatrick.vico.core.cartesian.layer.LineCartesianLayer
import com.patrykandpatrick.vico.core.common.Dimensions
import com.patrykandpatrick.vico.core.common.component.ShapeComponent
import com.patrykandpatrick.vico.core.common.shader.DynamicShader
import com.patrykandpatrick.vico.core.common.shader.TopBottomShader
import com.patrykandpatrick.vico.core.common.shape.Shape
import com.patrykandpatrick.vico.databinding.Chart9Binding
import com.patrykandpatrick.vico.sample.showcase.Defaults
import com.patrykandpatrick.vico.sample.showcase.UIFramework
import com.patrykandpatrick.vico.sample.showcase.rememberMarker
import kotlin.random.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext
@Composable
internal fun Chart9(uiFramework: UIFramework, modifier: Modifier) {
val modelProducer = remember { CartesianChartModelProducer() }
LaunchedEffect(Unit) {
withContext(Dispatchers.Default) {
while (isActive) {
modelProducer.runTransaction {
/* Learn more:
https://patrykandpatrick.com/vico/wiki/cartesian-charts/layers/line-layer#data. */
lineSeries { series(x = x, y = x.map { Random.nextFloat() * 30 - 10 }) }
}
delay(Defaults.TRANSACTION_INTERVAL_MS)
}
}
}
when (uiFramework) {
UIFramework.Compose -> ComposeChart9(modelProducer, modifier)
UIFramework.Views -> ViewChart9(modelProducer, modifier)
}
}
@Composable
private fun ComposeChart9(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val colors = chartColors
val marker = rememberMarker()
CartesianChartHost(
chart =
rememberCartesianChart(
rememberLineCartesianLayer(
lineProvider =
LineCartesianLayer.LineProvider.series(
rememberLine(
shader =
TopBottomShader(DynamicShader.color(colors[0]), DynamicShader.color(colors[1])),
backgroundShader =
TopBottomShader(
DynamicShader.compose(
DynamicShader.component(
componentSize = 6.dp,
component =
rememberShapeComponent(
color = colors[0],
shape = Shape.Pill,
margins = Dimensions.of(1.dp),
),
),
DynamicShader.verticalGradient(arrayOf(Color.Black, Color.Transparent)),
PorterDuff.Mode.DST_IN,
),
DynamicShader.compose(
DynamicShader.component(
componentSize = 5.dp,
component =
rememberShapeComponent(
color = colors[1],
shape = Shape.Rectangle,
margins = Dimensions.of(horizontal = 2.dp),
),
checkeredArrangement = false,
),
DynamicShader.verticalGradient(arrayOf(Color.Transparent, Color.Black)),
PorterDuff.Mode.DST_IN,
),
),
)
)
),
startAxis =
rememberStartAxis(
label =
rememberAxisLabelComponent(
color = MaterialTheme.colorScheme.onBackground,
margins = Dimensions.of(end = 8.dp),
padding = Dimensions.of(6.dp, 2.dp),
background =
rememberShapeComponent(
color = Color.Transparent,
shape = Shape.Pill,
strokeColor = MaterialTheme.colorScheme.outlineVariant,
strokeThickness = 1.dp,
),
),
line = null,
tick = null,
guideline =
rememberLineComponent(
color = MaterialTheme.colorScheme.outlineVariant,
shape =
remember { Shape.dashed(shape = Shape.Pill, dashLength = 4.dp, gapLength = 8.dp) },
),
itemPlacer = remember { VerticalAxis.ItemPlacer.count(count = { 4 }) },
),
bottomAxis =
rememberBottomAxis(
guideline = null,
itemPlacer =
remember {
HorizontalAxis.ItemPlacer.default(spacing = 3, addExtremeLabelPadding = true)
},
),
marker = marker,
horizontalLayout = HorizontalLayout.fullWidth(),
),
modelProducer = modelProducer,
modifier = modifier,
)
}
@Composable
private fun ViewChart9(modelProducer: CartesianChartModelProducer, modifier: Modifier) {
val marker = rememberMarker()
val colors = chartColors
AndroidViewBinding(
{ inflater, parent, attachToParent ->
Chart9Binding.inflate(inflater, parent, attachToParent).apply {
with(chartView) {
this.modelProducer = modelProducer
(chart?.bottomAxis as BaseAxis).guideline = null
chart?.marker = marker
with(chart?.layers?.get(0) as LineCartesianLayer) {
lineProvider =
LineCartesianLayer.LineProvider.series(
LineCartesianLayer.Line(
shader =
TopBottomShader(DynamicShader.color(colors[0]), DynamicShader.color(colors[1])),
backgroundShader =
TopBottomShader(
DynamicShader.compose(
DynamicShader.component(
componentSize = 6.dp,
component =
ShapeComponent(
color = colors[0].toArgb(),
shape = Shape.Pill,
margins = Dimensions.of(1.dp),
),
),
DynamicShader.verticalGradient(arrayOf(Color.Black, Color.Transparent)),
PorterDuff.Mode.DST_IN,
),
DynamicShader.compose(
DynamicShader.component(
componentSize = 5.dp,
component =
ShapeComponent(
color = colors[1].toArgb(),
shape = Shape.Rectangle,
margins = Dimensions.of(horizontal = 2.dp),
),
checkeredArrangement = false,
),
DynamicShader.verticalGradient(arrayOf(Color.Transparent, Color.Black)),
PorterDuff.Mode.DST_IN,
),
),
)
)
}
}
}
},
modifier,
)
}
private val chartColors
@ReadOnlyComposable
@Composable
get() =
listOf(
colorResource(id = R.color.chart_9_color_positive),
colorResource(id = R.color.chart_9_color_negative),
)
private val x = (1..100).toList()
@@ -0,0 +1,26 @@
<!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M17.6,9.48l1.84,-3.18c0.16,-0.31 0.04,-0.69 -0.26,-0.85c-0.29,-0.15 -0.65,-0.06 -0.83,0.22l-1.88,3.24c-2.86,-1.21 -6.08,-1.21 -8.94,0L5.65,5.67c-0.19,-0.29 -0.58,-0.38 -0.87,-0.2C4.5,5.65 4.41,6.01 4.56,6.3L6.4,9.48C3.3,11.25 1.28,14.44 1,18h22C22.72,14.44 20.7,11.25 17.6,9.48zM7,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25S8.25,13.31 8.25,14C8.25,14.69 7.69,15.25 7,15.25zM17,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25C18.25,14.69 17.69,15.25 17,15.25z" />
</vector>
@@ -0,0 +1,29 @@
<!--
~ Copyright 2022 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M16,5L9,12L16,19"
android:strokeWidth="2"
android:strokeColor="#000000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</vector>
@@ -0,0 +1,29 @@
<!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M9,5L16,12L9,19"
android:strokeWidth="2"
android:strokeColor="#000000"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</vector>
@@ -0,0 +1,33 @@
<!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#00000000"
android:pathData="M11,3.577C11.619,3.22 12.381,3.22 13,3.577L18.794,6.923C19.413,7.28 19.794,7.94 19.794,8.655V15.345C19.794,16.06 19.413,16.72 18.794,17.077L13,20.423C12.381,20.78 11.619,20.78 11,20.423L5.206,17.077C4.587,16.72 4.206,16.06 4.206,15.345V8.655C4.206,7.94 4.587,7.28 5.206,6.923L11,3.577Z"
android:strokeWidth="2"
android:strokeColor="#000000" />
<path
android:fillColor="#00000000"
android:pathData="M12,8L15.464,10V14L12,16L8.536,14V10L12,8Z"
android:strokeWidth="2"
android:strokeColor="#000000"
android:strokeLineJoin="round" />
</vector>
@@ -0,0 +1,27 @@
<!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#00000000"
android:pathData="M9.5,6H18.5C19.328,6 20,6.672 20,7.5V12M9.5,6H5.5C4.672,6 4,6.672 4,7.5V16.5C4,17.328 4.672,18 5.5,18H9.5M9.5,6V12M9.5,18V12M9.5,18H14.5M9.5,12H14.5M14.5,12V18M14.5,12H20M14.5,18H18.5C19.328,18 20,17.328 20,16.5V12"
android:strokeWidth="2"
android:strokeColor="#000000" />
</vector>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chartZoomEnabled="false"
app:layers="line"
app:lineLayerStyle="@style/Chart1LineLayerStyle"
app:showBottomAxis="true"
app:showStartAxis="true" />
</FrameLayout>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bottomAxisStyle="@style/Chart10BottomAxisStyle"
app:horizontalLayout="fullWidth"
app:layers="candlestick"
app:showBottomAxis="true"
app:showStartAxis="true" />
</FrameLayout>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bottomAxisStyle="@style/Chart2BottomAxisStyle"
app:columnLayerStyle="@style/Chart2ColumnLayerStyle"
app:horizontalLayout="fullWidth"
app:layers="column"
app:showBottomAxis="true"
app:showStartAxis="true" />
</FrameLayout>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:bottomAxisStyle="@style/Chart3BottomAxisStyle"
app:chartZoomEnabled="false"
app:fadingEdgeVisibilityInterpolator="androidx.interpolator.view.animation.FastOutSlowInInterpolator"
app:fadingEdgeWidth="32dp"
app:horizontalLayout="fullWidth"
app:layers="line"
app:lineLayerStyle="@style/Chart3LineLayerStyle"
app:showBottomAxis="true"
app:showStartAxis="true"
app:startAxisStyle="@style/Chart3StartAxisStyle" />
</FrameLayout>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chartZoomEnabled="false"
app:columnLayerStyle="@style/Chart4ColumnLayerStyle"
app:layers="line|column"
app:lineLayerStyle="@style/Chart4LineLayerStyle"
app:showEndAxis="true"
app:showTopAxis="true" />
</FrameLayout>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:axisStyle="@style/Chart5AxisStyle"
app:chartZoomEnabled="false"
app:columnLayerStyle="@style/Chart5ColumnLayerStyle"
app:layers="column"
app:showBottomAxis="true"
app:showStartAxis="true" />
</FrameLayout>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chartZoomEnabled="false"
app:columnLayerStyle="@style/Chart6ColumnLayerStyle"
app:previewColumnSeriesCount="3"
app:layers="column"
app:showBottomAxis="true"
app:showStartAxis="true" />
</FrameLayout>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chartZoomEnabled="false"
app:layers="line"
app:lineLayerStyle="@style/Chart7LineLayerStyle"
app:showBottomAxis="true"
app:showStartAxis="true" />
</FrameLayout>
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:chartZoomEnabled="false"
app:columnLayerStyle="@style/Chart8ColumnLayerStyle"
app:endAxisStyle="@style/Chart8VerticalAxisStyle"
app:layers="line|column"
app:lineLayerStyle="@style/Chart8LineLayerStyle"
app:showBottomAxis="true"
app:showEndAxis="true"
app:showStartAxis="true"
app:startAxisStyle="@style/Chart8VerticalAxisStyle" />
</FrameLayout>
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.patrykandpatrick.vico.views.cartesian.CartesianChartView
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Chart9ThemeOverlay"
app:bottomAxisStyle="@style/Chart9BottomAxisStyle"
app:horizontalLayout="fullWidth"
app:layers="line"
app:lineLayerStyle="@style/Chart9LineLayerStyle"
app:previewMaxX="8"
app:previewMaxY="10"
app:previewMinY="-7"
app:showBottomAxis="true"
app:showStartAxis="true"
app:startAxisStyle="@style/Chart9StartAxisStyle" />
</FrameLayout>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2023 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_9_color_positive">#735cff</color>
<color name="chart_9_color_negative">#ff337d</color>
</resources>
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<style name="Chart10BottomAxisStyle">
<item name="addExtremeHorizontalAxisLabelPadding">true</item>
<item name="horizontalAxisLabelSpacing">3</item>
<item name="showGuidelines">false</item>
</style>
</resources>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_1_color_1">#a485e0</color>
<style name="Chart1Line1Style">
<item name="color">@color/chart_1_color_1</item>
</style>
<style name="Chart1LineLayerStyle">
<item name="line1Style">@style/Chart1Line1Style</item>
</style>
</resources>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_2_color_1">#ff5500</color>
<style name="Chart2BottomAxisStyle">
<item name="addExtremeHorizontalAxisLabelPadding">true</item>
<item name="horizontalAxisLabelSpacing">3</item>
</style>
<style name="Chart2Column1Style">
<item name="color">@color/chart_2_color_1</item>
<item name="thickness">16dp</item>
</style>
<style name="Chart2ColumnLayerStyle">
<item name="column1Style">@style/Chart2Column1Style</item>
</style>
</resources>
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_3_color_1">#ffbb00</color>
<color name="chart_3_color_2">#9db591</color>
<style name="Chart3AxisStyle">
<item name="showTitle">true</item>
</style>
<style name="Chart3AxisTitleStyle">
<item name="android:paddingStart">8dp</item>
<item name="android:paddingTop">2dp</item>
<item name="android:paddingEnd">8dp</item>
<item name="android:paddingBottom">2dp</item>
<item name="typeface">monospace</item>
</style>
<style name="Chart3AxisTitleBackgroundShapeStyle">
<item name="cornerSize">100%</item>
<item name="cornerTreatment">rounded</item>
</style>
<style name="Chart3AxisTitleBackgroundStyle">
<item name="shapeStyle">@style/Chart3AxisTitleBackgroundShapeStyle</item>
</style>
<style name="Chart3BottomAxisTitleBackgroundStyle" parent="Chart3AxisTitleBackgroundStyle">
<item name="color">@color/chart_3_color_2</item>
</style>
<style name="Chart3BottomAxisTitleStyle" parent="Chart3AxisTitleStyle">
<item name="android:color">@android:color/white</item>
<item name="backgroundStyle">@style/Chart3BottomAxisTitleBackgroundStyle</item>
<item name="marginTop">4dp</item>
</style>
<style name="Chart3Line1Style">
<item name="color">@color/chart_3_color_1</item>
</style>
<style name="Chart3StartAxisTitleBackgroundStyle" parent="Chart3AxisTitleBackgroundStyle">
<item name="color">@color/chart_3_color_1</item>
</style>
<style name="Chart3StartAxisTitleStyle" parent="Chart3AxisTitleStyle">
<item name="android:color">@android:color/black</item>
<item name="backgroundStyle">@style/Chart3StartAxisTitleBackgroundStyle</item>
<item name="marginEnd">4dp</item>
</style>
<style name="Chart3BottomAxisStyle" parent="Chart3AxisStyle">
<item name="titleStyle">@style/Chart3BottomAxisTitleStyle</item>
<item name="title">@string/x_axis</item>
</style>
<style name="Chart3LineLayerStyle">
<item name="line1Style">@style/Chart3Line1Style</item>
</style>
<style name="Chart3StartAxisStyle" parent="Chart3AxisStyle">
<item name="showGuidelines">false</item>
<item name="verticalAxisHorizontalLabelPosition">inside</item>
<item name="titleStyle">@style/Chart3StartAxisTitleStyle</item>
<item name="title">@string/y_axis</item>
</style>
</resources>
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_4_color_1">#916cda</color>
<color name="chart_4_color_2">#d877d8</color>
<color name="chart_4_color_3">#f094bb</color>
<color name="chart_4_color_4">#fdc8c4</color>
<style name="Chart4ColumnShapeStyle">
<item name="cornerSize">2dp</item>
</style>
<style name="Chart4ColumnStyle">
<item name="shapeStyle">@style/Chart4ColumnShapeStyle</item>
</style>
<style name="Chart4Column1Style" parent="@style/Chart4ColumnStyle">
<item name="color">@color/chart_4_color_1</item>
</style>
<style name="Chart4Column2Style" parent="@style/Chart4ColumnStyle">
<item name="color">@color/chart_4_color_2</item>
</style>
<style name="Chart4Column3Style" parent="@style/Chart4ColumnStyle">
<item name="color">@color/chart_4_color_3</item>
</style>
<style name="Chart4Line1Style">
<item name="color">@color/chart_4_color_4</item>
<item name="curvature">0%</item>
</style>
<style name="Chart4ColumnLayerStyle">
<item name="column1Style">@style/Chart4Column1Style</item>
<item name="column2Style">@style/Chart4Column2Style</item>
<item name="column3Style">@style/Chart4Column3Style</item>
</style>
<style name="Chart4LineLayerStyle">
<item name="line1Style">@style/Chart4Line1Style</item>
</style>
</resources>
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_5_color_1">#6438a7</color>
<color name="chart_5_color_2">#3490de</color>
<color name="chart_5_color_3">#73e8dc</color>
<style name="Chart5Column1ShapeStyle">
<item name="topStartCornerSize">0dp</item>
<item name="topEndCornerSize">0dp</item>
<item name="bottomEndCornerSize">40%</item>
<item name="bottomStartCornerSize">40%</item>
</style>
<style name="Chart5Column2ShapeStyle">
<item name="cornerSize">0dp</item>
</style>
<style name="Chart5Column3ShapeStyle">
<item name="topStartCornerSize">40%</item>
<item name="topEndCornerSize">40%</item>
<item name="bottomEndCornerSize">0dp</item>
<item name="bottomStartCornerSize">0dp</item>
</style>
<style name="Chart5Column1Style">
<item name="color">@color/chart_5_color_1</item>
<item name="shapeStyle">@style/Chart5Column1ShapeStyle</item>
<item name="thickness">10dp</item>
</style>
<style name="Chart5Column2Style">
<item name="color">@color/chart_5_color_2</item>
<item name="shapeStyle">@style/Chart5Column2ShapeStyle</item>
<item name="thickness">10dp</item>
</style>
<style name="Chart5Column3Style">
<item name="color">@color/chart_5_color_3</item>
<item name="shapeStyle">@style/Chart5Column3ShapeStyle</item>
<item name="thickness">10dp</item>
</style>
<style name="Chart5AxisStyle">
<item name="labelRotationDegrees">45</item>
</style>
<style name="Chart5ColumnLayerStyle">
<item name="column1Style">@style/Chart5Column1Style</item>
<item name="column2Style">@style/Chart5Column2Style</item>
<item name="column3Style">@style/Chart5Column3Style</item>
<item name="mergeMode">stacked</item>
</style>
</resources>
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_6_color_1">#3e6558</color>
<color name="chart_6_color_2">#5e836a</color>
<color name="chart_6_color_3">#a5ba8e</color>
<style name="Chart6ColumnShapeStyle">
<item name="topStartCornerSize">50%</item>
<item name="topStartCornerTreatment">cut</item>
</style>
<style name="Chart6ColumnStyle">
<item name="shapeStyle">@style/Chart6ColumnShapeStyle</item>
</style>
<style name="Chart6Column1Style" parent="@style/Chart6ColumnStyle">
<item name="color">@color/chart_6_color_1</item>
</style>
<style name="Chart6Column2Style" parent="@style/Chart6ColumnStyle">
<item name="color">@color/chart_6_color_2</item>
</style>
<style name="Chart6Column3Style" parent="@style/Chart6ColumnStyle">
<item name="color">@color/chart_6_color_3</item>
</style>
<style name="Chart6ColumnLayerStyle">
<item name="column1Style">@style/Chart6Column1Style</item>
<item name="column2Style">@style/Chart6Column2Style</item>
<item name="column3Style">@style/Chart6Column3Style</item>
</style>
</resources>
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_7_color_1">#b983ff</color>
<color name="chart_7_color_2">#91b1fd</color>
<color name="chart_7_color_3">#8fdaff</color>
<style name="Chart7LineStyle">
<item name="gradientTopColor">@android:color/transparent</item>
<item name="gradientBottomColor">@android:color/transparent</item>
</style>
<style name="Chart7Line1Style" parent="@style/Chart7LineStyle">
<item name="color">@color/chart_7_color_1</item>
</style>
<style name="Chart7Line2Style" parent="@style/Chart7LineStyle">
<item name="color">@color/chart_7_color_2</item>
</style>
<style name="Chart7Line3Style" parent="@style/Chart7LineStyle">
<item name="color">@color/chart_7_color_3</item>
</style>
<style name="Chart7LineLayerStyle">
<item name="line1Style">@style/Chart7Line1Style</item>
<item name="line2Style">@style/Chart7Line2Style</item>
<item name="line3Style">@style/Chart7Line3Style</item>
</style>
</resources>
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_8_color_1">#a55a5a</color>
<color name="chart_8_color_2">#d3756b</color>
<color name="chart_8_color_3">#f09b7d</color>
<color name="chart_8_color_4">#ffc3a1</color>
<style name="Chart8VerticalAxisStyle">
<item name="showGuidelines">false</item>
</style>
<style name="Chart8Column1Style">
<item name="color">@color/chart_8_color_1</item>
</style>
<style name="Chart8Column2Style">
<item name="color">@color/chart_8_color_2</item>
</style>
<style name="Chart8Column3Style">
<item name="color">@color/chart_8_color_3</item>
</style>
<style name="Chart8Line1Style">
<item name="color">@color/chart_8_color_4</item>
</style>
<style name="Chart8ColumnLayerStyle">
<item name="column1Style">@style/Chart8Column1Style</item>
<item name="column2Style">@style/Chart8Column2Style</item>
<item name="column3Style">@style/Chart8Column3Style</item>
<item name="mergeMode">stacked</item>
</style>
<style name="Chart8LineLayerStyle">
<item name="line1Style">@style/Chart8Line1Style</item>
</style>
</resources>
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<color name="chart_9_color_positive">#FF3716FF</color>
<color name="chart_9_color_negative">#FFFF166A</color>
<style name="Chart9Line1Style">
<item name="positiveColor">?colorPrimary</item>
<item name="negativeColor">?colorSecondary</item>
</style>
<style name="Chart9LineLayerStyle">
<item name="line1Style">@style/Chart9Line1Style</item>
</style>
<style name="Chart9BottomAxisStyle">
<item name="horizontalAxisLabelSpacing">3</item>
<item name="showGuidelines">false</item>
<item name="addExtremeHorizontalAxisLabelPadding">true</item>
</style>
<style name="Chart9StartAxisStyle">
<item name="verticalAxisItemCount">4</item>
<item name="labelStyle">@style/Chart9StartAxisLabelStyle</item>
<item name="showTicks">false</item>
<item name="showLine">false</item>
<item name="guidelineStyle">@style/Chart9AxisGuidelineStyle</item>
</style>
<style name="Chart9StartAxisLabelStyle">
<item name="backgroundStyle">@style/Chart9StartAxisLabelBackgroundStyle</item>
<item name="marginEnd">8dp</item>
<item name="android:paddingStart">6dp</item>
<item name="android:paddingEnd">6dp</item>
<item name="android:paddingTop">2dp</item>
<item name="android:paddingBottom">2dp</item>
</style>
<style name="Chart9StartAxisLabelBackgroundStyle">
<item name="color">@android:color/transparent</item>
<item name="shapeStyle">@style/Chart9StartAxisLabelBackgroundShapeStyle</item>
<item name="strokeThickness">1dp</item>
<item name="strokeColor">?colorOutlineVariant</item>
</style>
<style name="Chart9StartAxisLabelBackgroundShapeStyle">
<item name="cornerSize">50%</item>
</style>
<style name="Chart9AxisGuidelineStyle">
<item name="shapeStyle">@style/Chart9AxisGuidelineShapeStyle</item>
<item name="color">?colorOutlineVariant</item>
</style>
<style name="Chart9AxisGuidelineShapeStyle">
<item name="dashLength">4dp</item>
<item name="gapLength">8dp</item>
</style>
<style name="Chart9ThemeOverlay" parent="Theme.Vico">
<item name="colorPrimary">@color/chart_9_color_positive</item>
<item name="colorSecondary">@color/chart_9_color_negative</item>
</style>
</resources>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<string name="app_name">Vico</string>
<string name="compose">Compose</string>
<string name="views">Views</string>
<string name="series_x">Series %d</string>
<string name="x_axis">x-axis</string>
<string name="y_axis">y-axis</string>
<string name="chart_x">Chart %d</string>
</resources>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2024 by Patryk Goworowski and Patrick Michalik.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<style name="Theme.Vico" parent="Theme.Material3.DayNight.NoActionBar" />
</resources>
@@ -0,0 +1,76 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample
import androidx.compose.runtime.Composable
import app.cash.paparazzi.Paparazzi
import com.android.ide.common.rendering.api.SessionParams
import com.patrykandpatrick.vico.sample.paparazzi.lightConfig
import com.patrykandpatrick.vico.sample.paparazzi.nightConfig
import com.patrykandpatrick.vico.sample.previews.composables.column.DefaultColumnChart
import com.patrykandpatrick.vico.sample.previews.composables.column.DefaultColumnChartLongNonScrollable
import com.patrykandpatrick.vico.sample.previews.composables.column.DefaultColumnChartLongScrollable
import com.patrykandpatrick.vico.sample.previews.composables.column.DefaultColumnChartLongScrollableEnd
import com.patrykandpatrick.vico.sample.previews.composables.line.DefaultLineChart
import com.patrykandpatrick.vico.sample.previews.composables.line.DefaultLineChartLongNonScrollable
import com.patrykandpatrick.vico.sample.previews.composables.line.DefaultLineChartLongScrollable
import com.patrykandpatrick.vico.sample.previews.composables.line.DefaultLineChartLongScrollableEnd
import org.junit.Rule
import org.junit.Test
public class PaparazziTest {
private val defaultCharts =
listOf<Pair<String, @Composable () -> Unit>>(
"LineChart" to { DefaultLineChart() },
"LineChart Long Scrollable" to { DefaultLineChartLongScrollable() },
"LineChart Long Scrollable with initial scroll end" to
{
DefaultLineChartLongScrollableEnd()
},
"LineChart Long Not Scrollable" to { DefaultLineChartLongNonScrollable() },
"ColumnChart" to { DefaultColumnChart() },
"ColumnChart Long Scrollable" to { DefaultColumnChartLongScrollable() },
"ColumnChart Long Scrollable with initial scroll end" to
{
DefaultColumnChartLongScrollableEnd()
},
"ColumnChart Long Not Scrollable" to { DefaultColumnChartLongNonScrollable() },
)
@get:Rule
public val paparazzi =
Paparazzi(
deviceConfig = lightConfig,
renderingMode = SessionParams.RenderingMode.SHRINK,
maxPercentDifference = 0.2,
)
private fun List<Pair<String, @Composable () -> Unit>>.snapshotAll() {
forEach { (name, composable) -> paparazzi.snapshot(name) { composable() } }
}
@Test
public fun `Test default charts in NOT NIGHT`() {
defaultCharts.snapshotAll()
}
@Test
public fun `Test default charts in NIGHT`() {
paparazzi.unsafeUpdateConfig(nightConfig)
defaultCharts.snapshotAll()
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2024 by Patryk Goworowski and Patrick Michalik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.patrykandpatrick.vico.sample.paparazzi
import app.cash.paparazzi.DeviceConfig
import com.android.resources.NightMode
internal val lightConfig = DeviceConfig(screenWidth = 1080, screenHeight = 800)
internal val nightConfig = lightConfig.copy(nightMode = NightMode.NIGHT)