├── .editorconfig ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md ├── pull_request_template.md └── workflows │ ├── android.yml │ └── publish.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app ├── .gitignore ├── api │ └── app.api ├── build.gradle.kts └── src │ └── main │ ├── AndroidManifest.xml │ ├── kotlin │ └── io │ │ └── androidpoet │ │ └── drafterdemo │ │ ├── ChartContainer.kt │ │ ├── ChartTitle.kt │ │ ├── MainActivity.kt │ │ ├── bars │ │ ├── GroupedBarChartExample.kt │ │ ├── HistogramChartExample.kt │ │ ├── SimpleBarChartExample.kt │ │ ├── StackedBarChartExample.kt │ │ └── WaterfallChartExample.kt │ │ ├── buble │ │ └── BubbleChart.kt │ │ ├── gantt │ │ └── GanntChartDemo.kt │ │ ├── githubgraph │ │ └── GithubGraph.kt │ │ ├── line │ │ ├── GroupedLineChartExample.kt │ │ ├── ScatterPlotChartExample.kt │ │ ├── SimpleLineChartExample.kt │ │ └── StackedLineChartExample.kt │ │ ├── manager │ │ └── ChartThemeManager.kt │ │ ├── pie │ │ └── PieChartExample.kt │ │ ├── radar │ │ └── RadarChart.kt │ │ └── ui │ │ └── theme │ │ ├── Color.kt │ │ ├── Theme.kt │ │ └── Type.kt │ └── res │ ├── drawable │ ├── ic_launcher_background.xml │ └── ic_launcher_foreground.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-mdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── baselineprofile-app ├── .gitignore ├── api │ └── baselineprofile-app.api ├── build.gradle.kts └── src │ ├── main │ ├── AndroidManifest.xml │ ├── kotlin │ │ └── io │ │ │ └── androidpoet │ │ │ └── drafter │ │ │ └── baselineprofile │ │ │ └── app │ │ │ ├── ChartContainer.kt │ │ │ ├── ChartTitle.kt │ │ │ ├── MainActivity.kt │ │ │ ├── bars │ │ │ ├── GroupedBarChartExample.kt │ │ │ ├── HistogramChartExample.kt │ │ │ ├── SimpleBarChartExample.kt │ │ │ ├── StackedBarChartExample.kt │ │ │ └── WaterfallChartExample.kt │ │ │ ├── buble │ │ │ └── BubbleChart.kt │ │ │ ├── gantt │ │ │ └── GanntChartDemo.kt │ │ │ ├── githubgraph │ │ │ └── GithubGraph.kt │ │ │ ├── line │ │ │ ├── GroupedLineChartExample.kt │ │ │ ├── ScatterPlotChartExample.kt │ │ │ ├── SimpleLineChartExample.kt │ │ │ └── StackedLineChartExample.kt │ │ │ ├── manager │ │ │ └── ChartThemeManager.kt │ │ │ ├── pie │ │ │ └── PieChartExample.kt │ │ │ ├── radar │ │ │ └── RadarChart.kt │ │ │ └── ui │ │ │ └── theme │ │ │ ├── Color.kt │ │ │ ├── Theme.kt │ │ │ └── Type.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── release │ └── generated │ └── baselineProfiles │ └── baseline-prof.txt ├── baselineprofile ├── .gitignore ├── build.gradle.kts └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── io │ └── androidpoet │ └── drafter │ └── baselineprofile │ └── BaselineProfileGenerator.kt ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── io │ └── androidpoet │ └── drafter │ └── Configuration.kt ├── chartsx.mp4 ├── drafter ├── .gitignore ├── api │ ├── android │ │ └── drafter.api │ └── desktop │ │ └── drafter.api ├── build.gradle.kts └── src │ └── commonMain │ ├── baseline-prof.txt │ ├── kotlin │ └── io │ │ └── androidpoet │ │ └── drafter │ │ ├── bars │ │ ├── BarChart.kt │ │ ├── BarChartDataRenderer.kt │ │ ├── model │ │ │ └── BarChartModel.kt │ │ └── renderer │ │ │ ├── BarChartRenderer.kt │ │ │ ├── GroupedBarChartRenderer.kt │ │ │ ├── HistogramRenderer.kt │ │ │ ├── StackedBarChartRenderer.kt │ │ │ └── WaterfallChartRenderer.kt │ │ ├── buble │ │ ├── BarChartRenderer.kt │ │ ├── BubbleChart.kt │ │ ├── BubbleChartData.kt │ │ └── BubbleChartDataRenderer.kt │ │ ├── gant │ │ ├── GantChart.kt │ │ ├── GantChartData.kt │ │ └── GanttChartRenderer.kt │ │ ├── heatmap │ │ ├── HeatMapData.kt │ │ ├── Heatmap.kt │ │ └── HeatmapDataRenderer.kt │ │ ├── lines │ │ ├── LineChart.kt │ │ ├── LineChartDataRenderer.kt │ │ ├── model │ │ │ └── LineChartData.kt │ │ └── renderer │ │ │ ├── GroupedLineChartRenderer.kt │ │ │ ├── LineChartRenderer.kt │ │ │ └── StackedLineChartRenderer.kt │ │ ├── pie │ │ ├── PieChart.kt │ │ ├── model │ │ │ └── PieChartData.kt │ │ └── renderer │ │ │ ├── DonutChartRenderer.kt │ │ │ ├── PieChartDataRenderer.kt │ │ │ └── PieChartRenderer.kt │ │ ├── popup │ │ └── Tooltip.kt │ │ ├── radar │ │ ├── RadarChart.kt │ │ ├── RadarChartDataRenderer.kt │ │ ├── model │ │ │ └── RadarChartData.kt │ │ └── renderer │ │ │ └── RadarChartRenderer.kt │ │ └── scatterplot │ │ ├── ScatterPlotChart.kt │ │ ├── ScatterPlotChartRenderer.kt │ │ └── model │ │ └── ScatterPlotData.kt │ └── resources │ └── files │ └── countries.json ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── kotlin-js-store └── yarn.lock ├── renovate.json ├── scripts └── publish-module.gradle.kts ├── settings.gradle.kts └── spotless ├── copyright.kt ├── copyright.kts └── copyright.xml /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | # Most of the standard properties are supported 4 | indent_size=2 5 | max_line_length=100 6 | 7 | ktlint_standard_function-naming = disabled 8 | ktlint_standard_property-naming = disabled 9 | ktlint_standard_filename = disabled 10 | ktlint_standard_no-empty-file = disabled -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # More details are here: https://help.github.com/articles/about-codeowners/ 5 | 6 | # The '*' pattern is global owners. 7 | # Not adding in this PR, but I'd like to try adding a global owner set with the entire team. 8 | # One interpretation of their docs is that global owners are added only if not removed 9 | # by a more local rule. 10 | 11 | # Order is important. The last matching pattern has the most precedence. 12 | # The folders are ordered as follows: 13 | 14 | # In each subsection folders are ordered first by depth, then alphabetically. 15 | # This should make it easy to add new rules without breaking existing ones. 16 | * @androidpoet -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: androidpoet 2 | custom: ["https://www.buymeacoffee.com/androidpoet"] 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Something is crashing or not working as intended 4 | 5 | --- 6 | 7 | **Please complete the following information:** 8 | - Library Version [e.g. v1.0.0] 9 | - Affected Device(s) [e.g. Samsung Galaxy s10 with Android 9.0] 10 | 11 | **Describe the Bug:** 12 | 13 | Add a clear description about the problem. 14 | 15 | **Expected Behavior:** 16 | 17 | A clear description of what you expected to happen. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem?** 8 | 9 | A clear and concise description of what the problem is. 10 | 11 | **Describe the solution you'd like:** 12 | 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered:** 16 | 17 | A clear description of any alternative solutions you've considered. 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Guidelines 2 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. 3 | 4 | ### Types of changes 5 | What types of changes does your code introduce? 6 | 7 | - [ ] Bugfix (non-breaking change which fixes an issue) 8 | - [ ] New feature (non-breaking change which adds functionality) 9 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 10 | 11 | ### Preparing a pull request for review 12 | Ensure your change is properly formatted by running: 13 | 14 | ```gradle 15 | $ ./gradlew spotlessApply 16 | ``` 17 | 18 | Please correct any failures before requesting a review. -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | lint: 11 | name: Spotless check 12 | runs-on: macos-latest 13 | steps: 14 | - name: Check out code 15 | uses: actions/checkout@v2 16 | - name: Set up JDK 17 | uses: actions/setup-java@v1 18 | with: 19 | distribution: zulu 20 | java-version: 17 21 | - name: spotless 22 | run: ./gradlew spotlessCheck 23 | 24 | api_check: 25 | name: API check 26 | runs-on: macos-latest 27 | steps: 28 | - name: Check out code 29 | uses: actions/checkout@v2 30 | - name: Set up JDK 31 | uses: actions/setup-java@v1 32 | with: 33 | distribution: zulu 34 | java-version: 17 35 | - name: API check 36 | run: ./gradlew apiCheck 37 | 38 | build: 39 | runs-on: macos-latest 40 | steps: 41 | - uses: actions/checkout@v2 42 | 43 | - name: set up JDK 44 | uses: actions/setup-java@v1 45 | with: 46 | distribution: zulu 47 | java-version: 17 48 | 49 | - name: Cache Gradle and wrapper 50 | uses: actions/cache@v2 51 | with: 52 | path: | 53 | ~/.gradle/caches 54 | ~/.gradle/wrapper 55 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} 56 | restore-keys: | 57 | ${{ runner.os }}-gradle- 58 | 59 | - name: Make Gradle executable 60 | run: chmod +x ./gradlew 61 | 62 | - name: Build with Gradle 63 | run: | 64 | ./gradlew --scan --stacktrace \ 65 | assemble -x :baselineprofile:pixel6api31Setup -x :baselineprofile:pixel6api31NonMinifiedReleaseAndroidTest -x :baselineprofile:collectNonMinifiedReleaseBaselineProfile -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: [ released ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | publish: 10 | name: Snapshot build and publish 11 | runs-on: macos-latest 12 | steps: 13 | - name: Check out code 14 | uses: actions/checkout@v3.1.0 15 | 16 | - name: Set up JDK 17 17 | uses: actions/setup-java@v3.5.1 18 | with: 19 | distribution: 'zulu' 20 | java-version: 17 21 | 22 | - name: Grant Permission to Execute Gradle 23 | run: chmod +x gradlew 24 | 25 | - name: Release build 26 | run: ./gradlew assemble --scan -x :baselineprofile:pixel6api31Setup -x :baselineprofile:pixel6api31NonMinifiedReleaseAndroidTest -x :baselineprofile:collectNonMinifiedReleaseBaselineProfile 27 | 28 | - name: Publish to MavenCentral 29 | run: | 30 | ./gradlew publishAllPublicationsToMavenCentral --no-configuration-cache 31 | env: 32 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.OSSRH_USERNAME }} 33 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.OSSRH_PASSWORD }} 34 | ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }} 35 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} 36 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Kotlin class files 12 | .kotlin 13 | 14 | # Generated files 15 | bin/ 16 | gen/ 17 | out/ 18 | 19 | # Gradle files 20 | /.idea 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # Intellij 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/dictionaries 45 | .idea/libraries 46 | app/.idea/ 47 | 48 | # Mac 49 | *.DS_Store 50 | 51 | # Keystore files 52 | *.jks 53 | 54 | # External native build folder generated in Android Studio 2.2 and later 55 | .externalNativeBuild 56 | 57 | # Google Services (e.g. APIs or Firebase) 58 | google-services.json 59 | 60 | # Freeline 61 | freeline.py 62 | freeline/ 63 | freeline_project_description.json 64 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute 2 | We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. 3 | 4 | ## Preparing a pull request for review 5 | Ensure your change is properly formatted by running: 6 | 7 | ```gradle 8 | ./gradlew spotlessApply 9 | ``` 10 | 11 | Then dump binary API of this library that is public in sense of Kotlin visibilities and ensures that the public binary API wasn't changed in a way that make this change binary incompatible. 12 | 13 | ```gradle 14 | ./gradlew apiDump 15 | ``` 16 | 17 | Please correct any failures before requesting a review. 18 | 19 | ## Code reviews 20 | All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) for more information on using pull requests. 21 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | import io.androidpoet.drafter.Configuration 3 | 4 | @Suppress("DSL_SCOPE_VIOLATION") 5 | plugins { 6 | id( 7 | libs.plugins.android.application 8 | .get() 9 | .pluginId, 10 | ) 11 | id( 12 | libs.plugins.kotlin.android 13 | .get() 14 | .pluginId, 15 | ) 16 | id( 17 | libs.plugins.compose.compiler 18 | .get() 19 | .pluginId, 20 | ) 21 | } 22 | 23 | android { 24 | compileSdk = Configuration.compileSdk 25 | namespace = "io.androidpoet.drafterdemo" 26 | defaultConfig { 27 | applicationId = "io.androidpoet.drafterdemo" 28 | minSdk = Configuration.minSdk 29 | targetSdk = Configuration.targetSdk 30 | versionCode = Configuration.versionCode 31 | versionName = Configuration.versionName 32 | } 33 | 34 | compileOptions { 35 | sourceCompatibility = JavaVersion.VERSION_11 36 | targetCompatibility = JavaVersion.VERSION_11 37 | } 38 | 39 | kotlinOptions { 40 | jvmTarget = libs.versions.jvmTarget.get() 41 | } 42 | 43 | buildFeatures { 44 | compose = true 45 | buildConfig = true 46 | } 47 | 48 | packaging { 49 | resources { 50 | excludes.add("/META-INF/{AL2.0,LGPL2.1}") 51 | } 52 | } 53 | 54 | lint { 55 | abortOnError = false 56 | } 57 | buildTypes { 58 | getByName("release") { 59 | signingConfig = signingConfigs.getByName("debug") 60 | } 61 | } 62 | } 63 | 64 | dependencies { 65 | implementation(platform(libs.androidx.compose.bom)) 66 | implementation(libs.androidx.activity.compose) 67 | implementation(libs.androidx.compose.ui) 68 | implementation(libs.androidx.compose.ui.tooling) 69 | implementation(libs.androidx.compose.foundation) 70 | implementation(libs.androidx.compose.runtime) 71 | implementation(libs.androidx.compose.material) 72 | implementation(libs.androidx.compose.material3) 73 | implementation(libs.kotlinx.datetime) 74 | implementation(project(":drafter")) 75 | } 76 | task("testClasses") {} 77 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 21 | 31 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/ChartContainer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo 17 | 18 | import androidx.compose.foundation.layout.Box 19 | import androidx.compose.foundation.layout.fillMaxWidth 20 | import androidx.compose.foundation.layout.height 21 | import androidx.compose.foundation.layout.padding 22 | import androidx.compose.runtime.Composable 23 | import androidx.compose.ui.Alignment 24 | import androidx.compose.ui.Modifier 25 | import androidx.compose.ui.unit.dp 26 | 27 | @Composable 28 | fun ChartContainer( 29 | modifier: Modifier = Modifier, 30 | content: @Composable () -> Unit, 31 | ) { 32 | Box( 33 | modifier = 34 | modifier 35 | .fillMaxWidth() 36 | .height(200.dp) 37 | .padding(horizontal = 16.dp), 38 | contentAlignment = Alignment.Center, 39 | ) { 40 | content() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/ChartTitle.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.padding 20 | import androidx.compose.material3.MaterialTheme 21 | import androidx.compose.material3.Text 22 | import androidx.compose.runtime.Composable 23 | import androidx.compose.ui.Modifier 24 | import androidx.compose.ui.text.style.TextAlign 25 | import androidx.compose.ui.unit.dp 26 | 27 | @Composable 28 | fun ChartTitle( 29 | text: String, 30 | modifier: Modifier = Modifier, 31 | ) { 32 | Text( 33 | text = text, 34 | modifier = 35 | modifier 36 | .padding(horizontal = 16.dp) 37 | .fillMaxWidth(), 38 | style = MaterialTheme.typography.titleLarge, 39 | textAlign = TextAlign.Center, 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/bars/GroupedBarChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.bars 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.bars.BarChart 25 | import io.androidpoet.drafter.bars.model.GroupedBarChartData 26 | import io.androidpoet.drafter.bars.renderer.GroupedBarChartRenderer 27 | 28 | private fun getBarChartRenderer() = 29 | GroupedBarChartRenderer( 30 | GroupedBarChartData( 31 | labelsList = listOf("2020", "2021", "2022"), 32 | itemNames = listOf("Product A", "Product B", "Product C"), 33 | groupedValues = 34 | listOf( 35 | listOf(10f, 20f, 15f), // 2020 36 | listOf(25f, 5f, 30f), // 2021 37 | listOf(12f, 28f, 10f), // 2022 38 | ), 39 | colors = listOf(Color.Red, Color.Green, Color.Blue), 40 | ), 41 | ) 42 | 43 | @Composable 44 | fun GroupedBarChartExample( 45 | colors: List, 46 | modifier: Modifier = Modifier, 47 | ) { 48 | BarChart( 49 | renderer = getBarChartRenderer(), 50 | modifier = 51 | Modifier 52 | .height(300.dp) 53 | .fillMaxWidth(), 54 | animate = true, 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/bars/HistogramChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.bars 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.bars.BarChart 25 | import io.androidpoet.drafter.bars.renderer.HistogramRenderer 26 | 27 | private fun getHistogramData() = listOf(1f, 2f, 2f, 3f, 3f, 3f, 4f, 4f, 5f, 5f, 5f, 5f) 28 | 29 | private fun getHistogramRenderer() = 30 | HistogramRenderer( 31 | dataPoints = getHistogramData(), 32 | binCount = 5, 33 | color = Color.Blue, 34 | ) 35 | 36 | @Composable 37 | fun HistogramChartExample( 38 | modifier: Modifier = Modifier, 39 | animate: Boolean = true, 40 | ) { 41 | BarChart( 42 | renderer = getHistogramRenderer(), 43 | modifier = 44 | modifier 45 | .height(300.dp) 46 | .fillMaxWidth(), 47 | animate = animate, 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/bars/SimpleBarChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.bars 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.bars.BarChart 25 | import io.androidpoet.drafter.bars.model.SimpleBarChartData 26 | import io.androidpoet.drafter.bars.renderer.BarChartRenderer 27 | 28 | private fun getBarChartData(colors: List) = 29 | SimpleBarChartData( 30 | labelsList = listOf("Jan", "Feb", "Mar", "Apr"), 31 | values = listOf(10f, 30f, 15f, 45f), 32 | colors = colors, 33 | ) 34 | 35 | private fun getSimpleBarChartRenderer(colors: List) = 36 | BarChartRenderer(getBarChartData(colors = colors)) 37 | 38 | @Composable 39 | fun SimpleBarChartExample( 40 | colors: List, 41 | modifier: Modifier = Modifier, 42 | ) { 43 | BarChart( 44 | renderer = getSimpleBarChartRenderer(colors = colors), 45 | modifier = 46 | modifier 47 | .height(300.dp) 48 | .fillMaxWidth(), 49 | animate = true, 50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/bars/StackedBarChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.bars 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.bars.BarChart 25 | import io.androidpoet.drafter.bars.model.StackedBarChartData 26 | import io.androidpoet.drafter.bars.renderer.StackedBarChartRenderer 27 | 28 | private fun getStackedBarChartData(colors: List) = 29 | StackedBarChartData( 30 | labelsList = listOf("Q1", "Q2", "Q3"), 31 | stacks = 32 | listOf( 33 | listOf(10f, 15f, 5f), // Q1 34 | listOf(8f, 12f, 20f), // Q2 35 | listOf(18f, 10f, 15f), // Q3 36 | ), 37 | colors = colors, 38 | ) 39 | 40 | private fun getStackedBarChartRenderer(colors: List) = 41 | StackedBarChartRenderer(getStackedBarChartData(colors = colors)) 42 | 43 | @Composable 44 | fun StackedBarChartExample( 45 | colors: List, 46 | modifier: Modifier = Modifier, 47 | ) { 48 | BarChart( 49 | renderer = getStackedBarChartRenderer(colors = colors), 50 | modifier = 51 | modifier 52 | .height(300.dp) 53 | .fillMaxWidth(), 54 | animate = true, 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/bars/WaterfallChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.bars 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.bars.BarChart 25 | import io.androidpoet.drafter.bars.model.WaterfallChartData 26 | import io.androidpoet.drafter.bars.renderer.WaterfallChartRenderer 27 | 28 | private fun getWaterfallChartRenderer(colors: List) = 29 | WaterfallChartRenderer( 30 | WaterfallChartData( 31 | labelsList = listOf("Start", "Revenue", "Cost", "Profit"), 32 | values = listOf(+50f, -20f, +30f), // Changes from 'Start' 33 | colors = colors, 34 | initialValue = 100f, // Start from 100 35 | ), 36 | ) 37 | 38 | @Composable 39 | fun WaterfallChartExample( 40 | colors: List, 41 | modifier: Modifier = Modifier, 42 | ) { 43 | BarChart( 44 | renderer = getWaterfallChartRenderer(colors = colors), 45 | modifier = 46 | modifier 47 | .height(300.dp) 48 | .fillMaxWidth(), 49 | animate = true, 50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/buble/BubbleChart.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.buble 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.buble.BubbleChart 25 | import io.androidpoet.drafter.buble.BubbleChartData 26 | import io.androidpoet.drafter.buble.SimpleBubbleChartDataRenderer 27 | 28 | private fun getBubbleChartData(colors: List) = 29 | BubbleChartData( 30 | series = 31 | listOf( 32 | listOf( 33 | BubbleChartData.BubbleData(10f, 26f, 30f, colors[0]), 34 | BubbleChartData.BubbleData(26f, 30f, 60f, colors[0]), 35 | BubbleChartData.BubbleData(26f, 46f, 45f, colors[0]), 36 | ), 37 | listOf( 38 | BubbleChartData.BubbleData(14f, 15f, 30f, colors[1]), 39 | BubbleChartData.BubbleData(22f, 36f, 45f, colors[1]), 40 | BubbleChartData.BubbleData(90f, 57f, 75f, colors[1]), 41 | ), 42 | listOf( 43 | BubbleChartData.BubbleData(8f, 9f, 90f, colors[2]), 44 | BubbleChartData.BubbleData(20f, 57f, 45f, colors[2]), 45 | BubbleChartData.BubbleData(40f, 50f, 60f, colors[2]), 46 | ), 47 | listOf( 48 | BubbleChartData.BubbleData(8f, 20f, 22.5f, colors[3]), 49 | BubbleChartData.BubbleData(12f, 30f, 30f, colors[3]), 50 | BubbleChartData.BubbleData(30f, 40f, 45f, colors[3]), 51 | ), 52 | ), 53 | ) 54 | 55 | private fun getBubbleChartRenderer(colors: List) = 56 | SimpleBubbleChartDataRenderer(getBubbleChartData(colors = colors)) 57 | 58 | @Composable 59 | fun BubbleChartExample( 60 | colors: List, 61 | modifier: Modifier = Modifier, 62 | ) { 63 | BubbleChart( 64 | renderer = getBubbleChartRenderer(colors = colors), 65 | modifier = 66 | modifier 67 | .height(300.dp) 68 | .fillMaxWidth(), 69 | ) 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/gantt/GanntChartDemo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.gantt 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.gant.GanttChart 25 | import io.androidpoet.drafter.gant.GanttChartData 26 | import io.androidpoet.drafter.gant.GanttChartRenderer 27 | import io.androidpoet.drafter.gant.GanttTask 28 | 29 | private fun getGanttChartRenderer(colors: List) = 30 | GanttChartRenderer( 31 | GanttChartData( 32 | taskColors = colors, 33 | tasks = 34 | listOf( 35 | GanttTask("Planning", 0f, 2f), 36 | GanttTask("Design", 2f, 2f), 37 | GanttTask("Development", 4f, 3f), 38 | GanttTask("Testing", 7f, 2f), 39 | GanttTask("Deployment", 9f, 1f), 40 | ), 41 | ), 42 | ) 43 | 44 | @Composable 45 | fun GanttChartExample( 46 | colors: List, 47 | modifier: Modifier = Modifier, 48 | ) { 49 | GanttChart( 50 | renderer = getGanttChartRenderer(colors = colors), 51 | modifier = 52 | modifier 53 | .height(300.dp) 54 | .fillMaxWidth(), 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/githubgraph/GithubGraph.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.githubgraph 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.heatmap.ContributionData 25 | import io.androidpoet.drafter.heatmap.ContributionHeatmapData 26 | import io.androidpoet.drafter.heatmap.Heatmap 27 | import io.androidpoet.drafter.heatmap.HeatmapRenderer 28 | import kotlinx.datetime.Clock 29 | import kotlin.random.Random 30 | import kotlin.time.Duration.Companion.days 31 | 32 | private fun getHeatmapRenderer(color: Color) = 33 | HeatmapRenderer( 34 | ContributionHeatmapData( 35 | baseColor = color, 36 | contributions = 37 | buildList { 38 | val now = Clock.System.now() 39 | repeat(365) { day -> 40 | val date = now.minus(day.days) 41 | val count = if (Random.nextFloat() > 0.6f) Random.nextInt(1, 15) else 0 42 | add(ContributionData(date, count)) 43 | } 44 | }, 45 | ), 46 | ) 47 | 48 | @Composable 49 | fun GithubGraph( 50 | color: Color, 51 | modifier: Modifier = Modifier, 52 | ) { 53 | Heatmap( 54 | renderer = getHeatmapRenderer(color = color), 55 | modifier = 56 | modifier 57 | .height(300.dp) 58 | .fillMaxWidth(), 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/line/GroupedLineChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.line 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.lines.LineChart 25 | import io.androidpoet.drafter.lines.model.GroupedLineChartData 26 | import io.androidpoet.drafter.lines.renderer.GroupedLineChartRenderer 27 | import io.androidpoet.drafterdemo.ChartContainer 28 | 29 | private fun getGroupedLineChartData(colors: List) = 30 | GroupedLineChartData( 31 | labels = listOf("Q1", "Q2", "Q3", "Q4"), 32 | itemNames = listOf("Product A", "Product B"), 33 | groupedValues = 34 | listOf( 35 | listOf(10f, 15f), 36 | listOf(20f, 25f), 37 | listOf(15f, 10f), 38 | listOf(25f, 20f), 39 | ), 40 | colors = colors, 41 | ) 42 | 43 | private fun getGroupedLineChartRenderer(colors: List) = 44 | GroupedLineChartRenderer(getGroupedLineChartData(colors = colors)) 45 | 46 | @Composable 47 | fun GroupedLineChartExample( 48 | colors: List, 49 | modifier: Modifier = Modifier, 50 | ) { 51 | ChartContainer { 52 | LineChart( 53 | renderer = getGroupedLineChartRenderer(colors = colors), 54 | modifier = 55 | modifier 56 | .height(300.dp) 57 | .fillMaxWidth(), 58 | ) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/line/ScatterPlotChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.line 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.scatterplot.ScatterPlot 25 | import io.androidpoet.drafter.scatterplot.SimpleScatterPlotRenderer 26 | import io.androidpoet.drafter.scatterplot.model.ScatterPlotData 27 | import kotlin.math.roundToInt 28 | import kotlin.random.Random 29 | 30 | private fun getScatterPlotRenderer(colors: List) = 31 | SimpleScatterPlotRenderer( 32 | ScatterPlotData( 33 | points = 34 | List(30) { 35 | Pair( 36 | (Random.nextFloat() * 10).roundToInt() / 10f, 37 | (Random.nextFloat() * 10).roundToInt() / 10f, 38 | ) 39 | }, 40 | pointColors = 41 | List(30) { 42 | if (colors.isNotEmpty()) colors[it % colors.size] else Color.Gray 43 | }, 44 | ), 45 | ) 46 | 47 | @Composable 48 | fun ScatterPlotChartExample( 49 | colors: List, 50 | modifier: Modifier = Modifier, 51 | ) { 52 | ScatterPlot( 53 | modifier = 54 | Modifier 55 | .height(300.dp) 56 | .fillMaxWidth(), 57 | renderer = getScatterPlotRenderer(colors = colors), 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/line/SimpleLineChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.line 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.lines.LineChart 25 | import io.androidpoet.drafter.lines.model.SimpleLineChartData 26 | import io.androidpoet.drafter.lines.renderer.LineChartRenderer 27 | 28 | private fun getLineChartRenderer(colors: List) = 29 | LineChartRenderer( 30 | SimpleLineChartData( 31 | labels = listOf("A", "B", "C", "D"), 32 | values = listOf(10f, 20f, 15f, 25f), 33 | color = colors.first(), 34 | ), 35 | ) 36 | 37 | @Composable 38 | fun SimpleLineChartExample( 39 | colors: List, 40 | modifier: Modifier = Modifier, 41 | ) { 42 | LineChart( 43 | renderer = getLineChartRenderer(colors = colors), 44 | modifier = 45 | modifier 46 | .height(300.dp) 47 | .fillMaxWidth(), 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/line/StackedLineChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.line 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.lines.LineChart 25 | import io.androidpoet.drafter.lines.model.StackedLineChartData 26 | import io.androidpoet.drafter.lines.renderer.StackedLineChartRenderer 27 | import io.androidpoet.drafterdemo.ChartContainer 28 | 29 | private fun getStackedLineChartRenderer(colors: List) = 30 | StackedLineChartRenderer( 31 | StackedLineChartData( 32 | labels = listOf("Jan", "Feb", "Mar", "Apr"), 33 | stacks = 34 | listOf( 35 | listOf(5f, 5f, 2f), 36 | listOf(7f, 3f, 4f), 37 | listOf(6f, 4f, 3f), 38 | listOf(8f, 2f, 5f), 39 | ), 40 | colors = colors, 41 | ), 42 | ) 43 | 44 | @Composable 45 | fun StackedLineChartExample( 46 | colors: List, 47 | modifier: Modifier = Modifier, 48 | ) { 49 | ChartContainer { 50 | LineChart( 51 | renderer = getStackedLineChartRenderer(colors = colors), 52 | modifier = 53 | modifier 54 | .height(300.dp) 55 | .fillMaxWidth(), 56 | ) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/manager/ChartThemeManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.manager 17 | 18 | import androidx.compose.runtime.State 19 | import androidx.compose.runtime.mutableStateOf 20 | import androidx.compose.ui.graphics.Color 21 | 22 | object ChartThemeManager { 23 | enum class ColorTheme { 24 | MATERIAL, 25 | MODERN, 26 | NATURE, 27 | PROFESSIONAL, 28 | } 29 | 30 | private val palettes = 31 | mapOf( 32 | ColorTheme.MATERIAL to 33 | listOf( 34 | Color(0xFF2196F3), // Primary Blue 35 | Color(0xFFFF9800), // Orange 36 | Color(0xFF4CAF50), // Green 37 | Color(0xFFF44336), // Red 38 | Color(0xFF9C27B0), // Purple 39 | Color(0xFF795548), // Brown 40 | Color(0xFF009688), // Teal 41 | Color(0xFFE91E63), // Pink 42 | ), 43 | ColorTheme.MODERN to 44 | listOf( 45 | Color(0xFF7E57C2), // Purple 46 | Color(0xFF26A69A), // Teal 47 | Color(0xFFFF7043), // Coral 48 | Color(0xFF66BB6A), // Light Green 49 | Color(0xFF5C6BC0), // Indigo 50 | Color(0xFFFFCA28), // Amber 51 | Color(0xFF42A5F5), // Light Blue 52 | Color(0xFFEC407A), // Pink 53 | ), 54 | ColorTheme.NATURE to 55 | listOf( 56 | Color(0xFF66BB6A), // Green 57 | Color(0xFF42A5F5), // Sky Blue 58 | Color(0xFFFFB74D), // Light Orange 59 | Color(0xFF8D6E63), // Brown 60 | Color(0xFF26A69A), // Sea Green 61 | Color(0xFFFFCC80), // Pale Orange 62 | Color(0xFF81C784), // Light Green 63 | Color(0xFF7986CB), // Blue Grey 64 | ), 65 | ColorTheme.PROFESSIONAL to 66 | listOf( 67 | Color(0xFF5C6BC0), // Indigo 68 | Color(0xFF8D6E63), // Brown 69 | Color(0xFF26A69A), // Teal 70 | Color(0xFF78909C), // Blue Grey 71 | Color(0xFF7E57C2), // Deep Purple 72 | Color(0xFF66BB6A), // Green 73 | Color(0xFF29B6F6), // Light Blue 74 | Color(0xFFBDBDBD), // Grey 75 | ), 76 | ) 77 | 78 | private val githubColors = 79 | listOf( 80 | Color(0xFF0E4429), // Darkest 81 | Color(0xFF006D32), // Dark 82 | Color(0xFF26A641), // Medium 83 | Color(0xFF39D353), // Light 84 | ) 85 | 86 | private fun getFullPalette(theme: ColorTheme): List = 87 | palettes[theme] ?: palettes[ColorTheme.MATERIAL]!! 88 | 89 | private val _currentTheme = mutableStateOf(ColorTheme.MATERIAL) 90 | private val _currentFullPalette = mutableStateOf(getFullPalette(ColorTheme.MATERIAL)) 91 | val currentTheme: State = _currentTheme 92 | val palette: State> = _currentFullPalette 93 | 94 | fun setTheme(theme: ColorTheme) { 95 | _currentTheme.value = theme 96 | _currentFullPalette.value = getFullPalette(theme) 97 | } 98 | 99 | fun getGithubColors() = githubColors 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/pie/PieChartExample.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.pie 17 | 18 | import androidx.compose.foundation.layout.fillMaxWidth 19 | import androidx.compose.foundation.layout.height 20 | import androidx.compose.runtime.Composable 21 | import androidx.compose.ui.Modifier 22 | import androidx.compose.ui.graphics.Color 23 | import androidx.compose.ui.unit.dp 24 | import io.androidpoet.drafter.pie.PieChart 25 | import io.androidpoet.drafter.pie.model.PieChartData 26 | import io.androidpoet.drafter.pie.renderer.DonutChartRenderer 27 | import io.androidpoet.drafter.pie.renderer.PieChartRenderer 28 | 29 | private fun getPieChartRenderer(colors: List) = 30 | PieChartRenderer( 31 | PieChartData( 32 | slices = 33 | listOf( 34 | PieChartData.Slice(value = 40f, color = colors[0], label = "Red"), 35 | PieChartData.Slice(value = 30f, color = colors[1], label = "Green"), 36 | PieChartData.Slice(value = 20f, color = colors[2], label = "Blue"), 37 | PieChartData.Slice(value = 10f, color = colors[3], label = "Purple"), 38 | ), 39 | ), 40 | ) 41 | 42 | private fun getDonutPieChartRenderer(colors: List) = 43 | DonutChartRenderer( 44 | PieChartData( 45 | slices = 46 | listOf( 47 | PieChartData.Slice(value = 40f, color = colors[0], label = "Red"), 48 | PieChartData.Slice(value = 30f, color = colors[1], label = "Green"), 49 | PieChartData.Slice(value = 20f, color = colors[2], label = "Blue"), 50 | PieChartData.Slice(value = 10f, color = colors[3], label = "Purple"), 51 | ), 52 | ), 53 | ) 54 | 55 | @Composable 56 | fun PieChartExample( 57 | colors: List, 58 | modifier: Modifier = Modifier, 59 | ) { 60 | PieChart( 61 | renderer = getPieChartRenderer(colors = colors), 62 | modifier = 63 | modifier 64 | .height(300.dp).fillMaxWidth(), 65 | animate = true, 66 | ) 67 | } 68 | 69 | @Composable 70 | fun DonutChartExample( 71 | colors: List, 72 | modifier: Modifier = Modifier, 73 | ) { 74 | PieChart( 75 | renderer = getDonutPieChartRenderer(colors = colors), 76 | modifier = 77 | modifier 78 | .height(300.dp) 79 | .fillMaxWidth(), 80 | animate = true, 81 | ) 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/radar/RadarChart.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.radar 17 | 18 | import androidx.compose.foundation.isSystemInDarkTheme 19 | import androidx.compose.foundation.layout.fillMaxWidth 20 | import androidx.compose.foundation.layout.height 21 | import androidx.compose.runtime.Composable 22 | import androidx.compose.ui.Modifier 23 | import androidx.compose.ui.graphics.Color 24 | import androidx.compose.ui.unit.dp 25 | import io.androidpoet.drafter.radar.RadarChart 26 | import io.androidpoet.drafter.radar.model.RadarChartData 27 | import io.androidpoet.drafter.radar.renderer.RadarChartRenderer 28 | 29 | private fun getRadarRenderer(colors: List) = 30 | RadarChartRenderer( 31 | data = 32 | listOf( 33 | RadarChartData( 34 | mapOf( 35 | "Execution" to 0.8f, 36 | "Landing" to 0.6f, 37 | "Difficulty" to 0.9f, 38 | "Style" to 0.7f, 39 | "Creativity" to 0.85f, 40 | ), 41 | ), 42 | ), 43 | colors = colors, 44 | ) 45 | 46 | @Composable 47 | fun RadarChartExample( 48 | colors: List, 49 | modifier: Modifier = Modifier, 50 | ) { 51 | RadarChart( 52 | modifier = 53 | modifier 54 | .height(300.dp) 55 | .fillMaxWidth(), 56 | renderer = getRadarRenderer(colors), 57 | isSystemInDarkTheme = isSystemInDarkTheme(), 58 | ) 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.ui.theme 17 | 18 | import androidx.compose.ui.graphics.Color 19 | 20 | val Purple80 = Color(0xFFD0BCFF) 21 | val PurpleGrey80 = Color(0xFFCCC2DC) 22 | val Pink80 = Color(0xFFEFB8C8) 23 | 24 | val Purple40 = Color(0xFF6650a4) 25 | val PurpleGrey40 = Color(0xFF625b71) 26 | val Pink40 = Color(0xFF7D5260) 27 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.ui.theme 17 | 18 | import android.app.Activity 19 | import android.os.Build 20 | import androidx.compose.foundation.isSystemInDarkTheme 21 | import androidx.compose.material3.MaterialTheme 22 | import androidx.compose.material3.darkColorScheme 23 | import androidx.compose.material3.dynamicDarkColorScheme 24 | import androidx.compose.material3.dynamicLightColorScheme 25 | import androidx.compose.material3.lightColorScheme 26 | import androidx.compose.runtime.Composable 27 | import androidx.compose.runtime.SideEffect 28 | import androidx.compose.ui.graphics.toArgb 29 | import androidx.compose.ui.platform.LocalContext 30 | import androidx.compose.ui.platform.LocalView 31 | import androidx.core.view.WindowCompat 32 | 33 | private val DarkColorScheme = 34 | darkColorScheme( 35 | primary = Purple80, 36 | secondary = PurpleGrey80, 37 | tertiary = Pink80, 38 | ) 39 | 40 | private val LightColorScheme = 41 | lightColorScheme( 42 | primary = Purple40, 43 | secondary = PurpleGrey40, 44 | tertiary = Pink40, 45 | /* Other default colors to override 46 | background = Color(0xFFFFFBFE), 47 | surface = Color(0xFFFFFBFE), 48 | onPrimary = Color.White, 49 | onSecondary = Color.White, 50 | onTertiary = Color.White, 51 | onBackground = Color(0xFF1C1B1F), 52 | onSurface = Color(0xFF1C1B1F), 53 | */ 54 | ) 55 | 56 | @Composable 57 | fun DrafterDemoTheme( 58 | darkTheme: Boolean = isSystemInDarkTheme(), 59 | dynamicColor: Boolean = true, 60 | content: @Composable () -> Unit, 61 | ) { 62 | val colorScheme = 63 | when { 64 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { 65 | val context = LocalContext.current 66 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) 67 | } 68 | 69 | darkTheme -> DarkColorScheme 70 | else -> LightColorScheme 71 | } 72 | val view = LocalView.current 73 | if (!view.isInEditMode) { 74 | SideEffect { 75 | val window = (view.context as Activity).window 76 | window.statusBarColor = colorScheme.primary.toArgb() 77 | WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme 78 | } 79 | } 80 | 81 | MaterialTheme( 82 | colorScheme = colorScheme, 83 | typography = Typography, 84 | content = content, 85 | ) 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/kotlin/io/androidpoet/drafterdemo/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafterdemo.ui.theme 17 | 18 | import androidx.compose.material3.Typography 19 | import androidx.compose.ui.text.TextStyle 20 | import androidx.compose.ui.text.font.FontFamily 21 | import androidx.compose.ui.text.font.FontWeight 22 | import androidx.compose.ui.unit.sp 23 | 24 | val Typography = 25 | Typography( 26 | bodyLarge = 27 | TextStyle( 28 | fontFamily = FontFamily.Default, 29 | fontWeight = FontWeight.Normal, 30 | fontSize = 16.sp, 31 | lineHeight = 24.sp, 32 | letterSpacing = 0.5.sp, 33 | ), 34 | /* Other default text styles to override 35 | titleLarge = TextStyle( 36 | fontFamily = FontFamily.Default, 37 | fontWeight = FontWeight.Normal, 38 | fontSize = 22.sp, 39 | lineHeight = 28.sp, 40 | letterSpacing = 0.sp 41 | ), 42 | labelSmall = TextStyle( 43 | fontFamily = FontFamily.Default, 44 | fontWeight = FontWeight.Medium, 45 | fontSize = 11.sp, 46 | lineHeight = 16.sp, 47 | letterSpacing = 0.5.sp 48 | ) 49 | */ 50 | ) 51 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 23 | 24 | 25 | 31 | 34 | 37 | 38 | 39 | 40 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | #FFBB86FC 19 | #FF6200EE 20 | #FF3700B3 21 | #FF03DAC5 22 | #FF018786 23 | #FF000000 24 | #FFFFFFFF 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | DrafterDemo 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /baselineprofile/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /baselineprofile/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import io.androidpoet.drafter.Configuration 2 | 3 | @Suppress("DSL_SCOPE_VIOLATION") 4 | plugins { 5 | id( 6 | libs.plugins.android.test 7 | .get() 8 | .pluginId, 9 | ) 10 | id( 11 | libs.plugins.kotlin.android 12 | .get() 13 | .pluginId, 14 | ) 15 | id( 16 | libs.plugins.baseline.profile 17 | .get() 18 | .pluginId, 19 | ) 20 | } 21 | 22 | android { 23 | namespace = "io.androidpoet.drafter.baselineprofile" 24 | compileSdk = Configuration.compileSdk 25 | 26 | compileOptions { 27 | sourceCompatibility = JavaVersion.VERSION_11 28 | targetCompatibility = JavaVersion.VERSION_11 29 | } 30 | 31 | kotlinOptions { 32 | jvmTarget = libs.versions.jvmTarget.get() 33 | } 34 | 35 | defaultConfig { 36 | minSdk = 24 37 | targetSdk = Configuration.targetSdk 38 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 39 | } 40 | 41 | targetProjectPath = ":baselineprofile-app" 42 | 43 | testOptions.managedDevices.devices { 44 | maybeCreate("pixel6api31").apply { 45 | device = "Pixel 6" 46 | apiLevel = 31 47 | systemImageSource = "aosp" 48 | } 49 | } 50 | } 51 | baselineProfile { 52 | managedDevices += "pixel6api31" 53 | useConnectedDevices = true 54 | } 55 | 56 | dependencies { 57 | implementation(libs.androidx.test.runner) 58 | implementation(libs.androidx.test.uiautomator) 59 | implementation(libs.androidx.benchmark.macro) 60 | implementation(libs.androidx.profileinstaller) 61 | } 62 | -------------------------------------------------------------------------------- /baselineprofile/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | -------------------------------------------------------------------------------- /baselineprofile/src/main/kotlin/io/androidpoet/drafter/baselineprofile/BaselineProfileGenerator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.baselineprofile 17 | 18 | import android.os.Build 19 | import androidx.annotation.RequiresApi 20 | import androidx.benchmark.macro.junit4.BaselineProfileRule 21 | import org.junit.Rule 22 | import org.junit.Test 23 | 24 | @RequiresApi(Build.VERSION_CODES.P) 25 | class BaselineProfileGenerator { 26 | @get:Rule 27 | val baselineProfileRule = BaselineProfileRule() 28 | 29 | @Test 30 | fun startup() = 31 | baselineProfileRule.collect( 32 | packageName = "io.androidpoet.drafter.baselineprofile.app", 33 | stableIterations = 2, 34 | maxIterations = 8, 35 | ) { 36 | pressHome() 37 | startActivityAndWait() 38 | device.waitForIdle() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | @Suppress("DSL_SCOPE_VIOLATION") 3 | plugins { 4 | alias(libs.plugins.android.application) apply false 5 | alias(libs.plugins.android.library) apply false 6 | alias(libs.plugins.kotlin.multiplatform) apply false 7 | alias(libs.plugins.compose.compiler) apply false 8 | alias(libs.plugins.kotlin.android) apply false 9 | alias(libs.plugins.jetbrains.compose) apply false 10 | alias(libs.plugins.baseline.profile) apply false 11 | alias(libs.plugins.kotlin.binary.compatibility) 12 | alias(libs.plugins.nexus.plugin) 13 | alias(libs.plugins.spotless) 14 | alias(libs.plugins.dokka) 15 | } 16 | 17 | subprojects { 18 | apply( 19 | plugin = 20 | rootProject.libs.plugins.spotless 21 | .get() 22 | .pluginId, 23 | ) 24 | 25 | configure { 26 | kotlin { 27 | target("**/*.kt") 28 | targetExclude("$buildDir/**/*.kt") 29 | ktlint().editorConfigOverride( 30 | mapOf( 31 | "indent_size" to "2", 32 | "continuation_indent_size" to "2", 33 | ), 34 | ) 35 | licenseHeaderFile(rootProject.file("spotless/copyright.kt")) 36 | trimTrailingWhitespace() 37 | endWithNewline() 38 | } 39 | format("xml") { 40 | target("**/*.xml") 41 | targetExclude("**/build/**/*.xml") 42 | licenseHeaderFile(rootProject.file("spotless/copyright.xml"), "(<[^!?])") 43 | trimTrailingWhitespace() 44 | endWithNewline() 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/io/androidpoet/drafter/Configuration.kt: -------------------------------------------------------------------------------- 1 | package io.androidpoet.drafter 2 | 3 | object Configuration { 4 | const val compileSdk = 34 5 | const val targetSdk = 33 6 | const val minSdk = 21 7 | const val majorVersion = 0 8 | const val minorVersion = 1 9 | const val patchVersion = 8 10 | const val versionName = "$majorVersion.$minorVersion.$patchVersion" 11 | const val versionCode = 1 12 | const val snapshotVersionName = "$majorVersion.$minorVersion.${patchVersion + 1}-SNAPSHOT" 13 | const val artifactGroup = "io.github.androidpoet" 14 | } 15 | -------------------------------------------------------------------------------- /chartsx.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/chartsx.mp4 -------------------------------------------------------------------------------- /drafter/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /drafter/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import io.androidpoet.drafter.Configuration 2 | import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl 3 | 4 | @Suppress("DSL_SCOPE_VIOLATION") 5 | plugins { 6 | alias(libs.plugins.android.library) 7 | alias(libs.plugins.kotlin.multiplatform) 8 | alias(libs.plugins.jetbrains.compose) 9 | alias(libs.plugins.compose.compiler) 10 | alias(libs.plugins.nexus.plugin) 11 | alias(libs.plugins.baseline.profile) 12 | } 13 | 14 | apply(from = "$rootDir/scripts/publish-module.gradle.kts") 15 | 16 | mavenPublishing { 17 | val artifactId = "drafter" 18 | coordinates( 19 | Configuration.artifactGroup, 20 | artifactId, 21 | rootProject.extra.get("libVersion").toString(), 22 | ) 23 | 24 | pom { 25 | name.set(artifactId) 26 | description.set( 27 | "\uD83D\uDCCA A powerful, flexible charting library for Compose Multiplatform applications", 28 | ) 29 | } 30 | } 31 | 32 | kotlin { 33 | androidTarget { publishLibraryVariants("release") } 34 | jvm("desktop") 35 | iosX64() 36 | iosArm64() 37 | iosSimulatorArm64() 38 | macosX64() 39 | macosArm64() 40 | js(IR) { 41 | browser() 42 | nodejs() 43 | } 44 | @OptIn(ExperimentalWasmDsl::class) 45 | wasmJs { 46 | browser() 47 | nodejs() 48 | binaries.executable() 49 | } 50 | @Suppress("OPT_IN_USAGE") 51 | applyHierarchyTemplate { 52 | common { 53 | group("jvm") { 54 | withAndroidTarget() 55 | withJvm() 56 | } 57 | group("skia") { 58 | withJvm() 59 | group("darwin") { 60 | group("apple") { 61 | group("ios") { 62 | withIosX64() 63 | withIosArm64() 64 | withIosSimulatorArm64() 65 | } 66 | group("macos") { 67 | withMacosX64() 68 | withMacosArm64() 69 | } 70 | } 71 | withJs() 72 | withWasmJs() 73 | } 74 | } 75 | } 76 | } 77 | 78 | targets.configureEach { 79 | compilations.configureEach { 80 | compilerOptions.configure { 81 | freeCompilerArgs.add("-Xexpect-actual-classes") 82 | } 83 | } 84 | } 85 | 86 | sourceSets { 87 | val commonMain by getting { 88 | dependencies { 89 | implementation(compose.ui) 90 | implementation(compose.material3) 91 | implementation(compose.runtime) 92 | implementation(compose.animation) 93 | implementation(libs.kotlinx.datetime) 94 | } 95 | } 96 | } 97 | 98 | explicitApi() 99 | } 100 | composeCompiler { 101 | enableStrongSkippingMode = true 102 | } 103 | android { 104 | compileSdk = Configuration.compileSdk 105 | namespace = "io.androidpoet.drafter" 106 | defaultConfig { 107 | minSdk = Configuration.minSdk 108 | } 109 | 110 | buildFeatures { 111 | compose = true 112 | buildConfig = false 113 | } 114 | 115 | compileOptions { 116 | sourceCompatibility = JavaVersion.VERSION_1_8 117 | targetCompatibility = JavaVersion.VERSION_1_8 118 | } 119 | 120 | packaging { 121 | resources { 122 | excludes.add("/META-INF/{AL2.0,LGPL2.1}") 123 | } 124 | } 125 | 126 | lint { 127 | abortOnError = false 128 | } 129 | } 130 | 131 | baselineProfile { 132 | baselineProfileOutputDir = "../../src/androidMain" 133 | filter { 134 | include("io.androidpoet.drafter.**") 135 | } 136 | } 137 | 138 | dependencies { 139 | baselineProfile(project(":baselineprofile")) 140 | } 141 | 142 | tasks.withType { 143 | kotlinOptions { 144 | jvmTarget = "1.8" 145 | freeCompilerArgs += 146 | listOf( 147 | "-Xexplicit-api=strict", 148 | "-Xopt-in=androidx.compose.material3.ExperimentalMaterial3Api", 149 | ) 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/bars/BarChartDataRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.bars 17 | 18 | import androidx.compose.ui.graphics.drawscope.DrawScope 19 | 20 | public interface BarChartDataRenderer { 21 | /** The labels for the X-axis (one per bar group, bin, etc.). */ 22 | public fun getLabels(): List 23 | 24 | /** How many bars are in each group? (e.g. 1 for simple/histogram, >1 for grouped) */ 25 | public fun barsPerGroup(): Int 26 | 27 | /** The maximum Y value to use for scaling the bars. */ 28 | public fun calculateMaxValue(): Float 29 | 30 | /** 31 | * Given [chartWidth], [dataSize], and [barsPerGroup], return (barWidth, groupSpacing). 32 | * Must clamp or safeguard so values never go negative. 33 | */ 34 | public fun calculateBarAndSpacing( 35 | chartWidth: Float, 36 | dataSize: Int, 37 | barsPerGroup: Int, 38 | ): Pair 39 | 40 | /** 41 | * For layout, how wide is a single "group" on the X-axis? (barWidth * barsPerGroup + internal spacing). 42 | */ 43 | public fun calculateGroupWidth( 44 | barWidth: Float, 45 | barsPerGroup: Int, 46 | ): Float 47 | 48 | /** 49 | * Draw the bars for group [index]. This is where grouped, stacked, or histogram logic goes. 50 | */ 51 | public fun drawBars( 52 | drawScope: DrawScope, 53 | index: Int, 54 | left: Float, 55 | barWidth: Float, 56 | groupSpacing: Float, 57 | chartBottom: Float, 58 | chartHeight: Float, 59 | maxValue: Float, 60 | animationProgress: Float, 61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/bars/model/BarChartModel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.bars.model 17 | 18 | import androidx.compose.ui.graphics.Color 19 | 20 | /** 21 | * Data class representing data for a grouped bar chart where multiple bars are shown side by side 22 | * for each category/label. 23 | * 24 | * @property labelsList List of labels for each group on the X-axis 25 | * @property itemNames Names of individual items within each group (e.g., "Men", "Women" or "Q1", "Q2", "Q3") 26 | * @property groupedValues List of lists containing values for each item in each group 27 | * @property colors List of colors to be used for different items in the groups 28 | */ 29 | public data class GroupedBarChartData( 30 | val labelsList: List, 31 | val itemNames: List, 32 | val groupedValues: List>, 33 | val colors: List, 34 | ) 35 | 36 | /** 37 | * Data class representing data for a simple bar chart with single bars. 38 | * 39 | * @property labelsList List of labels for the X-axis 40 | * @property values List of values for each bar 41 | * @property colors List of colors for each bar 42 | */ 43 | public data class SimpleBarChartData( 44 | val labelsList: List, 45 | val values: List, 46 | val colors: List, 47 | ) 48 | 49 | /** 50 | * Data class representing data for a stacked bar chart where bars are stacked on top of each other. 51 | * 52 | * @property labelsList List of labels for the X-axis 53 | * @property stacks List of lists containing values for each stack segment 54 | * @property colors List of colors for each stack segment 55 | */ 56 | public data class StackedBarChartData( 57 | val labelsList: List, 58 | val stacks: List>, 59 | val colors: List, 60 | ) 61 | 62 | /** 63 | * Data class representing data for a waterfall chart that shows running total. 64 | * 65 | * @property labelsList List of labels for the X-axis 66 | * @property values List of values representing changes at each step 67 | * @property colors List of colors for each bar 68 | * @property initialValue Starting value for the waterfall chart (defaults to 0) 69 | */ 70 | public data class WaterfallChartData( 71 | val labelsList: List, 72 | val values: List, 73 | val colors: List, 74 | val initialValue: Float = 0f, 75 | ) 76 | 77 | /** 78 | * Data class representing histogram data with binned values. 79 | * 80 | * @property labels List of bin labels for the X-axis 81 | * @property frequencies List of frequencies/counts for each bin 82 | * @property colors List of colors for each bin 83 | */ 84 | public data class HistogramData( 85 | val labels: List, 86 | val frequencies: List, 87 | val colors: List, 88 | ) 89 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/bars/renderer/BarChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.bars.renderer 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.geometry.Size 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.drawscope.DrawScope 22 | import io.androidpoet.drafter.bars.BarChartDataRenderer 23 | import io.androidpoet.drafter.bars.model.SimpleBarChartData 24 | 25 | /** 26 | * A renderer for simple bar charts where each category has a single bar. 27 | * This is the most basic form of a bar chart with one value per label. 28 | * 29 | * @property data The [SimpleBarChartData] containing labels, values, and colors for the bars 30 | */ 31 | public class BarChartRenderer( 32 | public val data: SimpleBarChartData, 33 | ) : BarChartDataRenderer { 34 | /** 35 | * Returns the list of labels for the X-axis. 36 | */ 37 | override fun getLabels(): List = data.labelsList 38 | 39 | /** 40 | * Returns 1 since simple bar charts have one bar per group. 41 | */ 42 | override fun barsPerGroup(): Int = 1 43 | 44 | /** 45 | * Calculates the maximum value across all bars for scaling purposes. 46 | * Returns 0 if there are no values. 47 | */ 48 | override fun calculateMaxValue(): Float = data.values.maxOrNull() ?: 0f 49 | 50 | /** 51 | * Calculates the width of bars and spacing between them based on chart dimensions. 52 | * 53 | * @param chartWidth Total width of the chart area 54 | * @param dataSize Number of data points (bars) to display 55 | * @param barsPerGroup Always 1 for simple bar charts (unused parameter) 56 | * @return Pair of (barWidth, spacing) 57 | */ 58 | override fun calculateBarAndSpacing( 59 | chartWidth: Float, 60 | dataSize: Int, 61 | barsPerGroup: Int, 62 | ): Pair { 63 | val totalSpacing = chartWidth * 0.1f 64 | val groupSpacing = totalSpacing / (dataSize + 1) 65 | val availableWidth = chartWidth - totalSpacing 66 | val barWidth = availableWidth / dataSize 67 | 68 | return Pair(barWidth, groupSpacing) 69 | } 70 | 71 | /** 72 | * Returns the width of a single bar as the group width. 73 | * For simple bar charts, group width equals bar width. 74 | */ 75 | override fun calculateGroupWidth( 76 | barWidth: Float, 77 | barsPerGroup: Int, 78 | ): Float = barWidth 79 | 80 | /** 81 | * Draws a single bar at the specified position. 82 | * 83 | * @param drawScope Drawing context 84 | * @param index Index of the current bar 85 | * @param left Left position of the bar 86 | * @param barWidth Width of the bar 87 | * @param groupSpacing Spacing between bars (unused in simple charts) 88 | * @param chartBottom Y-coordinate of chart bottom 89 | * @param chartHeight Total height of chart 90 | * @param maxValue Maximum value for scaling 91 | * @param animationProgress Current animation progress (0-1) 92 | */ 93 | override fun drawBars( 94 | drawScope: DrawScope, 95 | index: Int, 96 | left: Float, 97 | barWidth: Float, 98 | groupSpacing: Float, 99 | chartBottom: Float, 100 | chartHeight: Float, 101 | maxValue: Float, 102 | animationProgress: Float, 103 | ) { 104 | val value = data.values[index] 105 | val barHeight = (value / maxValue) * chartHeight * animationProgress 106 | val color = data.colors.getOrElse(index) { Color.Gray } 107 | drawScope.drawRect( 108 | color = color, 109 | topLeft = Offset(left, chartBottom - barHeight), 110 | size = Size(barWidth, barHeight), 111 | ) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/bars/renderer/StackedBarChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.bars.renderer 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.geometry.Size 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.drawscope.DrawScope 22 | import io.androidpoet.drafter.bars.BarChartDataRenderer 23 | import io.androidpoet.drafter.bars.model.StackedBarChartData 24 | import kotlin.math.roundToInt 25 | 26 | /** 27 | * A renderer for stacked bar charts where multiple values are stacked vertically in a single bar. 28 | * The bars are distributed evenly across the available width to ensure full X-axis coverage. 29 | * 30 | * @property data The [StackedBarChartData] containing labels, stacked values, and colors for the segments 31 | */ 32 | public class StackedBarChartRenderer( 33 | public val data: StackedBarChartData, 34 | ) : BarChartDataRenderer { 35 | override fun getLabels(): List = 36 | data.labelsList.map { label -> 37 | label.toFloatOrNull()?.let { formatToOneDecimal(it) } ?: label 38 | } 39 | 40 | override fun barsPerGroup(): Int = 1 41 | 42 | override fun calculateMaxValue(): Float = data.stacks.maxOf { it.sum() } 43 | 44 | /** 45 | * Calculates the width of bars and spacing between them to fill the entire chart width. 46 | * Ensures consistent spacing and bar widths across the full X-axis. 47 | * 48 | * @param chartWidth Total width of the chart area 49 | * @param dataSize Number of stacked bars to display 50 | * @param barsPerGroup Always 1 for stacked charts (unused parameter) 51 | * @return Pair of (barWidth, spacing) 52 | */ 53 | override fun calculateBarAndSpacing( 54 | chartWidth: Float, 55 | dataSize: Int, 56 | barsPerGroup: Int, 57 | ): Pair { 58 | if (dataSize <= 0) return Pair(0f, 0f) 59 | val totalGapSpace = chartWidth * 0.2f // Increased from 0.1f to give more spacing 60 | val groupSpacing = totalGapSpace / (dataSize + 1) 61 | val availableWidth = chartWidth - totalGapSpace 62 | val barWidth = (availableWidth / dataSize).coerceAtLeast(0f) 63 | 64 | return Pair(barWidth, groupSpacing) 65 | } 66 | 67 | override fun calculateGroupWidth( 68 | barWidth: Float, 69 | barsPerGroup: Int, 70 | ): Float = barWidth 71 | 72 | /** 73 | * Draws a stacked bar with multiple segments, ensuring proper vertical stacking 74 | * and consistent width across the chart. 75 | */ 76 | override fun drawBars( 77 | drawScope: DrawScope, 78 | index: Int, 79 | left: Float, 80 | barWidth: Float, 81 | groupSpacing: Float, 82 | chartBottom: Float, 83 | chartHeight: Float, 84 | maxValue: Float, 85 | animationProgress: Float, 86 | ) { 87 | if (index >= data.stacks.size) return 88 | var currentBottom = chartBottom 89 | val stackValues = data.stacks[index] 90 | stackValues.forEachIndexed { stackIndex, value -> 91 | val safeMaxValue = maxValue.coerceAtLeast(1e-6f) // Prevent division by zero 92 | val barHeight = (value / safeMaxValue) * chartHeight * animationProgress 93 | val barColor = data.colors.getOrElse(stackIndex) { Color.Gray } 94 | drawScope.drawRect( 95 | color = barColor, 96 | topLeft = Offset(left, currentBottom - barHeight), 97 | size = Size(barWidth, barHeight), 98 | ) 99 | currentBottom -= barHeight 100 | } 101 | } 102 | } 103 | 104 | /** 105 | * Formats a float value to exactly one decimal place using platform-independent approach. 106 | * 107 | * @param value Float value to format 108 | * @return String representation with exactly one decimal place 109 | */ 110 | private fun formatToOneDecimal(value: Float): String = ((value * 10).roundToInt() / 10f).toString() 111 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/buble/BarChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.buble 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.graphics.drawscope.DrawScope 20 | 21 | public class SimpleBubbleChartDataRenderer( 22 | private val data: BubbleChartData, 23 | ) : BubbleChartDataRenderer { 24 | override fun getLabels(): List = emptyList() 25 | 26 | override fun getValueRanges(): ValueRanges { 27 | val allBubbles = data.series.flatten() 28 | val xMin = 0f // Always start from 0 29 | val yMin = 0f // Always start from 0 30 | val xMax = roundToNiceNumber(allBubbles.maxOfOrNull { it.x } ?: 0f) 31 | val yMax = roundToNiceNumber(allBubbles.maxOfOrNull { it.y } ?: 0f) 32 | return ValueRanges(xMin, xMax, yMin, yMax) 33 | } 34 | 35 | override fun getMaxValues(): Pair { 36 | val ranges = getValueRanges() 37 | return Pair(ranges.xMax, ranges.yMax) 38 | } 39 | 40 | private fun roundToNiceNumber(value: Float): Float = 41 | when { 42 | value <= 50f -> (((value + 9) / 10).toInt() * 10).toFloat() 43 | value <= 100f -> (((value + 24) / 25).toInt() * 25).toFloat() 44 | else -> (((value + 49) / 50).toInt() * 50).toFloat() 45 | } 46 | 47 | override fun drawBubbles( 48 | drawScope: DrawScope, 49 | chartWidth: Float, 50 | chartHeight: Float, 51 | originX: Float, 52 | originY: Float, 53 | animationProgress: Float, 54 | ) { 55 | val ranges = getValueRanges() 56 | val maxBubbleSize = data.series.flatten().maxOfOrNull { it.size } ?: 0f 57 | 58 | data.series.forEachIndexed { seriesIndex, series -> 59 | series.forEachIndexed { bubbleIndex, bubble -> 60 | val delay = (seriesIndex * series.size + bubbleIndex) * 0.1f 61 | val bubbleProgress = (animationProgress - delay).coerceIn(0f, 1f) 62 | val x = originX + (bubble.x / ranges.xMax) * chartWidth 63 | val y = originY - (bubble.y / ranges.yMax) * chartHeight 64 | val scaleFactor = minOf(chartWidth, chartHeight) / 6f 65 | val scaledSize = (bubble.size / maxBubbleSize) * scaleFactor 66 | 67 | drawScope.drawCircle( 68 | color = bubble.color, 69 | radius = scaledSize * bubbleProgress, 70 | center = Offset(x, y), 71 | ) 72 | } 73 | } 74 | } 75 | } 76 | 77 | public data class ValueRanges( 78 | val xMin: Float, 79 | val xMax: Float, 80 | val yMin: Float, 81 | val yMax: Float, 82 | ) 83 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/buble/BubbleChartData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.buble 17 | 18 | import androidx.compose.ui.graphics.Color 19 | 20 | public data class BubbleChartData( 21 | val series: List>, 22 | ) { 23 | public data class BubbleData( 24 | val x: Float, 25 | val y: Float, 26 | val size: Float, 27 | val color: Color, 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/buble/BubbleChartDataRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.buble 17 | 18 | import androidx.compose.ui.graphics.drawscope.DrawScope 19 | 20 | public interface BubbleChartDataRenderer { 21 | public fun getLabels(): List 22 | 23 | public fun getMaxValues(): Pair // x, y 24 | 25 | public fun getValueRanges(): ValueRanges 26 | 27 | public fun drawBubbles( 28 | drawScope: DrawScope, 29 | chartWidth: Float, 30 | chartHeight: Float, 31 | originX: Float, 32 | originY: Float, 33 | animationProgress: Float, 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/gant/GantChartData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.gant 17 | 18 | import androidx.compose.ui.graphics.Color 19 | 20 | public data class GanttTask( 21 | val name: String, 22 | val startMonth: Float, 23 | val duration: Float, 24 | ) 25 | 26 | public data class GanttChartData( 27 | val tasks: List, 28 | val taskColors: List = List(tasks.size) { Color.Blue }, 29 | ) 30 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/gant/GanttChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.gant 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.geometry.Size 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.drawscope.DrawScope 22 | import kotlin.math.max 23 | 24 | public class GanttChartRenderer( 25 | public val data: GanttChartData, 26 | ) { 27 | public fun calculateMaxValues(): Pair { 28 | val maxMonth = data.tasks.maxOfOrNull { it.startMonth + it.duration } ?: 1f 29 | return Pair(max(maxMonth, 1f), max(data.tasks.size.toFloat(), 1f)) 30 | } 31 | 32 | public fun drawTasks( 33 | drawScope: DrawScope, 34 | chartLeft: Float, 35 | chartTop: Float, 36 | chartWidth: Float, 37 | chartHeight: Float, 38 | maxMonth: Float, 39 | animationProgress: Float, 40 | ) { 41 | if (data.tasks.isEmpty()) return 42 | val safeMaxMonth = max(maxMonth, 1f) 43 | val taskHeight = max(chartHeight / data.tasks.size, 1f) 44 | 45 | data.tasks.forEachIndexed { index, task -> 46 | val startX = chartLeft + (task.startMonth / safeMaxMonth) * chartWidth 47 | val width = max((task.duration / safeMaxMonth) * chartWidth * animationProgress, 1f) 48 | val y = chartTop + index * taskHeight 49 | val color = 50 | if (index < data.taskColors.size) { 51 | data.taskColors[index] 52 | } else { 53 | Color.Blue 54 | } 55 | drawScope.drawRect( 56 | color = color.copy(alpha = animationProgress), 57 | topLeft = Offset(startX, y + taskHeight * 0.1f), 58 | size = Size(width, max(taskHeight * 0.8f, 1f)), 59 | ) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/heatmap/HeatMapData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.heatmap 17 | 18 | import androidx.compose.ui.graphics.Color 19 | import kotlinx.datetime.Instant 20 | 21 | public data class ContributionData( 22 | val timestamp: Instant, 23 | val count: Int, 24 | ) 25 | 26 | public data class ContributionHeatmapData( 27 | val contributions: List, 28 | val baseColor: Color = Color(0xFF40C463), 29 | val backgroundSquareColor: Color = Color(0xFF2D333B), 30 | ) 31 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/heatmap/Heatmap.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.heatmap 17 | 18 | import androidx.compose.animation.core.Animatable 19 | import androidx.compose.animation.core.FastOutSlowInEasing 20 | import androidx.compose.animation.core.tween 21 | import androidx.compose.foundation.Canvas 22 | import androidx.compose.foundation.background 23 | import androidx.compose.foundation.horizontalScroll 24 | import androidx.compose.foundation.isSystemInDarkTheme 25 | import androidx.compose.foundation.layout.Box 26 | import androidx.compose.foundation.layout.fillMaxSize 27 | import androidx.compose.foundation.layout.padding 28 | import androidx.compose.foundation.rememberScrollState 29 | import androidx.compose.runtime.Composable 30 | import androidx.compose.runtime.LaunchedEffect 31 | import androidx.compose.runtime.remember 32 | import androidx.compose.ui.Modifier 33 | import androidx.compose.ui.graphics.Color 34 | import androidx.compose.ui.platform.LocalDensity 35 | import androidx.compose.ui.unit.dp 36 | import kotlinx.datetime.Clock 37 | import kotlinx.datetime.DateTimeUnit 38 | import kotlinx.datetime.TimeZone 39 | import kotlinx.datetime.atStartOfDayIn 40 | import kotlinx.datetime.minus 41 | import kotlinx.datetime.toLocalDateTime 42 | 43 | @Composable 44 | public fun Heatmap( 45 | renderer: HeatmapDataRenderer, 46 | modifier: Modifier = Modifier, 47 | isSystemInDarkTheme: Boolean = isSystemInDarkTheme(), 48 | ) { 49 | val density = LocalDensity.current 50 | val cellSize = with(density) { 8.dp.toPx() } 51 | val cellPadding = with(density) { 2.dp.toPx() } 52 | 53 | val now = Clock.System.now() 54 | val endDate = now.toLocalDateTime(TimeZone.currentSystemDefault()).date 55 | val startDate = endDate.minus(1, DateTimeUnit.YEAR) 56 | 57 | val startInstant = startDate.atStartOfDayIn(TimeZone.currentSystemDefault()) 58 | val endInstant = endDate.atStartOfDayIn(TimeZone.currentSystemDefault()) 59 | 60 | val animationProgress = remember { Animatable(0f) } 61 | 62 | LaunchedEffect(Unit) { 63 | animationProgress.animateTo( 64 | targetValue = 1f, 65 | animationSpec = 66 | tween( 67 | durationMillis = 1000, 68 | easing = FastOutSlowInEasing, 69 | ), 70 | ) 71 | } 72 | 73 | Box( 74 | modifier = 75 | modifier 76 | .horizontalScroll(rememberScrollState()) 77 | .background(if (isSystemInDarkTheme) Color.Black else Color.White) 78 | .padding(8.dp), 79 | ) { 80 | Canvas( 81 | modifier = 82 | Modifier 83 | .fillMaxSize() 84 | .padding(4.dp), 85 | ) { 86 | renderer.drawHeatmap( 87 | drawScope = this, 88 | cellSize = cellSize, 89 | cellPadding = cellPadding, 90 | startInstant = startInstant, 91 | endInstant = endInstant, 92 | animationProgress = animationProgress.value, 93 | isSystemInDarkTheme = isSystemInDarkTheme, 94 | ) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/heatmap/HeatmapDataRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.heatmap 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.geometry.Size 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.drawscope.DrawScope 22 | import kotlinx.datetime.DateTimeUnit 23 | import kotlinx.datetime.Instant 24 | import kotlinx.datetime.TimeZone 25 | import kotlinx.datetime.daysUntil 26 | import kotlinx.datetime.plus 27 | import kotlinx.datetime.toLocalDateTime 28 | 29 | public interface HeatmapDataRenderer { 30 | public val data: ContributionHeatmapData 31 | 32 | public fun drawHeatmap( 33 | drawScope: DrawScope, 34 | cellSize: Float, 35 | cellPadding: Float, 36 | startInstant: Instant, 37 | endInstant: Instant, 38 | animationProgress: Float, 39 | isSystemInDarkTheme: Boolean, 40 | ) 41 | } 42 | 43 | public class HeatmapRenderer( 44 | override val data: ContributionHeatmapData, 45 | ) : HeatmapDataRenderer { 46 | private fun getContributionColor( 47 | count: Int, 48 | isSystemInDarkTheme: Boolean, 49 | ): Color = 50 | when { 51 | count == 0 -> 52 | if (isSystemInDarkTheme) { 53 | Color(0xFF24292E) 54 | } else { 55 | Color(0xFFF6F8FA).copy(alpha = 0.5f) 56 | } 57 | count <= 3 -> data.baseColor.copy(alpha = 0.2f) 58 | count <= 6 -> data.baseColor.copy(alpha = 0.4f) 59 | count <= 9 -> data.baseColor.copy(alpha = 0.7f) 60 | else -> data.baseColor.copy(alpha = 1.0f) 61 | } 62 | 63 | override fun drawHeatmap( 64 | drawScope: DrawScope, 65 | cellSize: Float, 66 | cellPadding: Float, 67 | startInstant: Instant, 68 | endInstant: Instant, 69 | animationProgress: Float, 70 | isSystemInDarkTheme: Boolean, 71 | ) { 72 | with(drawScope) { 73 | val startDate = startInstant.toLocalDateTime(TimeZone.currentSystemDefault()).date 74 | val endDate = endInstant.toLocalDateTime(TimeZone.currentSystemDefault()).date 75 | val weeks = startDate.daysUntil(endDate) / 7 76 | 77 | val contributionsMap = 78 | data.contributions 79 | .groupingBy { 80 | it.timestamp.toLocalDateTime(TimeZone.currentSystemDefault()).date 81 | }.aggregate { _, accumulator: Int?, element, _ -> 82 | (accumulator ?: 0) + element.count 83 | } 84 | 85 | var currentDate = startDate 86 | for (week in 0..weeks) { 87 | for (dayOfWeek in 0..6) { 88 | if (currentDate <= endDate) { 89 | val contributions = contributionsMap[currentDate] ?: 0 90 | 91 | val x = week * (cellSize + cellPadding) 92 | val y = dayOfWeek * (cellSize + cellPadding) 93 | 94 | drawRect( 95 | color = getContributionColor(contributions, isSystemInDarkTheme), 96 | topLeft = Offset(x, y), 97 | size = Size(cellSize, cellSize), 98 | ) 99 | 100 | currentDate = currentDate.plus(1, DateTimeUnit.DAY) 101 | } 102 | } 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/lines/LineChartDataRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.lines 17 | 18 | import androidx.compose.ui.graphics.drawscope.DrawScope 19 | 20 | public interface LineChartDataRenderer { 21 | public fun getLabels(): List 22 | 23 | public fun calculateMaxValue(): Float 24 | 25 | public fun drawLines( 26 | drawScope: DrawScope, 27 | chartLeft: Float, 28 | chartTop: Float, 29 | chartWidth: Float, 30 | chartHeight: Float, 31 | maxValue: Float, 32 | animationProgress: Float, 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/lines/model/LineChartData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.lines.model 17 | 18 | import androidx.compose.ui.graphics.Color 19 | 20 | public interface LineChartData { 21 | public val labels: List 22 | } 23 | 24 | public data class SimpleLineChartData( 25 | override val labels: List, 26 | val values: List, 27 | val color: Color, 28 | ) : LineChartData 29 | 30 | public data class GroupedLineChartData( 31 | override val labels: List, 32 | val itemNames: List, 33 | val groupedValues: List>, 34 | val colors: List, 35 | ) : LineChartData 36 | 37 | public data class StackedLineChartData( 38 | override val labels: List, 39 | val stacks: List>, 40 | val colors: List, 41 | ) : LineChartData 42 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/lines/renderer/GroupedLineChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.lines.renderer 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.graphics.Color 20 | import androidx.compose.ui.graphics.drawscope.DrawScope 21 | import io.androidpoet.drafter.lines.LineChartDataRenderer 22 | import io.androidpoet.drafter.lines.model.GroupedLineChartData 23 | import kotlin.math.pow 24 | 25 | public class GroupedLineChartRenderer( 26 | private val data: GroupedLineChartData, 27 | ) : LineChartDataRenderer { 28 | override fun getLabels(): List = data.labels 29 | 30 | override fun calculateMaxValue(): Float = data.groupedValues.flatten().maxOrNull() ?: 0f 31 | 32 | override fun drawLines( 33 | drawScope: DrawScope, 34 | chartLeft: Float, 35 | chartTop: Float, 36 | chartWidth: Float, 37 | chartHeight: Float, 38 | maxValue: Float, 39 | animationProgress: Float, 40 | ) { 41 | val numPoints = data.labels.size 42 | val xPositions = 43 | List(numPoints) { index -> 44 | chartLeft + index * (chartWidth / (numPoints - 1)) 45 | } 46 | 47 | data.itemNames.forEachIndexed { itemIndex, _ -> 48 | val points = 49 | List(numPoints) { index -> 50 | val value = data.groupedValues[index][itemIndex] 51 | val x = xPositions[index] 52 | val y = chartTop + chartHeight - (value / maxValue) * chartHeight 53 | Offset(x, y) 54 | } 55 | 56 | val totalLength = 57 | points 58 | .zipWithNext() 59 | .sumOf { (start, end) -> 60 | val dx = end.x - start.x 61 | val dy = end.y - start.y 62 | kotlin.math.sqrt((dx * dx + dy * dy).toDouble()) 63 | }.toFloat() 64 | 65 | var currentLength = 0f 66 | 67 | points.zipWithNext().forEach { (start, end) -> 68 | val segmentLength = 69 | kotlin.math.sqrt( 70 | (end.x - start.x).pow(2) + (end.y - start.y).pow(2), 71 | ) 72 | val segmentProgress = (currentLength + segmentLength) / totalLength 73 | 74 | if (segmentProgress <= animationProgress) { 75 | drawScope.drawLine( 76 | color = data.colors.getOrElse(itemIndex) { Color.Gray }, 77 | start = start, 78 | end = end, 79 | strokeWidth = 2f, 80 | ) 81 | } else if (currentLength / totalLength <= animationProgress) { 82 | val remainingProgress = 83 | (animationProgress - currentLength / totalLength) / (segmentLength / totalLength) 84 | val partialEnd = 85 | Offset( 86 | x = start.x + (end.x - start.x) * remainingProgress, 87 | y = start.y + (end.y - start.y) * remainingProgress, 88 | ) 89 | drawScope.drawLine( 90 | color = data.colors.getOrElse(itemIndex) { Color.Gray }, 91 | start = start, 92 | end = partialEnd, 93 | strokeWidth = 2f, 94 | ) 95 | } 96 | currentLength += segmentLength 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/lines/renderer/LineChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.lines.renderer 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.graphics.drawscope.DrawScope 20 | import io.androidpoet.drafter.lines.LineChartDataRenderer 21 | import io.androidpoet.drafter.lines.model.SimpleLineChartData 22 | import kotlin.math.pow 23 | 24 | public class LineChartRenderer( 25 | private val data: SimpleLineChartData, 26 | ) : LineChartDataRenderer { 27 | override fun getLabels(): List = data.labels 28 | 29 | override fun calculateMaxValue(): Float = data.values.maxOrNull() ?: 0f 30 | 31 | override fun drawLines( 32 | drawScope: DrawScope, 33 | chartLeft: Float, 34 | chartTop: Float, 35 | chartWidth: Float, 36 | chartHeight: Float, 37 | maxValue: Float, 38 | animationProgress: Float, 39 | ) { 40 | val points = 41 | data.values.mapIndexed { index, value -> 42 | val x = chartLeft + index * (chartWidth / (data.values.size - 1)) 43 | val y = chartTop + chartHeight - (value / maxValue) * chartHeight 44 | Offset(x, y) 45 | } 46 | 47 | val totalLength = 48 | points 49 | .zipWithNext() 50 | .sumOf { (start, end) -> 51 | val dx = end.x - start.x 52 | val dy = end.y - start.y 53 | kotlin.math.sqrt((dx * dx + dy * dy).toDouble()) 54 | }.toFloat() 55 | 56 | var currentLength = 0f 57 | var lastDrawnPoint = points.first() 58 | 59 | points.zipWithNext().forEach { (start, end) -> 60 | val segmentLength = 61 | kotlin.math.sqrt( 62 | (end.x - start.x).pow(2) + (end.y - start.y).pow(2), 63 | ) 64 | val segmentProgress = (currentLength + segmentLength) / totalLength 65 | 66 | if (segmentProgress <= animationProgress) { 67 | drawScope.drawLine( 68 | color = data.color, 69 | start = start, 70 | end = end, 71 | strokeWidth = 2f, 72 | ) 73 | lastDrawnPoint = end 74 | } else if (currentLength / totalLength <= animationProgress) { 75 | val remainingProgress = 76 | (animationProgress - currentLength / totalLength) / (segmentLength / totalLength) 77 | val partialEnd = 78 | Offset( 79 | x = start.x + (end.x - start.x) * remainingProgress, 80 | y = start.y + (end.y - start.y) * remainingProgress, 81 | ) 82 | drawScope.drawLine( 83 | color = data.color, 84 | start = start, 85 | end = partialEnd, 86 | strokeWidth = 2f, 87 | ) 88 | } 89 | currentLength += segmentLength 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/lines/renderer/StackedLineChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.lines.renderer 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.graphics.Color 20 | import androidx.compose.ui.graphics.Path 21 | import androidx.compose.ui.graphics.drawscope.DrawScope 22 | import androidx.compose.ui.graphics.drawscope.Fill 23 | import io.androidpoet.drafter.lines.LineChartDataRenderer 24 | import io.androidpoet.drafter.lines.model.StackedLineChartData 25 | 26 | public class StackedLineChartRenderer( 27 | private val data: StackedLineChartData, 28 | ) : LineChartDataRenderer { 29 | override fun getLabels(): List = data.labels 30 | 31 | override fun calculateMaxValue(): Float = data.stacks.map { it.sum() }.maxOrNull() ?: 0f 32 | 33 | override fun drawLines( 34 | drawScope: DrawScope, 35 | chartLeft: Float, 36 | chartTop: Float, 37 | chartWidth: Float, 38 | chartHeight: Float, 39 | maxValue: Float, 40 | animationProgress: Float, 41 | ) { 42 | val numPoints = data.labels.size 43 | val xPositions = 44 | List(numPoints) { index -> 45 | chartLeft + index * (chartWidth / (numPoints - 1)) 46 | } 47 | 48 | val accumulatedValues = MutableList(numPoints) { 0f } 49 | val stackCount = data.stacks[0].size 50 | for (stackIndex in 0 until stackCount) { 51 | val previousAccumulatedValues = accumulatedValues.toList() 52 | for (i in 0 until numPoints) { 53 | accumulatedValues[i] += data.stacks[i][stackIndex] 54 | } 55 | val upperPoints = 56 | List(numPoints) { i -> 57 | val x = xPositions[i] 58 | val y = 59 | chartTop + chartHeight - 60 | ((accumulatedValues[i] * animationProgress) / maxValue) * chartHeight 61 | Offset(x, y) 62 | } 63 | 64 | val lowerPoints = 65 | List(numPoints) { i -> 66 | val x = xPositions[i] 67 | val y = 68 | chartTop + chartHeight - 69 | ((previousAccumulatedValues[i] * animationProgress) / maxValue) * chartHeight 70 | Offset(x, y) 71 | } 72 | val path = 73 | Path().apply { 74 | moveTo(upperPoints.first().x, upperPoints.first().y) 75 | for (point in upperPoints.drop(1)) { 76 | lineTo(point.x, point.y) 77 | } 78 | for (point in lowerPoints.reversed()) { 79 | lineTo(point.x, point.y) 80 | } 81 | close() 82 | } 83 | drawScope.drawPath( 84 | path = path, 85 | color = data.colors.getOrElse(stackIndex) { Color.Gray }, 86 | style = Fill, 87 | ) 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/pie/PieChart.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.pie 17 | 18 | import androidx.compose.animation.core.Animatable 19 | import androidx.compose.animation.core.tween 20 | import androidx.compose.foundation.Canvas 21 | import androidx.compose.foundation.isSystemInDarkTheme 22 | import androidx.compose.runtime.Composable 23 | import androidx.compose.runtime.LaunchedEffect 24 | import androidx.compose.runtime.remember 25 | import androidx.compose.ui.Modifier 26 | import androidx.compose.ui.text.rememberTextMeasurer 27 | import io.androidpoet.drafter.pie.renderer.PieChartDataRenderer 28 | 29 | @Composable 30 | public fun PieChart( 31 | renderer: PieChartDataRenderer, 32 | modifier: Modifier = Modifier, 33 | animate: Boolean = true, 34 | isSystemInDarkTheme: Boolean = isSystemInDarkTheme(), 35 | ) { 36 | val textMeasurer = rememberTextMeasurer() 37 | val progress = remember { Animatable(0f) } 38 | LaunchedEffect(animate) { 39 | if (animate) { 40 | progress.animateTo( 41 | targetValue = 1f, 42 | animationSpec = tween(durationMillis = 1000), 43 | ) 44 | } else { 45 | progress.snapTo(1f) 46 | } 47 | } 48 | Canvas(modifier = modifier) { 49 | renderer.drawChart( 50 | drawScope = this, 51 | size = size, 52 | progress = progress.value, 53 | textMeasurer = textMeasurer, 54 | isSystemInDarkTheme = isSystemInDarkTheme, 55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/pie/model/PieChartData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.pie.model 17 | 18 | import androidx.compose.ui.graphics.Color 19 | 20 | public data class PieChartData( 21 | val slices: List, 22 | ) { 23 | public data class Slice( 24 | val value: Float, 25 | val color: Color, 26 | val label: String, 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/pie/renderer/DonutChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.pie.renderer 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.geometry.Size 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.drawscope.DrawScope 22 | import androidx.compose.ui.graphics.drawscope.Stroke 23 | import androidx.compose.ui.text.TextMeasurer 24 | import androidx.compose.ui.text.TextStyle 25 | import androidx.compose.ui.text.drawText 26 | import androidx.compose.ui.unit.sp 27 | import io.androidpoet.drafter.pie.model.PieChartData 28 | import kotlin.math.PI 29 | import kotlin.math.cos 30 | import kotlin.math.max 31 | import kotlin.math.sin 32 | 33 | /** 34 | * Renders a "donut" by using an arc + Stroke (hole in center). 35 | */ 36 | public class DonutChartRenderer( 37 | override val data: PieChartData, 38 | private val labelThreshold: Float = 5f, 39 | private val holeRadiusFraction: Float = 0.5f, 40 | ) : PieChartDataRenderer { 41 | public override fun drawChart( 42 | drawScope: DrawScope, 43 | size: Size, 44 | progress: Float, 45 | textMeasurer: TextMeasurer, 46 | isSystemInDarkTheme: Boolean, 47 | ) { 48 | val totalValue = 49 | max( 50 | data.slices.sumOf { slice -> slice.value.toDouble() }.toFloat(), 51 | 1f, 52 | ) 53 | var startAngle = -90f 54 | 55 | val outerRadius = (size.minDimension / 2) * 0.6f 56 | val innerRadius = outerRadius * holeRadiusFraction 57 | val center = Offset(size.width / 2, size.height / 2) 58 | 59 | data.slices.forEach { slice -> 60 | val slicePercentage = slice.value / totalValue 61 | val sweepAngle = slicePercentage * 360f * progress 62 | drawScope.drawArc( 63 | color = slice.color, 64 | startAngle = startAngle, 65 | sweepAngle = sweepAngle, 66 | useCenter = false, 67 | topLeft = Offset(center.x - outerRadius, center.y - outerRadius), 68 | size = Size(outerRadius * 2, outerRadius * 2), 69 | style = Stroke(width = outerRadius - innerRadius), 70 | ) 71 | val percentage = slicePercentage * 100 72 | if (percentage >= labelThreshold && sweepAngle > 0f) { 73 | val midAngleRad = (startAngle + sweepAngle / 2) * (PI.toFloat() / 180f) 74 | val labelRadius = outerRadius * 1.3f 75 | 76 | val labelText = "${percentage.toInt()}%" 77 | val style = 78 | TextStyle(fontSize = 12.sp, color = if (isSystemInDarkTheme) Color.White else Color.Black) 79 | val textLayout = textMeasurer.measure(labelText, style) 80 | val baseX = center.x + (labelRadius * cos(midAngleRad)) 81 | val baseY = center.y + (labelRadius * sin(midAngleRad)) 82 | val xOffset = -textLayout.size.width / 2 83 | val yOffset = -textLayout.size.height / 2 84 | val radialPushFactor = 0.15f // Adjust this value to control how far text pushes outward 85 | val radialOffsetX = radialPushFactor * labelRadius * cos(midAngleRad) 86 | val radialOffsetY = radialPushFactor * labelRadius * sin(midAngleRad) 87 | 88 | drawScope.drawText( 89 | textMeasurer = textMeasurer, 90 | text = labelText, 91 | style = style, 92 | topLeft = 93 | Offset( 94 | x = baseX + xOffset + radialOffsetX, 95 | y = baseY + yOffset + radialOffsetY, 96 | ), 97 | ) 98 | } 99 | 100 | startAngle += sweepAngle 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/pie/renderer/PieChartDataRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.pie.renderer 17 | 18 | import androidx.compose.ui.geometry.Size 19 | import androidx.compose.ui.graphics.drawscope.DrawScope 20 | import androidx.compose.ui.text.TextMeasurer 21 | import io.androidpoet.drafter.pie.model.PieChartData 22 | 23 | /** 24 | * A single interface for all pie/donut chart renderers. 25 | * - [data] stores the PieChartData internally. 26 | * - [drawChart] is called by [PieChart] composable to do the drawing. 27 | */ 28 | public interface PieChartDataRenderer { 29 | public val data: PieChartData 30 | 31 | /** 32 | * Draw the chart (pie, donut, etc.). 33 | * @param drawScope current [DrawScope] to use for drawing. 34 | * @param size The canvas size. 35 | * @param progress A float [0..1] that can be used for animation. 36 | */ 37 | public fun drawChart( 38 | drawScope: DrawScope, 39 | size: Size, 40 | progress: Float, 41 | textMeasurer: TextMeasurer, 42 | isSystemInDarkTheme: Boolean, 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/pie/renderer/PieChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.pie.renderer 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.geometry.Size 20 | import androidx.compose.ui.graphics.Color 21 | import androidx.compose.ui.graphics.drawscope.DrawScope 22 | import androidx.compose.ui.text.TextMeasurer 23 | import androidx.compose.ui.text.TextStyle 24 | import androidx.compose.ui.text.drawText 25 | import androidx.compose.ui.text.font.FontWeight 26 | import androidx.compose.ui.unit.sp 27 | import io.androidpoet.drafter.pie.model.PieChartData 28 | import kotlin.math.PI 29 | import kotlin.math.cos 30 | import kotlin.math.max 31 | import kotlin.math.sin 32 | 33 | public class PieChartRenderer( 34 | override val data: PieChartData, 35 | private val labelThreshold: Float = 5f, 36 | ) : PieChartDataRenderer { 37 | public override fun drawChart( 38 | drawScope: DrawScope, 39 | size: Size, 40 | progress: Float, 41 | textMeasurer: TextMeasurer, 42 | isSystemInDarkTheme: Boolean, 43 | ) { 44 | val totalValue = 45 | max( 46 | data.slices.sumOf { slice -> slice.value.toDouble() }.toFloat(), 47 | 1f, 48 | ) 49 | 50 | var startAngle = -90f 51 | val radius = (size.minDimension / 2) * 0.7f 52 | val center = Offset(size.width / 2, size.height / 2) 53 | 54 | data.slices.forEach { slice -> 55 | val slicePercentage = slice.value / totalValue 56 | val sweepAngle = slicePercentage * 360f * progress 57 | 58 | drawScope.drawArc( 59 | color = slice.color, 60 | startAngle = startAngle, 61 | sweepAngle = sweepAngle, 62 | useCenter = true, 63 | topLeft = Offset(center.x - radius, center.y - radius), 64 | size = Size(radius * 2, radius * 2), 65 | ) 66 | val percentage = slicePercentage * 100 67 | if (percentage >= labelThreshold && sweepAngle > 0f) { 68 | val angleMid = startAngle + sweepAngle / 2 69 | val angleRad = angleMid * (PI / 180) 70 | val labelRadius = radius * 0.7f 71 | val labelX = center.x + (labelRadius * cos(angleRad)).toFloat() 72 | val labelY = center.y + (labelRadius * sin(angleRad)).toFloat() 73 | 74 | val labelText = "${percentage.toInt()}%" 75 | val style = 76 | TextStyle( 77 | fontSize = 12.sp, 78 | color = if (isSystemInDarkTheme) Color.Black else Color.White, 79 | fontWeight = FontWeight.Bold, 80 | ) 81 | val textLayout = textMeasurer.measure(labelText, style) 82 | 83 | drawScope.drawText( 84 | textMeasurer = textMeasurer, 85 | text = labelText, 86 | style = style, 87 | topLeft = 88 | Offset( 89 | x = labelX - textLayout.size.width / 2, 90 | y = labelY - textLayout.size.height / 2, 91 | ), 92 | ) 93 | } 94 | 95 | startAngle += sweepAngle 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/popup/Tooltip.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.popup 17 | 18 | import androidx.compose.foundation.layout.padding 19 | import androidx.compose.foundation.shape.RoundedCornerShape 20 | import androidx.compose.material3.Surface 21 | import androidx.compose.material3.Text 22 | import androidx.compose.runtime.Composable 23 | import androidx.compose.ui.Alignment 24 | import androidx.compose.ui.Modifier 25 | import androidx.compose.ui.draw.shadow 26 | import androidx.compose.ui.geometry.Offset 27 | import androidx.compose.ui.graphics.Color 28 | import androidx.compose.ui.unit.dp 29 | import androidx.compose.ui.unit.sp 30 | import androidx.compose.ui.window.Popup 31 | 32 | @Composable 33 | public fun Tooltip(text: String) { 34 | Popup( 35 | alignment = Alignment.TopStart, 36 | ) { 37 | Surface( 38 | modifier = 39 | Modifier 40 | .shadow(4.dp) 41 | .padding(4.dp), 42 | color = Color.White, 43 | shape = RoundedCornerShape(4.dp), 44 | ) { 45 | Text( 46 | text = text, 47 | modifier = Modifier.padding(8.dp), 48 | fontSize = 12.sp, 49 | ) 50 | } 51 | } 52 | } 53 | 54 | public data class HoverState( 55 | val isHovered: Boolean = false, 56 | val position: Offset = Offset.Zero, 57 | val value: String = "", 58 | ) 59 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/radar/RadarChart.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.radar 17 | 18 | import androidx.compose.animation.core.Animatable 19 | import androidx.compose.animation.core.FastOutSlowInEasing 20 | import androidx.compose.animation.core.tween 21 | import androidx.compose.foundation.Canvas 22 | import androidx.compose.foundation.isSystemInDarkTheme 23 | import androidx.compose.foundation.layout.size 24 | import androidx.compose.runtime.Composable 25 | import androidx.compose.runtime.LaunchedEffect 26 | import androidx.compose.runtime.remember 27 | import androidx.compose.ui.Modifier 28 | import androidx.compose.ui.text.rememberTextMeasurer 29 | import androidx.compose.ui.unit.dp 30 | import io.androidpoet.drafter.radar.renderer.RadarChartRenderer 31 | 32 | @Composable 33 | public fun RadarChart( 34 | renderer: RadarChartRenderer, 35 | modifier: Modifier = Modifier, 36 | isSystemInDarkTheme: Boolean = isSystemInDarkTheme(), 37 | ) { 38 | val textMeasurer = rememberTextMeasurer() 39 | val animatedProgress = remember { Animatable(0f) } 40 | 41 | LaunchedEffect(Unit) { 42 | animatedProgress.animateTo( 43 | targetValue = 1f, 44 | animationSpec = 45 | tween( 46 | durationMillis = 1000, 47 | easing = FastOutSlowInEasing, 48 | ), 49 | ) 50 | } 51 | 52 | Canvas(modifier = modifier.size(300.dp)) { 53 | val centerX = size.width / 2 54 | val centerY = size.height / 2 55 | val radius = size.width.coerceAtMost(size.height) / 2 * 0.8f 56 | 57 | renderer.drawChart( 58 | drawScope = this, 59 | centerX = centerX, 60 | centerY = centerY, 61 | radius = radius, 62 | textMeasurer = textMeasurer, 63 | animationProgress = animatedProgress.value, 64 | isSystemInDarkTheme = isSystemInDarkTheme, 65 | ) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/radar/RadarChartDataRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.radar 17 | 18 | import androidx.compose.ui.graphics.drawscope.DrawScope 19 | import androidx.compose.ui.text.TextMeasurer 20 | 21 | public interface RadarChartDataRenderer { 22 | public fun drawChart( 23 | drawScope: DrawScope, 24 | centerX: Float, 25 | centerY: Float, 26 | radius: Float, 27 | textMeasurer: TextMeasurer, 28 | animationProgress: Float, 29 | isSystemInDarkTheme: Boolean, 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/radar/model/RadarChartData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.radar.model 17 | 18 | public data class RadarChartData( 19 | val values: Map, 20 | ) 21 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/scatterplot/ScatterPlotChartRenderer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.scatterplot 17 | 18 | import androidx.compose.ui.geometry.Offset 19 | import androidx.compose.ui.graphics.Color 20 | import androidx.compose.ui.graphics.drawscope.DrawScope 21 | import io.androidpoet.drafter.scatterplot.model.ScatterPlotData 22 | 23 | public interface ScatterPlotRenderer { 24 | public fun calculateMaxValues(): Pair 25 | 26 | public fun getPoints(): List> 27 | 28 | public fun drawPoints( 29 | drawScope: DrawScope, 30 | chartLeft: Float, 31 | chartTop: Float, 32 | chartWidth: Float, 33 | chartHeight: Float, 34 | maxX: Float, 35 | maxY: Float, 36 | animationProgress: Float, 37 | ) 38 | } 39 | 40 | public class SimpleScatterPlotRenderer( 41 | public val data: ScatterPlotData, 42 | ) : ScatterPlotRenderer { 43 | override fun calculateMaxValues(): Pair { 44 | val maxX = data.points.maxOfOrNull { it.first } ?: 0f 45 | val maxY = data.points.maxOfOrNull { it.second } ?: 0f 46 | return Pair(maxX, maxY) 47 | } 48 | 49 | override fun getPoints(): List> = data.points 50 | 51 | override fun drawPoints( 52 | drawScope: DrawScope, 53 | chartLeft: Float, 54 | chartTop: Float, 55 | chartWidth: Float, 56 | chartHeight: Float, 57 | maxX: Float, 58 | maxY: Float, 59 | animationProgress: Float, 60 | ) { 61 | data.points.forEachIndexed { index, point -> 62 | val x = chartLeft + (point.first / maxX) * chartWidth 63 | val y = chartTop + chartHeight - (point.second / maxY) * chartHeight 64 | 65 | val pointSize = 5f * animationProgress 66 | 67 | val color = 68 | if (index < data.pointColors.size) data.pointColors[index] else Color.Gray 69 | drawScope.drawCircle( 70 | color = color.copy(alpha = animationProgress), 71 | radius = pointSize, 72 | center = Offset(x, y), 73 | ) 74 | } 75 | } 76 | } 77 | 78 | public fun DrawScope.drawAxes( 79 | left: Float, 80 | top: Float, 81 | bottom: Float, 82 | width: Float, 83 | isSystemInDarkTheme: Boolean, 84 | ) { 85 | drawLine( 86 | if (isSystemInDarkTheme) Color.White else Color.Black, 87 | Offset(left, top), 88 | Offset(left, bottom), 89 | strokeWidth = 2f, 90 | ) 91 | drawLine( 92 | if (isSystemInDarkTheme) Color.White else Color.Black, 93 | Offset(left, bottom), 94 | Offset(left + width, bottom), 95 | strokeWidth = 2f, 96 | ) 97 | } 98 | -------------------------------------------------------------------------------- /drafter/src/commonMain/kotlin/io/androidpoet/drafter/scatterplot/model/ScatterPlotData.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.androidpoet.drafter.scatterplot.model 17 | 18 | import androidx.compose.ui.graphics.Color 19 | 20 | public data class ScatterPlotData( 21 | val points: List>, 22 | val pointColors: List = listOf(Color.Black), 23 | ) 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # https://docs.gradle.org/current/userguide/build_environment.html#sec:configuring_jvm_memory 17 | org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC -Dlint.nullness.ignore-deprecated=true 18 | # https://docs.gradle.org/current/userguide/build_cache.html 19 | org.gradle.caching=true 20 | # When configured, Gradle will run in incubating parallel mode. 21 | # This option should only be used with decoupled projects. More details, visit 22 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 23 | org.gradle.parallel=true 24 | # Configure only necessary projects, useful with multimodule projects 25 | org.gradle.configureondemand=true 26 | # AndroidX Migration https://developer.android.com/jetpack/androidx/migrate 27 | android.useAndroidX=true 28 | # Removes uneccessary default build features 29 | android.defaults.buildfeatures.aidl=false 30 | android.defaults.buildfeatures.buildconfig=false 31 | android.defaults.buildfeatures.renderscript=false 32 | android.defaults.buildfeatures.resvalues=false 33 | android.defaults.buildfeatures.shaders=false 34 | # Enables namespacing of each library's R class so that its R class includes only the 35 | # resources declared in the library itself and none from the library's dependencies, 36 | # thereby reducing the size of the R class for that library 37 | # https://developer.android.com/studio/releases/gradle-plugin#4.1-nontransitive-r-class 38 | android.nonTransitiveRClass=true 39 | # MPP 40 | kotlin.mpp.enableCInteropCommonization=true 41 | kotlin.mpp.stability.nowarn=true 42 | kotlin.mpp.androidSourceSetLayoutVersion=2 43 | kotlin.native.binary.memoryModel=experimental 44 | kotlin.native.cacheKind=none 45 | # Compose 46 | org.jetbrains.compose.experimental.uikit.enabled=true 47 | org.jetbrains.compose.experimental.macos.enabled=true 48 | org.jetbrains.compose.experimental.jscanvas.enabled=true 49 | compose.kotlin.native.manageCacheKind=false 50 | # Required to publish to Nexus (see https://github.com/gradle/gradle/issues/11308) 51 | systemProp.org.gradle.internal.publish.checksums.insecure=true 52 | # Increase timeout when pushing to Sonatype (otherwise we get timeouts) 53 | systemProp.org.gradle.internal.http.socketTimeout=120000 54 | POM_URL=https://github.com/androidpoet/Drafter 55 | POM_SCM_URL=https://github.com/androidpoet/Drafter 56 | POM_SCM_CONNECTION=scm:git:git://github.com/androidpoet/Drafter.git 57 | POM_SCM_DEV_CONNECTION=scm:git:git://github.com/androidpoet/Drafter.git 58 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 59 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 60 | POM_LICENCE_DIST=repo 61 | POM_DEVELOPER_ID=androidpoet 62 | POM_DEVELOPER_NAME=Ranbir Singh 63 | POM_DEVELOPER_URL=https://github.com/androidpoet/ 64 | POM_DEVELOPER_EMAIL=poetdroid2@gmail.com 65 | SONATYPE_HOST=CENTRAL_PORTAL 66 | RELEASE_SIGNING_ENABLED=true 67 | SONATYPE_AUTOMATIC_RELEASE=true 68 | SONATYPE_CONNECT_TIMEOUT_SECONDS=60 69 | SONATYPE_CLOSE_TIMEOUT_SECONDS=900 -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | agp = "8.5.2" 3 | dokka = "1.9.10" 4 | kotlinxDatetime = "0.6.1" 5 | nexusPlugin = "0.29.0" 6 | kotlin = "2.0.20" 7 | kotlinBinaryCompatibility = "0.16.3" 8 | jvmTarget = "11" 9 | androidxComposeBom = "2024.05.00" 10 | androidxActivity = "1.9.2" 11 | androidxTest = "1.6.2" 12 | baselineProfiles = "1.3.1" 13 | uiAutomator = "2.3.0" 14 | spotless = "6.21.0" 15 | androidxMacroBenchmark = "1.3.0" 16 | jetbrains-compose = "1.6.11" 17 | 18 | [plugins] 19 | android-application = { id = "com.android.application", version.ref = "agp" } 20 | android-library = { id = "com.android.library", version.ref = "agp" } 21 | android-test = { id = "com.android.test", version.ref = "agp" } 22 | kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } 23 | kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } 24 | compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } 25 | dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } 26 | nexus-plugin = { id = "com.vanniktech.maven.publish", version.ref = "nexusPlugin" } 27 | kotlin-binary-compatibility = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "kotlinBinaryCompatibility" } 28 | spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } 29 | baseline-profile = { id = "androidx.baselineprofile", version.ref = "androidxMacroBenchmark" } 30 | jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "jetbrains-compose" } 31 | 32 | [libraries] 33 | androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidxComposeBom" } 34 | androidx-compose-ui = { group = "androidx.compose.animation", name = "animation" } 35 | androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } 36 | androidx-compose-material = { group = "androidx.compose.material", name = "material" } 37 | androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } 38 | androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidxActivity" } 39 | androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" } 40 | androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" } 41 | # unit test 42 | androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidxTest" } 43 | androidx-profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "baselineProfiles" } 44 | androidx-benchmark-macro = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidxMacroBenchmark" } 45 | androidx-test-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "uiAutomator" } 46 | kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndroidPoet/Drafter/b2cd0f60940dceddc88b0976d063ca45cd7871f4/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ], 6 | "packageRules": [ 7 | { 8 | "groupName": "Kotlin, KSP and Compose Compiler", 9 | "groupSlug": "kotlin", 10 | "matchPackagePrefixes": [ 11 | "com.google.devtools.ksp", 12 | "androidx.compose.compiler", 13 | "com.android.tools.build:gradle" 14 | ], 15 | "matchPackagePatterns": [ 16 | "org.jetbrains.kotlin.*" 17 | ], 18 | "enabled": false 19 | }, 20 | { 21 | "description": "Automatically merge minor and patch-level updates", 22 | "matchUpdateTypes": ["minor", "patch", "digest"], 23 | "automerge": true, 24 | "automergeType": "pr", 25 | "platformAutomerge": true 26 | }, 27 | { 28 | "description": "Exclude Spotless updates", 29 | "matchPackagePrefixes": ["com.diffplug.spotless"], 30 | "enabled": false 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /scripts/publish-module.gradle.kts: -------------------------------------------------------------------------------- 1 | import io.androidpoet.drafter.Configuration 2 | 3 | apply(plugin = "com.vanniktech.maven.publish") 4 | 5 | rootProject.extra.apply { 6 | val snapshot = System.getenv("SNAPSHOT").toBoolean() 7 | val libVersion = 8 | if (snapshot) { 9 | Configuration.snapshotVersionName 10 | } else { 11 | Configuration.versionName 12 | } 13 | set("libVersion", libVersion) 14 | } 15 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | mavenCentral() 6 | maven(url = "https://plugins.gradle.org/m2/") 7 | maven(url = "https://maven.pkg.jetbrains.space/public/p/compose/dev") 8 | } 9 | } 10 | dependencyResolutionManagement { 11 | repositories { 12 | google() 13 | mavenCentral() 14 | maven(url = "https://plugins.gradle.org/m2/") 15 | maven(url = "https://maven.pkg.jetbrains.space/public/p/compose/dev") 16 | } 17 | } 18 | rootProject.name = "DrafterDemo" 19 | include(":app") 20 | include(":drafter") 21 | include(":baselineprofile-app") 22 | include(":baselineprofile") 23 | -------------------------------------------------------------------------------- /spotless/copyright.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /spotless/copyright.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Designed and developed by 2024 androidpoet (Ranbir Singh) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /spotless/copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | --------------------------------------------------------------------------------