├── .idea ├── .name ├── .gitignore ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── compiler.xml ├── kotlinc.xml ├── vcs.xml ├── AndroidProjectSystem.xml ├── artifacts │ ├── app_desktop.xml │ ├── blueprint_no_op_js.xml │ ├── blueprint_no_op_desktop.xml │ ├── blueprint_no_op_wasm_js.xml │ ├── blueprint_js_2_0_0_alpha01.xml │ ├── blueprint_desktop_2_0_0_alpha01.xml │ ├── blueprint_wasm_js_2_0_0_alpha01.xml │ ├── blueprint_no_op_js_2_0_0_alpha01.xml │ ├── blueprint_no_op_wasm_js_2_0_0_alpha01.xml │ └── blueprint_no_op_desktop_2_0_0_alpha01.xml ├── deploymentTargetSelector.xml ├── misc.xml ├── gradle.xml ├── deploymentTargetDropDown.xml ├── runConfigurations.xml ├── inspectionProfiles │ └── Project_Default.xml ├── androidTestResultsUserPreferences.xml └── icon.svg ├── app ├── .gitignore ├── src │ ├── androidMain │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── themes.xml │ │ │ │ └── colors.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 │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-anydpi-v33 │ │ │ │ └── ic_launcher.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_background.xml │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ │ └── com │ │ │ └── popovanton0 │ │ │ └── blueprint │ │ │ └── app │ │ │ ├── Lab.android.kt │ │ │ └── MainActivity.kt │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── popovanton0 │ │ │ └── blueprint │ │ │ └── app │ │ │ └── ExampleUnitTest.kt │ ├── iosMain │ │ └── kotlin │ │ │ └── main.kt │ ├── desktopMain │ │ └── kotlin │ │ │ └── com │ │ │ └── popovanton0 │ │ │ └── blueprint │ │ │ └── app │ │ │ ├── Lab.desktop.kt │ │ │ └── Main.kt │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── popovanton0 │ │ │ └── blueprint │ │ │ └── app │ │ │ └── ExampleInstrumentedTest.kt │ └── commonMain │ │ └── kotlin │ │ └── com │ │ └── popovanton0 │ │ └── blueprint │ │ └── app │ │ └── ui │ │ └── theme │ │ └── Pipette.kt ├── proguard-rules.pro └── build.gradle.kts ├── blueprint ├── .gitignore ├── consumer-rules.pro ├── src │ ├── androidMain │ │ └── AndroidManifest.xml │ ├── commonMain │ │ └── kotlin │ │ │ └── com │ │ │ └── popovanton0 │ │ │ └── blueprint │ │ │ ├── dsl │ │ │ ├── BlueprintDslMarker.kt │ │ │ ├── Dimension.kt │ │ │ ├── Blueprint.kt │ │ │ ├── Group.kt │ │ │ ├── MeasureUnit.kt │ │ │ ├── Anchor.kt │ │ │ ├── SizeUnits.kt │ │ │ ├── GroupScope.kt │ │ │ ├── Position.kt │ │ │ ├── Arrow.kt │ │ │ ├── BlueprintBuilderScope.kt │ │ │ ├── VerticalScope.kt │ │ │ └── HorizontalScope.kt │ │ │ ├── ModifierLocalBlueprintMarkers.kt │ │ │ ├── BlueprintMarker.kt │ │ │ ├── ExperimentalBlueprintApi.kt │ │ │ ├── ModifierLocalProvider.kt │ │ │ └── BlueprintId.kt │ ├── androidUnitTest │ │ ├── snapshots │ │ │ └── images │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_basicTest.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_size_labels.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_emptyBlueprint.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_padding_not_applied.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_customFontSizeAndColor.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[0.0].png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_not_enough_space_to_draw.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_almost_none_space_to_draw.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[15.0].png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[45.0].png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[90.0].png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_fractional_dp_values_rendering.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_correct_line_widths_and_alignments.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_no_blueprint_if_globally_disabled.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_when_blueprint_is_disabled_it_is_not_shown.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_reacts_to_blueprint_builder_update_(with_green).png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_reacts_to_blueprint_builder_update_(without_green).png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_not_referenced_in_the_composable_no_dimensions_are_shown.png │ │ │ │ ├── com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(with_green).png │ │ │ │ └── com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(without_green).png │ │ └── kotlin │ │ │ └── com │ │ │ └── popovanton0 │ │ │ └── blueprint │ │ │ ├── BlueprintClass.kt │ │ │ ├── Dsl.kt │ │ │ └── BlueprintScreenshotTest.kt │ └── androidInstrumentedTest │ │ └── java │ │ └── com │ │ └── popovanton0 │ │ └── blueprint │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro ├── build.gradle.kts └── api │ ├── blueprint.api │ ├── android │ └── blueprint.api │ └── desktop │ └── blueprint.api ├── NOTICE ├── blueprint-no-op ├── .gitignore ├── consumer-rules.pro ├── src │ ├── androidMain │ │ └── AndroidManifest.xml │ ├── commonMain │ │ └── kotlin │ │ │ └── com │ │ │ └── popovanton0 │ │ │ └── blueprint │ │ │ ├── dsl │ │ │ ├── BlueprintDslMarker.kt │ │ │ ├── BlueprintBuilderScope.kt │ │ │ ├── GroupScope.kt │ │ │ ├── MeasureUnit.kt │ │ │ ├── Anchor.kt │ │ │ ├── SizeUnits.kt │ │ │ ├── VerticalScope.kt │ │ │ ├── HorizontalScope.kt │ │ │ ├── Arrow.kt │ │ │ └── Position.kt │ │ │ ├── ExperimentalBlueprintApi.kt │ │ │ ├── BlueprintId.kt │ │ │ └── Blueprint.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── popovanton0 │ │ └── blueprint │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro ├── build.gradle.kts └── api │ ├── android │ └── blueprint-no-op.api │ └── desktop │ └── blueprint-no-op.api ├── jitpack.yml ├── images ├── button-dark.png ├── button-light.png ├── navbar-dark.png ├── navbar-light.png ├── arrow-angle-anim.mp4 ├── combinations-dark.png ├── combinations-light.png └── arrow-angle-anim-debug.mp4 ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── iosApp ├── blueprintDemoApp │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── blueprintDemoAppApp.swift ├── blueprintDemoApp.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcuserdata │ │ └── arogachevskiy.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── blueprintDemoAppTests │ └── blueprintDemoAppTests.swift └── blueprintDemoAppUITests │ ├── blueprintDemoAppUITestsLaunchTests.swift │ └── blueprintDemoAppUITests.swift ├── .gitignore ├── settings.gradle.kts ├── gradle.properties ├── gradlew.bat ├── gradlew ├── LICENSE └── README.md /.idea/.name: -------------------------------------------------------------------------------- 1 | Blueprint -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /blueprint/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /blueprint/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2023, Anton Popov -------------------------------------------------------------------------------- /blueprint-no-op/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk17 -------------------------------------------------------------------------------- /blueprint-no-op/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /blueprint/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /images/button-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/images/button-dark.png -------------------------------------------------------------------------------- /images/button-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/images/button-light.png -------------------------------------------------------------------------------- /images/navbar-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/images/navbar-dark.png -------------------------------------------------------------------------------- /images/navbar-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/images/navbar-light.png -------------------------------------------------------------------------------- /blueprint-no-op/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /images/arrow-angle-anim.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/images/arrow-angle-anim.mp4 -------------------------------------------------------------------------------- /images/combinations-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/images/combinations-dark.png -------------------------------------------------------------------------------- /images/combinations-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/images/combinations-light.png -------------------------------------------------------------------------------- /app/src/androidMain/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Blueprint 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /images/arrow-angle-anim-debug.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/images/arrow-angle-anim-debug.mp4 -------------------------------------------------------------------------------- /iosApp/blueprintDemoApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/app/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/BlueprintDslMarker.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | @DslMarker 4 | internal annotation class BlueprintDslMarker 5 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/BlueprintDslMarker.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | @DslMarker 4 | internal annotation class BlueprintDslMarker 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /iosApp/blueprintDemoApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iosApp/blueprintDemoApp/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /.idea/artifacts/app_desktop.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/app/build/libs 4 | 5 | 6 | -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_basicTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_basicTest.png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_size_labels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_size_labels.png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_emptyBlueprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_emptyBlueprint.png -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_no_op_js.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint-no-op/build/libs 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/androidMain/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_padding_not_applied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_padding_not_applied.png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_customFontSizeAndColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_customFontSizeAndColor.png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[0.0].png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[0.0].png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_not_enough_space_to_draw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_not_enough_space_to_draw.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_no_op_desktop.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint-no-op/build/libs 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_no_op_wasm_js.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint-no-op/build/libs 4 | 5 | 6 | -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_almost_none_space_to_draw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_almost_none_space_to_draw.png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[15.0].png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[15.0].png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[45.0].png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[45.0].png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[90.0].png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[90.0].png -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/ModifierLocalBlueprintMarkers.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.compose.ui.modifier.modifierLocalOf 4 | 5 | internal val ModifierLocalBlueprintMarkers = 6 | modifierLocalOf?> { null } -------------------------------------------------------------------------------- /iosApp/blueprintDemoApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_js_2_0_0_alpha01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint/build/libs 4 | 5 | 6 | -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_fractional_dp_values_rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_fractional_dp_values_rendering.png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_correct_line_widths_and_alignments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_correct_line_widths_and_alignments.png -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_no_blueprint_if_globally_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_no_blueprint_if_globally_disabled.png -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_desktop_2_0_0_alpha01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint/build/libs 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_wasm_js_2_0_0_alpha01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint/build/libs 4 | 5 | 6 | -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/BlueprintMarker.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.compose.ui.layout.LayoutCoordinates 4 | import com.popovanton0.blueprint.dsl.SizeUnits 5 | 6 | internal data class BlueprintMarker(val coordinates: LayoutCoordinates, val sizeUnits: SizeUnits?) -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_blueprint_is_disabled_it_is_not_shown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_blueprint_is_disabled_it_is_not_shown.png -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_reacts_to_blueprint_builder_update_(with_green).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_reacts_to_blueprint_builder_update_(with_green).png -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/ExperimentalBlueprintApi.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | @RequiresOptIn( 4 | "This is EXTREMELY experimental API and it will definitely change or be removed in the future." 5 | ) 6 | @Retention(AnnotationRetention.BINARY) 7 | public annotation class ExperimentalBlueprintApi 8 | -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/ExperimentalBlueprintApi.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | @RequiresOptIn( 4 | "This is EXTREMELY experimental API and it will definitely change or be removed in the future." 5 | ) 6 | @Retention(AnnotationRetention.BINARY) 7 | public annotation class ExperimentalBlueprintApi 8 | -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_reacts_to_blueprint_builder_update_(without_green).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_reacts_to_blueprint_builder_update_(without_green).png -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Dimension.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | 5 | @Immutable 6 | internal data class Dimension internal constructor( 7 | internal val startAnchor: Anchor, 8 | internal val endAnchor: Anchor, 9 | internal val unit: MeasureUnit 10 | ) -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/androidMain/res/mipmap-anydpi-v33/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_no_op_js_2_0_0_alpha01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint-no-op/build/libs 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/BlueprintId.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.compose.runtime.Stable 4 | import androidx.compose.ui.Modifier 5 | import com.popovanton0.blueprint.dsl.SizeUnits 6 | 7 | /** 8 | * No-op implementation. 9 | */ 10 | @Stable 11 | public fun Modifier.blueprintId( 12 | id: String, 13 | sizeUnits: SizeUnits? = null 14 | ): Modifier = this -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_no_op_wasm_js_2_0_0_alpha01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint-no-op/build/libs 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_not_referenced_in_the_composable_no_dimensions_are_shown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_not_referenced_in_the_composable_no_dimensions_are_shown.png -------------------------------------------------------------------------------- /.idea/artifacts/blueprint_no_op_desktop_2_0_0_alpha01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/blueprint-no-op/build/libs 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /app/src/androidMain/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /iosApp/blueprintDemoAppTests/blueprintDemoAppTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // blueprintDemoAppTests.swift 3 | // blueprintDemoAppTests 4 | // 5 | // Created by Aleksey Rogachevskiy on 10.05.2025. 6 | // 7 | 8 | import Testing 9 | @testable import blueprintDemoApp 10 | 11 | struct blueprintDemoAppTests { 12 | 13 | @Test func example() async throws { 14 | // Write your test here and use APIs like `#expect(...)` to check expected conditions. 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/test/java/com/popovanton0/blueprint/app/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.app 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(with_green).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(with_green).png -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/BlueprintBuilderScope.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | @BlueprintDslMarker 4 | public class BlueprintBuilderScope internal constructor() { 5 | /** 6 | * No-op implementation. 7 | */ 8 | public fun widths(block: HorizontalScope.() -> Unit): Unit = Unit 9 | 10 | /** 11 | * No-op implementation. 12 | */ 13 | public fun heights(block: VerticalScope.() -> Unit): Unit = Unit 14 | } -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(without_green).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/popovanton0/Blueprint/HEAD/blueprint/src/androidUnitTest/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(without_green).png -------------------------------------------------------------------------------- /iosApp/blueprintDemoApp.xcodeproj/xcuserdata/arogachevskiy.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | blueprintDemoApp.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | pluginManagement { 4 | repositories { 5 | mavenCentral() 6 | google() 7 | gradlePluginPortal() 8 | } 9 | } 10 | dependencyResolutionManagement { 11 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 12 | repositories { 13 | mavenCentral() 14 | google() 15 | } 16 | } 17 | rootProject.name = "Blueprint" 18 | include(":app") 19 | include(":blueprint") 20 | include(":blueprint-no-op") 21 | -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/GroupScope.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 4 | 5 | public abstract class GroupScope internal constructor() { 6 | /** 7 | * No-op implementation. 8 | */ 9 | public infix fun Anchor.lineTo(other: Anchor): Unit = Unit 10 | 11 | /** 12 | * No-op implementation. 13 | */ 14 | @ExperimentalBlueprintApi 15 | public infix fun Anchor.spLineTo(other: Anchor): Unit = Unit 16 | } -------------------------------------------------------------------------------- /app/src/iosMain/kotlin/main.kt: -------------------------------------------------------------------------------- 1 | import androidx.compose.foundation.layout.fillMaxSize 2 | import androidx.compose.ui.window.ComposeUIViewController 3 | import androidx.compose.material3.MaterialTheme 4 | import androidx.compose.material3.Surface 5 | import androidx.compose.ui.Modifier 6 | import platform.UIKit.UIViewController 7 | import com.popovanton0.blueprint.app.Lab 8 | 9 | fun MainViewController(): UIViewController = ComposeUIViewController { 10 | MaterialTheme { 11 | Surface(modifier = Modifier.fillMaxSize()) { 12 | Lab() 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/desktopMain/kotlin/com/popovanton0/blueprint/app/Lab.desktop.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.app 2 | 3 | import androidx.compose.desktop.ui.tooling.preview.Preview 4 | import androidx.compose.runtime.Composable 5 | 6 | @Preview 7 | @Composable 8 | private fun LabPreview() = Lab() 9 | 10 | @Preview 11 | @Composable 12 | private fun SamplePreview() = Sample("Lorem ipsum dolor sit amet, consectetur adipiscing elit") 13 | 14 | @Preview 15 | @Composable 16 | private fun ManyButtonsSamplePreview() = ManyButtonsSample() 17 | 18 | @Preview 19 | @Composable 20 | private fun NavigationBarSamplePreview() = NavigationBarSample() 21 | -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Blueprint.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | 5 | @Immutable 6 | internal data class Blueprint internal constructor( 7 | internal val horizontalTopGroups: List, 8 | internal val horizontalBottomGroups: List, 9 | internal val verticalLeftGroups: List, 10 | internal val verticalRightGroups: List, 11 | ) { 12 | internal val groupCollection: List> = listOf( 13 | horizontalTopGroups, 14 | horizontalBottomGroups, 15 | verticalLeftGroups, 16 | verticalRightGroups, 17 | ) 18 | } -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Group.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | 5 | @Immutable 6 | internal sealed class Group { 7 | internal abstract val dimensions: List 8 | internal abstract val position: Position 9 | } 10 | 11 | @Immutable 12 | internal data class HorizontalGroup internal constructor( 13 | override val dimensions: List, 14 | override val position: Position.Vertical, 15 | ) : Group() 16 | 17 | @Immutable 18 | internal data class VerticalGroup internal constructor( 19 | override val dimensions: List, 20 | override val position: Position.Horizontal, 21 | ) : Group() -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/MeasureUnit.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 4 | import kotlin.jvm.JvmInline 5 | 6 | @JvmInline 7 | public value class MeasureUnit private constructor(private val value: Int) { 8 | override fun toString(): String = when (this) { 9 | Dp -> "Dp" 10 | Sp -> "Sp" 11 | else -> "Invalid" 12 | } 13 | 14 | public companion object { 15 | public val Dp: MeasureUnit = MeasureUnit(0) 16 | 17 | /** 18 | * Currently doesn't work correctly 19 | */ 20 | @ExperimentalBlueprintApi 21 | public val Sp: MeasureUnit = MeasureUnit(1) 22 | } 23 | } -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/MeasureUnit.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 4 | import kotlin.jvm.JvmInline 5 | 6 | @JvmInline 7 | public value class MeasureUnit private constructor(private val value: Int) { 8 | override fun toString(): String = when (this) { 9 | Dp -> "Dp" 10 | Sp -> "Sp" 11 | else -> "Invalid" 12 | } 13 | 14 | public companion object { 15 | public val Dp: MeasureUnit = MeasureUnit(0) 16 | 17 | /** 18 | * Currently doesn't work correctly 19 | */ 20 | @ExperimentalBlueprintApi 21 | public val Sp: MeasureUnit = MeasureUnit(1) 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/desktopMain/kotlin/com/popovanton0/blueprint/app/Main.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.app 2 | 3 | import androidx.compose.foundation.layout.fillMaxSize 4 | import androidx.compose.material3.MaterialTheme 5 | import androidx.compose.material3.Surface 6 | import androidx.compose.ui.Modifier 7 | import androidx.compose.ui.window.application 8 | import androidx.compose.ui.window.Window 9 | 10 | fun main() = application { 11 | Window( 12 | onCloseRequest = ::exitApplication, 13 | title = "Blueprint Demo", 14 | ) { 15 | MaterialTheme { 16 | Surface( 17 | modifier = Modifier.fillMaxSize(), 18 | color = MaterialTheme.colorScheme.background 19 | ) { 20 | Lab() 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /iosApp/blueprintDemoApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "idiom" : "universal", 16 | "platform" : "ios", 17 | "size" : "1024x1024" 18 | }, 19 | { 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "tinted" 24 | } 25 | ], 26 | "idiom" : "universal", 27 | "platform" : "ios", 28 | "size" : "1024x1024" 29 | } 30 | ], 31 | "info" : { 32 | "author" : "xcode", 33 | "version" : 1 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/popovanton0/blueprint/app/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.app 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.popovanton0.blueprint", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /blueprint/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /blueprint-no-op/src/androidTest/java/com/popovanton0/blueprint/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.* 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | internal class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("com.popovanton0.blueprint.test", appContext.packageName) 21 | } 22 | } -------------------------------------------------------------------------------- /blueprint-no-op/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /blueprint/src/androidInstrumentedTest/java/com/popovanton0/blueprint/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.* 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | internal class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("com.popovanton0.blueprint.test", appContext.packageName) 21 | } 22 | } -------------------------------------------------------------------------------- /iosApp/blueprintDemoApp/blueprintDemoAppApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // blueprintDemoAppApp.swift 3 | // blueprintDemoApp 4 | // 5 | // Created by Aleksey Rogachevskiy on 10.05.2025. 6 | // 7 | 8 | import UIKit 9 | import SwiftUI 10 | import blueprintDemoCompose 11 | 12 | @main 13 | struct blueprintDemoAppApp: App { 14 | var body: some Scene { 15 | WindowGroup { 16 | ContentView() 17 | } 18 | } 19 | } 20 | 21 | struct ContentView: View { 22 | var body: some View { 23 | ComposeView().ignoresSafeArea() 24 | } 25 | } 26 | 27 | struct ComposeView: UIViewControllerRepresentable { 28 | func makeUIViewController(context: Context) -> some UIViewController { 29 | MainKt.MainViewController() 30 | } 31 | 32 | func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {} 33 | } 34 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Anchor.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | 5 | @Immutable 6 | public class Anchor internal constructor( 7 | internal val key: String, 8 | internal val alignment: Float, 9 | ) { 10 | init { 11 | require(alignment in 0f..1f) { "Alignment must be in [0..1]" } 12 | } 13 | 14 | override fun equals(other: Any?): Boolean { 15 | if (this === other) return true 16 | if (other == null || this::class != other::class) return false 17 | 18 | other as Anchor 19 | 20 | if (key != other.key) return false 21 | if (alignment.compareTo(other.alignment) != 0) return false 22 | 23 | return true 24 | } 25 | 26 | override fun hashCode(): Int { 27 | var result = key.hashCode() 28 | result = 31 * result + alignment.hashCode() 29 | return result 30 | } 31 | } -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Anchor.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | 5 | @Immutable 6 | public class Anchor internal constructor( 7 | internal val key: String, 8 | internal val alignment: Float, 9 | ) { 10 | init { 11 | require(alignment in 0f..1f) { "Alignment must be in [0..1]" } 12 | } 13 | 14 | override fun equals(other: Any?): Boolean { 15 | if (this === other) return true 16 | if (other == null || this::class != other::class) return false 17 | 18 | other as Anchor 19 | 20 | if (key != other.key) return false 21 | if (alignment.compareTo(other.alignment) != 0) return false 22 | 23 | return true 24 | } 25 | 26 | override fun hashCode(): Int { 27 | var result = key.hashCode() 28 | result = 31 * result + alignment.hashCode() 29 | return result 30 | } 31 | } -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/androidMain/kotlin/com/popovanton0/blueprint/app/Lab.android.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.app 2 | 3 | import android.content.res.Configuration 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.tooling.preview.Preview 6 | import androidx.compose.ui.tooling.preview.datasource.LoremIpsum 7 | 8 | 9 | @Preview(fontScale = 1.0f) 10 | @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) 11 | @Composable 12 | private fun LabPreview() = Lab() 13 | 14 | @Preview 15 | @Composable 16 | private fun SamplePreview() = Sample(LoremIpsum(6).values.joinToString(separator = " ")) 17 | 18 | @Preview(widthDp = 750) 19 | @Preview(widthDp = 750, uiMode = Configuration.UI_MODE_NIGHT_YES) 20 | @Composable 21 | private fun ManyButtonsSamplePreview() = ManyButtonsSample() 22 | 23 | @Preview(widthDp = 500) 24 | @Preview(widthDp = 500, uiMode = Configuration.UI_MODE_NIGHT_YES) 25 | @Composable 26 | private fun NavigationBarSamplePreview() = NavigationBarSample() 27 | 28 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /iosApp/blueprintDemoAppUITests/blueprintDemoAppUITestsLaunchTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // blueprintDemoAppUITestsLaunchTests.swift 3 | // blueprintDemoAppUITests 4 | // 5 | // Created by Aleksey Rogachevskiy on 10.05.2025. 6 | // 7 | 8 | import XCTest 9 | 10 | final class blueprintDemoAppUITestsLaunchTests: XCTestCase { 11 | 12 | override class var runsForEachTargetApplicationUIConfiguration: Bool { 13 | true 14 | } 15 | 16 | override func setUpWithError() throws { 17 | continueAfterFailure = false 18 | } 19 | 20 | @MainActor 21 | func testLaunch() throws { 22 | let app = XCUIApplication() 23 | app.launch() 24 | 25 | // Insert steps here to perform after app launch but before taking a screenshot, 26 | // such as logging into a test account or navigating somewhere in the app 27 | 28 | let attachment = XCTAttachment(screenshot: app.screenshot()) 29 | attachment.name = "Launch Screen" 30 | attachment.lifetime = .keepAlways 31 | add(attachment) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/SizeUnits.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 5 | 6 | @Immutable 7 | public class SizeUnits( 8 | public val xUnit: MeasureUnit = MeasureUnit.Dp, 9 | public val yUnit: MeasureUnit = MeasureUnit.Dp, 10 | ) { 11 | public companion object { 12 | public val Dp: SizeUnits = SizeUnits() 13 | 14 | @ExperimentalBlueprintApi 15 | public val Sp: SizeUnits = SizeUnits(MeasureUnit.Sp, MeasureUnit.Sp) 16 | } 17 | 18 | override fun equals(other: Any?): Boolean { 19 | if (this === other) return true 20 | if (other == null || this::class != other::class) return false 21 | 22 | other as SizeUnits 23 | 24 | if (xUnit != other.xUnit) return false 25 | if (yUnit != other.yUnit) return false 26 | 27 | return true 28 | } 29 | 30 | override fun hashCode(): Int { 31 | var result = xUnit.hashCode() 32 | result = 31 * result + yUnit.hashCode() 33 | return result 34 | } 35 | } -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/SizeUnits.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 5 | 6 | @Immutable 7 | public class SizeUnits( 8 | public val xUnit: MeasureUnit = MeasureUnit.Dp, 9 | public val yUnit: MeasureUnit = MeasureUnit.Dp, 10 | ) { 11 | public companion object { 12 | public val Dp: SizeUnits = SizeUnits() 13 | 14 | @ExperimentalBlueprintApi 15 | public val Sp: SizeUnits = SizeUnits(MeasureUnit.Sp, MeasureUnit.Sp) 16 | } 17 | 18 | override fun equals(other: Any?): Boolean { 19 | if (this === other) return true 20 | if (other == null || this::class != other::class) return false 21 | 22 | other as SizeUnits 23 | 24 | if (xUnit != other.xUnit) return false 25 | if (yUnit != other.yUnit) return false 26 | 27 | return true 28 | } 29 | 30 | override fun hashCode(): Int { 31 | var result = xUnit.hashCode() 32 | result = 31 * result + yUnit.hashCode() 33 | return result 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/commonMain/kotlin/com/popovanton0/blueprint/app/ui/theme/Pipette.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.app.ui.theme 2 | 3 | import androidx.compose.foundation.border 4 | import androidx.compose.foundation.layout.padding 5 | import androidx.compose.material3.Text 6 | import androidx.compose.runtime.* 7 | import androidx.compose.ui.Modifier 8 | import androidx.compose.ui.graphics.Color 9 | import androidx.compose.ui.layout.LayoutCoordinates 10 | import androidx.compose.ui.modifier.modifierLocalConsumer 11 | import androidx.compose.ui.unit.dp 12 | 13 | 14 | @Composable 15 | internal fun Pipette() { 16 | var markers by remember { 17 | mutableStateOf?>(null) 18 | } 19 | Text( 20 | modifier = Modifier 21 | .border(2.dp, color = Color.Yellow) 22 | .padding(3.dp) 23 | .modifierLocalConsumer { 24 | //markers = ModifierLocalBlueprintMarkers.current 25 | }, 26 | text = markers?.entries?.joinToString( 27 | prefix = "Pipette content:\n", 28 | separator = "\n", 29 | transform = { it.key } 30 | ).toString() 31 | ) 32 | } -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/VerticalScope.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 4 | import com.popovanton0.blueprint.dsl.Position.Horizontal.Companion.Start 5 | 6 | @BlueprintDslMarker 7 | public class VerticalScope internal constructor() { 8 | /** 9 | * No-op implementation. 10 | */ 11 | public fun group( 12 | position: Position.Horizontal = Start, 13 | block: VerticalGroupScope.() -> Unit 14 | ): Unit = Unit 15 | } 16 | 17 | private val DefautlAnchor = Anchor("", 0f) 18 | 19 | @BlueprintDslMarker 20 | public class VerticalGroupScope internal constructor() : GroupScope() { 21 | public val String.top: Anchor get() = DefautlAnchor 22 | public val String.center: Anchor get() = DefautlAnchor 23 | public val String.bottom: Anchor get() = DefautlAnchor 24 | 25 | /** 26 | * No-op implementation. 27 | */ 28 | public infix fun String.lineTo(other: String): Unit = Unit 29 | 30 | /** 31 | * No-op implementation. 32 | */ 33 | @ExperimentalBlueprintApi 34 | public infix fun String.spLineTo(other: String): Unit = Unit 35 | } -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/HorizontalScope.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 4 | import com.popovanton0.blueprint.dsl.Position.Vertical.Companion.Bottom 5 | 6 | @BlueprintDslMarker 7 | public class HorizontalScope internal constructor() { 8 | /** 9 | * No-op implementation. 10 | */ 11 | public fun group( 12 | position: Position.Vertical = Bottom, 13 | block: HorizontalGroupScope.() -> Unit 14 | ): Unit = Unit 15 | } 16 | 17 | private val DefautlAnchor = Anchor("", 0f) 18 | 19 | @BlueprintDslMarker 20 | public class HorizontalGroupScope internal constructor() : GroupScope() { 21 | public val String.left: Anchor get() = DefautlAnchor 22 | public val String.center: Anchor get() = DefautlAnchor 23 | public val String.right: Anchor get() = DefautlAnchor 24 | 25 | /** 26 | * No-op implementation. 27 | */ 28 | public infix fun String.lineTo(other: String): Unit = Unit 29 | 30 | /** 31 | * No-op implementation. 32 | */ 33 | @ExperimentalBlueprintApi 34 | public infix fun String.spLineTo(other: String): Unit = Unit 35 | } -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/GroupScope.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 4 | 5 | public abstract class GroupScope internal constructor() { 6 | internal val dimensions = mutableListOf() 7 | 8 | /** 9 | * Defines a dimension line from the [this] to the [other]. 10 | * 11 | * [Anchor] is acquired from these extensions on [String]: 12 | * - [VerticalGroupScope.top], 13 | * - [VerticalGroupScope.bottom], 14 | * - [VerticalGroupScope.center]. 15 | * - [HorizontalGroupScope.left], 16 | * - [HorizontalGroupScope.center], 17 | * - [HorizontalGroupScope.right]. 18 | * 19 | * Length on the resulting dimension line is in [MeasureUnit.Dp]s. 20 | */ 21 | public infix fun Anchor.lineTo(other: Anchor) { 22 | dimensions.add(Dimension(this, other, MeasureUnit.Dp)) 23 | } 24 | 25 | /** 26 | * Length on the resulting dimension line is in [MeasureUnit.Sp]s. 27 | * 28 | * @see lineTo 29 | */ 30 | @ExperimentalBlueprintApi 31 | public infix fun Anchor.spLineTo(other: Anchor) { 32 | dimensions.add(Dimension(this, other, MeasureUnit.Sp)) 33 | } 34 | } -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/Blueprint.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.annotation.IntRange 4 | import androidx.compose.foundation.BorderStroke 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.Modifier 7 | import androidx.compose.ui.graphics.Color 8 | import androidx.compose.ui.unit.TextUnit 9 | import androidx.compose.ui.unit.dp 10 | import com.popovanton0.blueprint.dsl.Arrow 11 | import com.popovanton0.blueprint.dsl.BlueprintBuilderScope 12 | 13 | /** 14 | * No-op implementation. 15 | */ 16 | public var blueprintEnabled: Boolean = true 17 | 18 | /** 19 | * No-op implementation. 20 | */ 21 | @Composable 22 | public fun Blueprint( 23 | modifier: Modifier = Modifier, 24 | lineStroke: BorderStroke = DefaultStroke, 25 | borderStroke: BorderStroke = DefaultStroke, 26 | fontSize: TextUnit = TextUnit.Unspecified, 27 | fontColor: Color = Color.Unspecified, 28 | arrow: Arrow? = null, 29 | @IntRange(from = 0) precision: Int = 1, 30 | densityRounding: Boolean = true, 31 | applyPadding: Boolean = true, 32 | enabled: Boolean = true, 33 | blueprintBuilder: BlueprintBuilderScope.() -> Unit, 34 | content: @Composable () -> Unit, 35 | ): Unit = Unit 36 | 37 | private val DefaultStroke = BorderStroke(1.dp, Color.Red) -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Arrow.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.ui.unit.Dp 4 | import androidx.compose.ui.unit.isFinite 5 | import androidx.compose.ui.unit.isSpecified 6 | 7 | /** 8 | * No-op implementation. 9 | */ 10 | public class Arrow( 11 | public val length: Dp, 12 | public val angle: Float = 35f, 13 | public val roundCap: Boolean = false, 14 | ) { 15 | init { 16 | require(length.isSpecified && length.isFinite) { 17 | "Invalid arrow length: must be finite and specified" 18 | } 19 | require(angle in 0f..90f) { "Invalid arrow angle: must be in [0..180]" } 20 | } 21 | 22 | override fun equals(other: Any?): Boolean { 23 | if (this === other) return true 24 | if (other == null || this::class != other::class) return false 25 | 26 | other as Arrow 27 | 28 | if (length != other.length) return false 29 | if (angle.compareTo(other.angle) != 0) return false 30 | if (roundCap != other.roundCap) return false 31 | 32 | return true 33 | } 34 | 35 | override fun hashCode(): Int { 36 | var result = length.hashCode() 37 | result = 31 * result + angle.hashCode() 38 | result = 31 * result + roundCap.hashCode() 39 | return result 40 | } 41 | } -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/ModifierLocalProvider.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.compose.runtime.derivedStateOf 4 | import androidx.compose.runtime.getValue 5 | import androidx.compose.ui.ExperimentalComposeUiApi 6 | import androidx.compose.ui.Modifier 7 | import androidx.compose.ui.modifier.ModifierLocalProvider 8 | import androidx.compose.ui.modifier.ProvidableModifierLocal 9 | import androidx.compose.ui.modifier.modifierLocalProvider 10 | import androidx.compose.ui.platform.InspectorValueInfo 11 | import androidx.compose.ui.platform.debugInspectorInfo 12 | 13 | /** 14 | * Internal copy of [ExperimentalComposeUiApi] [modifierLocalProvider], to not depend on 15 | * experimental APIs. 16 | */ 17 | internal fun Modifier.blueprintModifierLocalProvider( 18 | key: ProvidableModifierLocal, 19 | value: () -> T 20 | ): Modifier { 21 | return this.then( 22 | object : ModifierLocalProvider, InspectorValueInfo( 23 | debugInspectorInfo { 24 | name = "blueprintModifierLocalProvider" 25 | properties["key"] = key 26 | properties["value"] = value 27 | } 28 | ) { 29 | override val key: ProvidableModifierLocal = key 30 | override val value by derivedStateOf(value) 31 | } 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Position.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | import kotlin.jvm.JvmInline 5 | 6 | @Immutable 7 | public sealed interface Position { 8 | 9 | @JvmInline 10 | public value class Horizontal private constructor(private val value: Int) : Position { 11 | override fun toString(): String = when (this) { 12 | Start -> "Start" 13 | End -> "End" 14 | else -> "Invalid" 15 | } 16 | 17 | internal fun toRtl(isRtl: Boolean) = when (this) { 18 | Start -> if (isRtl) End else Start 19 | End -> if (isRtl) Start else End 20 | else -> error("Invalid") 21 | } 22 | 23 | public companion object { 24 | public val Start: Horizontal = Horizontal(0) 25 | public val End: Horizontal = Horizontal(1) 26 | } 27 | } 28 | 29 | @JvmInline 30 | public value class Vertical private constructor(private val value: Int) : Position { 31 | override fun toString(): String = when (this) { 32 | Top -> "Top" 33 | Bottom -> "Bottom" 34 | else -> "Invalid" 35 | } 36 | 37 | public companion object { 38 | public val Top: Vertical = Vertical(0) 39 | public val Bottom: Vertical = Vertical(1) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /blueprint-no-op/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Position.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.runtime.Immutable 4 | import kotlin.jvm.JvmInline 5 | 6 | @Immutable 7 | public sealed interface Position { 8 | 9 | @JvmInline 10 | public value class Horizontal private constructor(private val value: Int) : Position { 11 | override fun toString(): String = when (this) { 12 | Start -> "Start" 13 | End -> "End" 14 | else -> "Invalid" 15 | } 16 | 17 | internal fun toRtl(isRtl: Boolean) = when (this) { 18 | Start -> if (isRtl) End else Start 19 | End -> if (isRtl) Start else End 20 | else -> error("Invalid") 21 | } 22 | 23 | public companion object { 24 | public val Start: Horizontal = Horizontal(0) 25 | public val End: Horizontal = Horizontal(1) 26 | } 27 | } 28 | 29 | @JvmInline 30 | public value class Vertical private constructor(private val value: Int) : Position { 31 | override fun toString(): String = when (this) { 32 | Top -> "Top" 33 | Bottom -> "Bottom" 34 | else -> "Invalid" 35 | } 36 | 37 | public companion object { 38 | public val Top: Vertical = Vertical(0) 39 | public val Bottom: Vertical = Vertical(1) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /iosApp/blueprintDemoAppUITests/blueprintDemoAppUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // blueprintDemoAppUITests.swift 3 | // blueprintDemoAppUITests 4 | // 5 | // Created by Aleksey Rogachevskiy on 10.05.2025. 6 | // 7 | 8 | import XCTest 9 | 10 | final class blueprintDemoAppUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | @MainActor 26 | func testExample() throws { 27 | // UI tests must launch the application that they test. 28 | let app = XCUIApplication() 29 | app.launch() 30 | 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | @MainActor 35 | func testLaunchPerformance() throws { 36 | // This measures how long it takes to launch your application. 37 | measure(metrics: [XCTApplicationLaunchMetric()]) { 38 | XCUIApplication().launch() 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | 25 | org.jetbrains.compose.experimental.jscanvas.enabled=true 26 | kotlin.native.enableKlibsCrossCompilation=true 27 | -------------------------------------------------------------------------------- /app/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/Arrow.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import androidx.compose.ui.unit.Dp 4 | import androidx.compose.ui.unit.isFinite 5 | import androidx.compose.ui.unit.isSpecified 6 | import androidx.compose.ui.unit.times 7 | import kotlin.math.cos 8 | import kotlin.math.sin 9 | import kotlin.math.PI 10 | 11 | /** 12 | * Arrow extending from the dimension lines in four directions 13 | */ 14 | public class Arrow( 15 | public val length: Dp, 16 | public val angle: Float = 35f, 17 | public val roundCap: Boolean = false, 18 | ) { 19 | init { 20 | require(length.isSpecified && length.isFinite) { 21 | "Invalid arrow length: must be finite and specified" 22 | } 23 | require(angle in 0f..90f) { "Invalid arrow angle: must be in [0..180]" } 24 | } 25 | 26 | internal fun projectionOnDimensionLine(strokeWidth: Dp): Dp = 27 | cos(toRadians(angle.toDouble())) * (length + strokeWidth) 28 | 29 | internal fun projectionOnExtendingLine(strokeWidth: Dp): Dp = 30 | sin(toRadians(angle.toDouble())) * (length + strokeWidth) 31 | 32 | override fun equals(other: Any?): Boolean { 33 | if (this === other) return true 34 | if (other == null || this::class != other::class) return false 35 | 36 | other as Arrow 37 | 38 | if (length != other.length) return false 39 | if (angle.compareTo(other.angle) != 0) return false 40 | if (roundCap != other.roundCap) return false 41 | 42 | return true 43 | } 44 | 45 | override fun hashCode(): Int { 46 | var result = length.hashCode() 47 | result = 31 * result + angle.hashCode() 48 | result = 31 * result + roundCap.hashCode() 49 | return result 50 | } 51 | } 52 | 53 | private fun toRadians(angle: Double) = angle * PI / 180.0 -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/kotlin/com/popovanton0/blueprint/BlueprintClass.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import com.popovanton0.blueprint.dsl.Anchor 4 | import com.popovanton0.blueprint.dsl.Arrow 5 | import com.popovanton0.blueprint.dsl.Blueprint 6 | import com.popovanton0.blueprint.dsl.BlueprintBuilderScope 7 | import com.popovanton0.blueprint.dsl.Dimension 8 | import com.popovanton0.blueprint.dsl.HorizontalGroup 9 | import com.popovanton0.blueprint.dsl.MeasureUnit 10 | import com.popovanton0.blueprint.dsl.Position 11 | import com.popovanton0.blueprint.dsl.SizeUnits 12 | import com.popovanton0.blueprint.dsl.VerticalGroup 13 | import nl.jqno.equalsverifier.EqualsVerifier 14 | import org.junit.Assert.assertEquals 15 | import org.junit.Assert.assertNotEquals 16 | import org.junit.Test 17 | 18 | internal class BlueprintClass { 19 | @Test 20 | fun `basic equals-hashcode check`() { 21 | val original = BlueprintBuilderScope().apply { 22 | widths { group { "aaa" lineTo "bbb" } } 23 | heights { group { "bbb" lineTo "ccc" } } 24 | }.toBlueprint() 25 | val equal = BlueprintBuilderScope().apply { 26 | widths { group { "aaa" lineTo "bbb" } } 27 | heights { group { "bbb" lineTo "ccc" } } 28 | }.toBlueprint() 29 | val modified = BlueprintBuilderScope().apply { 30 | widths { group { "aaa" lineTo "bbb" } } 31 | heights { group { "bbb" lineTo "another non equal value" } } 32 | }.toBlueprint() 33 | 34 | assertEquals(original, equal) 35 | assertNotEquals(original, modified) 36 | } 37 | 38 | @Test 39 | fun `advanced equals-hashcode verification`() { 40 | EqualsVerifier.forClass(Blueprint::class.java).withIgnoredFields("groupCollection").verify() 41 | EqualsVerifier.forClasses( 42 | HorizontalGroup::class.java, 43 | VerticalGroup::class.java, 44 | Dimension::class.java, 45 | Position::class.java, 46 | Position.Horizontal::class.java, 47 | Position.Vertical::class.java, 48 | MeasureUnit::class.java, 49 | SizeUnits::class.java, 50 | Anchor::class.java, 51 | Arrow::class.java, 52 | ).verify() 53 | } 54 | } -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/BlueprintBuilderScope.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | @BlueprintDslMarker 4 | public class BlueprintBuilderScope internal constructor() { 5 | private val horizontalTopGroups = mutableListOf() 6 | private val horizontalBottomGroups = mutableListOf() 7 | private val verticalLeftGroups = mutableListOf() 8 | private val verticalRightGroups = mutableListOf() 9 | 10 | /** 11 | * Groups in [block] are measuring a horizontal dimension — width. 12 | * 13 | * Lines in these groups will be placed at the [Position.Vertical.Top] or 14 | * [Position.Vertical.Bottom] of the composable. 15 | * 16 | * The placing order of groups is the following: 17 | * *first called -> placed closer to the composable*. 18 | * 19 | * In other words: going out from the center, like in an onion. 20 | */ 21 | public fun widths(block: HorizontalScope.() -> Unit) { 22 | val scope = HorizontalScope() 23 | scope.block() 24 | horizontalTopGroups.clear() 25 | horizontalBottomGroups.clear() 26 | horizontalTopGroups.addAll(scope.topGroups) 27 | horizontalBottomGroups.addAll(scope.bottomGroups) 28 | } 29 | 30 | /** 31 | * Groups in [block] are measuring a vertical dimension — height. 32 | * 33 | * Lines in these groups will be placed at the [Position.Horizontal.Start] or 34 | * [Position.Horizontal.End] of the composable. 35 | * 36 | * The placing order of groups is the following: 37 | * *first called -> placed closer to the composable*. 38 | * 39 | * In other words: going out from the center, like in an onion. 40 | */ 41 | public fun heights(block: VerticalScope.() -> Unit) { 42 | val scope = VerticalScope() 43 | scope.block() 44 | verticalLeftGroups.clear() 45 | verticalRightGroups.clear() 46 | verticalLeftGroups.addAll(scope.leftGroups) 47 | verticalRightGroups.addAll(scope.rightGroups) 48 | } 49 | 50 | internal fun toBlueprint(): Blueprint = Blueprint( 51 | horizontalTopGroups.toList(), 52 | horizontalBottomGroups.toList(), 53 | verticalLeftGroups.toList(), 54 | verticalRightGroups.toList(), 55 | ) 56 | } -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/VerticalScope.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 4 | import com.popovanton0.blueprint.blueprintId 5 | import com.popovanton0.blueprint.dsl.Position.Horizontal.Companion.End 6 | import com.popovanton0.blueprint.dsl.Position.Horizontal.Companion.Start 7 | 8 | @BlueprintDslMarker 9 | public class VerticalScope internal constructor() { 10 | internal val leftGroups = mutableListOf() 11 | internal val rightGroups = mutableListOf() 12 | 13 | /** 14 | * Defines a group of dimension lines. They will be drawn at the same depth level. 15 | * 16 | * To produce a pretty blueprint, try to place in one group only 17 | * non-overlapping dimension lines. Place the overlapping ones in different groups. 18 | */ 19 | public fun group( 20 | position: Position.Horizontal = Start, 21 | block: VerticalGroupScope.() -> Unit 22 | ) { 23 | val scope = VerticalGroupScope() 24 | scope.block() 25 | if (scope.dimensions.isEmpty()) return 26 | val group = VerticalGroup(scope.dimensions, position) 27 | when (position) { 28 | Start -> leftGroups += group 29 | End -> rightGroups += group 30 | } 31 | } 32 | } 33 | 34 | @BlueprintDslMarker 35 | public class VerticalGroupScope internal constructor() : GroupScope() { 36 | public val String.top: Anchor get() = Anchor(this, alignment = 0f) 37 | public val String.center: Anchor get() = Anchor(this, alignment = 0.5f) 38 | public val String.bottom: Anchor get() = Anchor(this, alignment = 1f) 39 | 40 | /** 41 | * Defines a dimension line from the [top] of [this] to the [bottom] of the [other]. 42 | * To define a line from different anchor points, use these 43 | * extensions: [top], [bottom], [center]. 44 | * 45 | * [this] and [other] are ids from [blueprintId] modifier. 46 | * 47 | * Length on the resulting dimension line is in [MeasureUnit.Dp]s. 48 | */ 49 | public infix fun String.lineTo(other: String): Unit = top lineTo other.bottom 50 | 51 | /** 52 | * Length on the resulting dimension line is in [MeasureUnit.Sp]s. 53 | * 54 | * @see lineTo 55 | */ 56 | @ExperimentalBlueprintApi 57 | public infix fun String.spLineTo(other: String): Unit = top spLineTo other.bottom 58 | } -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/dsl/HorizontalScope.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.dsl 2 | 3 | import com.popovanton0.blueprint.ExperimentalBlueprintApi 4 | import com.popovanton0.blueprint.blueprintId 5 | import com.popovanton0.blueprint.dsl.Position.Vertical.Companion.Bottom 6 | import com.popovanton0.blueprint.dsl.Position.Vertical.Companion.Top 7 | 8 | @BlueprintDslMarker 9 | public class HorizontalScope internal constructor() { 10 | internal val topGroups = mutableListOf() 11 | internal val bottomGroups = mutableListOf() 12 | 13 | /** 14 | * Defines a group of dimension lines. They will be drawn at the same *depth level*. 15 | * 16 | * To produce a pretty blueprint, try to place in one group only 17 | * non-overlapping dimension lines. Place the overlapping ones in different groups. 18 | */ 19 | public fun group( 20 | position: Position.Vertical = Bottom, 21 | block: HorizontalGroupScope.() -> Unit 22 | ) { 23 | val scope = HorizontalGroupScope() 24 | scope.block() 25 | if (scope.dimensions.isEmpty()) return 26 | val group = HorizontalGroup(scope.dimensions, position) 27 | when (position) { 28 | Top -> topGroups += group 29 | Bottom -> bottomGroups += group 30 | } 31 | } 32 | } 33 | 34 | @BlueprintDslMarker 35 | public class HorizontalGroupScope internal constructor() : GroupScope() { 36 | public val String.left: Anchor get() = Anchor(this, alignment = 0f) 37 | public val String.center: Anchor get() = Anchor(this, alignment = 0.5f) 38 | public val String.right: Anchor get() = Anchor(this, alignment = 1f) 39 | 40 | /** 41 | * Defines a dimension line from the [left] of [this] to the [right] of the [other]. 42 | * To define a line from different anchor points, use these 43 | * extensions: [left], [center], [right]. 44 | * 45 | * [this] and [other] are ids from [blueprintId] modifier. 46 | * 47 | * Length on the resulting dimension line is in [MeasureUnit.Dp]s. 48 | */ 49 | public infix fun String.lineTo(other: String): Unit = left lineTo other.right 50 | 51 | /** 52 | * Length on the resulting dimension line is in [MeasureUnit.Sp]s. 53 | * 54 | * @see lineTo 55 | */ 56 | @ExperimentalBlueprintApi 57 | public infix fun String.spLineTo(other: String): Unit = left spLineTo other.right 58 | } -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 41 | -------------------------------------------------------------------------------- /blueprint-no-op/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 4 | 5 | 6 | plugins { 7 | alias(libs.plugins.kotlin.multiplatform) 8 | alias(libs.plugins.kotlin.plugin.compose) 9 | alias(libs.plugins.android.library) 10 | alias(libs.plugins.paparazzi) 11 | alias(libs.plugins.binaryCompatibility) 12 | alias(libs.plugins.compose) 13 | id("maven-publish") 14 | } 15 | 16 | kotlin { 17 | androidTarget { 18 | publishLibraryVariants("release") 19 | compilations.all { 20 | compileTaskProvider.configure { 21 | compilerOptions { 22 | jvmTarget.set(JvmTarget.JVM_17) 23 | } 24 | } 25 | } 26 | } 27 | jvm("desktop") 28 | listOf( 29 | iosX64(), 30 | iosArm64(), 31 | iosSimulatorArm64() 32 | ).forEach { iosTarget -> 33 | iosTarget.binaries.framework { 34 | baseName = "blueprint-no-op" 35 | isStatic = true 36 | } 37 | } 38 | 39 | applyDefaultHierarchyTemplate() 40 | 41 | sourceSets { 42 | all { 43 | languageSettings { 44 | optIn("com.popovanton0.blueprint.ExperimentalBlueprintApi") 45 | } 46 | } 47 | 48 | commonMain { 49 | dependencies { 50 | implementation(compose.runtime) 51 | implementation(compose.foundation) 52 | implementation(libs.androidx.annotation) 53 | } 54 | } 55 | 56 | androidNativeTest { 57 | 58 | } 59 | } 60 | } 61 | 62 | android { 63 | namespace = "com.popovanton0.blueprint" 64 | compileSdk = libs.versions.compileSdk.get().toInt() 65 | sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") 66 | 67 | defaultConfig { 68 | minSdk = 21 69 | 70 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 71 | consumerProguardFiles("consumer-rules.pro") 72 | } 73 | 74 | buildTypes { 75 | release { 76 | isMinifyEnabled = false 77 | proguardFiles("proguard-android-optimize.txt", "proguard-rules.pro") 78 | } 79 | } 80 | compileOptions { 81 | sourceCompatibility = JavaVersion.VERSION_17 82 | targetCompatibility = JavaVersion.VERSION_17 83 | } 84 | kotlin { 85 | explicitApi() 86 | } 87 | } 88 | 89 | tasks.named("assemble") { 90 | dependsOn("check") 91 | } 92 | 93 | group = "com.popovanton0.blueprint" 94 | version = libs.versions.blueprint.get() 95 | 96 | publishing { 97 | } 98 | -------------------------------------------------------------------------------- /.idea/androidTestResultsUserPreferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 73 | 74 | -------------------------------------------------------------------------------- /blueprint/src/commonMain/kotlin/com/popovanton0/blueprint/BlueprintId.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.compose.runtime.Stable 4 | import androidx.compose.ui.Modifier 5 | import androidx.compose.ui.layout.LayoutCoordinates 6 | import androidx.compose.ui.modifier.ModifierLocalModifierNode 7 | import androidx.compose.ui.node.GlobalPositionAwareModifierNode 8 | import androidx.compose.ui.node.ModifierNodeElement 9 | import androidx.compose.ui.platform.InspectorInfo 10 | import com.popovanton0.blueprint.dsl.SizeUnits 11 | 12 | /** 13 | * This modifier marks a UI-composable with an [id] that can be used in blueprintBuilder to define 14 | * dimension lines between this composable and others. 15 | * 16 | * [id] must be **unique** for all children of the [Blueprint] composable. 17 | * 18 | * @param id *unique* identifier for this composable. Use it in 19 | * blueprintBuilder to define dimension lines. 20 | * @param sizeUnits if non-null, size label is drawn over the composable. 21 | * 22 | * @see blueprintEnabled 23 | */ 24 | @Stable 25 | public fun Modifier.blueprintId( 26 | id: String, 27 | sizeUnits: SizeUnits? = null 28 | ): Modifier = if (blueprintEnabled) { 29 | this then BlueprintMarkerElement( 30 | id = id, 31 | sizeUnits = sizeUnits, 32 | inspectorInfo = { 33 | name = "blueprintId" 34 | properties["id"] = id 35 | properties["sizeUnits"] = sizeUnits 36 | } 37 | ) 38 | } else { 39 | this 40 | } 41 | 42 | private class BlueprintMarkerElement( 43 | val id: String, 44 | val sizeUnits: SizeUnits?, 45 | val inspectorInfo: InspectorInfo.() -> Unit, 46 | ) : ModifierNodeElement() { 47 | override fun create(): BlueprintMarkerNode = BlueprintMarkerNode(id, sizeUnits) 48 | 49 | override fun update(node: BlueprintMarkerNode) { 50 | node.id = id 51 | node.sizeUnits = sizeUnits 52 | } 53 | 54 | override fun equals(other: Any?): Boolean { 55 | val otherModifierElement = other as? BlueprintMarkerElement ?: return false 56 | return id == otherModifierElement.id && sizeUnits == otherModifierElement.sizeUnits 57 | } 58 | 59 | override fun hashCode(): Int { 60 | var result = id.hashCode() 61 | result = 31 * result + (sizeUnits?.hashCode() ?: 0) 62 | return result 63 | } 64 | 65 | override fun InspectorInfo.inspectableProperties() { 66 | inspectorInfo() 67 | } 68 | } 69 | 70 | private class BlueprintMarkerNode( 71 | var id: String, 72 | var sizeUnits: SizeUnits?, 73 | ) : Modifier.Node(), ModifierLocalModifierNode, GlobalPositionAwareModifierNode { 74 | 75 | override fun onGloballyPositioned(coordinates: LayoutCoordinates) { 76 | val markers = ModifierLocalBlueprintMarkers.current ?: return 77 | markers.remove(id) 78 | if (coordinates.isAttached) markers[id] = BlueprintMarker(coordinates, sizeUnits) 79 | } 80 | } -------------------------------------------------------------------------------- /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 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /blueprint/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 4 | 5 | 6 | plugins { 7 | alias(libs.plugins.kotlin.multiplatform) 8 | alias(libs.plugins.kotlin.plugin.compose) 9 | alias(libs.plugins.compose) 10 | alias(libs.plugins.android.library) 11 | alias(libs.plugins.paparazzi) 12 | alias(libs.plugins.binaryCompatibility) 13 | id("maven-publish") 14 | } 15 | 16 | kotlin { 17 | androidTarget { 18 | publishLibraryVariants("release") 19 | compilations.all { 20 | compileTaskProvider.configure { 21 | compilerOptions { 22 | jvmTarget.set(JvmTarget.JVM_17) 23 | } 24 | } 25 | } 26 | } 27 | jvm("desktop") 28 | listOf( 29 | iosX64(), 30 | iosArm64(), 31 | iosSimulatorArm64() 32 | ).forEach { iosTarget -> 33 | iosTarget.binaries.framework { 34 | baseName = "blueprint" 35 | isStatic = true 36 | } 37 | } 38 | 39 | applyDefaultHierarchyTemplate() 40 | 41 | sourceSets { 42 | all { 43 | languageSettings { 44 | optIn("com.popovanton0.blueprint.ExperimentalBlueprintApi") 45 | } 46 | } 47 | commonMain { 48 | dependencies { 49 | implementation(compose.runtime) 50 | implementation(compose.foundation) 51 | implementation(libs.androidx.annotation) 52 | } 53 | } 54 | commonTest { 55 | 56 | } 57 | androidUnitTest { 58 | dependencies { 59 | implementation(libs.junit) 60 | implementation(compose.material3) 61 | implementation(libs.testParameterInjector) 62 | implementation(libs.equalsverifier) 63 | implementation(libs.androidx.testJunit) 64 | implementation(libs.androidx.compose.ui.testJunit) 65 | implementation(libs.androidx.compose.ui.tooling) 66 | } 67 | } 68 | androidInstrumentedTest { 69 | 70 | } 71 | } 72 | } 73 | 74 | android { 75 | namespace = "com.popovanton0.blueprint" 76 | compileSdk = libs.versions.compileSdk.get().toInt() 77 | 78 | defaultConfig { 79 | minSdk = 21 80 | 81 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 82 | consumerProguardFiles("consumer-rules.pro") 83 | } 84 | 85 | buildTypes { 86 | release { 87 | isMinifyEnabled = false 88 | proguardFiles("proguard-android-optimize.txt", "proguard-rules.pro") 89 | } 90 | } 91 | compileOptions { 92 | sourceCompatibility = JavaVersion.VERSION_17 93 | targetCompatibility = JavaVersion.VERSION_17 94 | } 95 | kotlin { 96 | explicitApi() 97 | } 98 | } 99 | 100 | tasks.named("assemble") { 101 | dependsOn("check") 102 | } 103 | 104 | group = "com.popovanton0.blueprint" 105 | version = libs.versions.blueprint.get() 106 | 107 | publishing { 108 | } 109 | -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 4 | 5 | plugins { 6 | alias(libs.plugins.kotlin.multiplatform) 7 | alias(libs.plugins.kotlin.plugin.compose) 8 | alias(libs.plugins.android.application) 9 | alias(libs.plugins.compose) 10 | } 11 | 12 | kotlin { 13 | androidTarget { 14 | compilations.all { 15 | compileTaskProvider.configure { 16 | compilerOptions { 17 | jvmTarget.set(JvmTarget.JVM_17) 18 | } 19 | } 20 | } 21 | } 22 | jvm("desktop") 23 | listOf( 24 | iosX64(), 25 | iosArm64(), 26 | iosSimulatorArm64() 27 | ).forEach { 28 | it.binaries.framework { 29 | baseName = "blueprintDemoCompose" 30 | isStatic = true 31 | } 32 | } 33 | 34 | applyDefaultHierarchyTemplate() 35 | 36 | sourceSets { 37 | all { 38 | languageSettings { 39 | optIn("androidx.compose.ui.ExperimentalComposeUiApi") 40 | optIn("com.popovanton0.blueprint.ExperimentalBlueprintApi") 41 | } 42 | } 43 | 44 | commonMain.dependencies { 45 | implementation(project(":blueprint")) 46 | implementation(compose.foundation) 47 | implementation(compose.material3) 48 | implementation(compose.materialIconsExtended) 49 | } 50 | 51 | androidMain.dependencies { 52 | implementation(compose.preview) 53 | implementation(compose.uiTooling) 54 | implementation(compose.uiUtil) 55 | 56 | implementation(libs.androidx.coreKtx) 57 | implementation(libs.androidx.lifecycleRuntimeKtx) 58 | implementation(libs.androidx.activityCompose) 59 | // note, these should have been debugImplementations, 60 | // but that does not seem to work 61 | implementation(libs.androidx.compose.ui.tooling) 62 | implementation(libs.androidx.compose.ui.testManifest) 63 | } 64 | 65 | val desktopMain by getting 66 | desktopMain.dependencies { 67 | implementation(compose.desktop.currentOs) 68 | implementation(compose.preview) 69 | implementation(compose.uiTooling) 70 | implementation(compose.uiUtil) 71 | } 72 | } 73 | 74 | } 75 | 76 | android { 77 | namespace = "com.popovanton0.blueprint.app" 78 | compileSdk = libs.versions.compileSdk.get().toInt() 79 | 80 | defaultConfig { 81 | applicationId = "com.popovanton0.blueprint.app" 82 | minSdk = 21 83 | targetSdk = libs.versions.compileSdk.get().toInt() 84 | versionCode = 1 85 | versionName = "1.0" 86 | 87 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 88 | vectorDrawables.useSupportLibrary = true 89 | } 90 | 91 | buildTypes { 92 | release { 93 | isMinifyEnabled = true 94 | proguardFiles("proguard-android-optimize.txt", "proguard-rules.pro") 95 | } 96 | } 97 | compileOptions { 98 | sourceCompatibility = JavaVersion.VERSION_17 99 | targetCompatibility = JavaVersion.VERSION_17 100 | } 101 | 102 | packagingOptions.resources.excludes += "/META-INF/{AL2.0,LGPL2.1}" 103 | } 104 | 105 | compose.desktop { 106 | application { 107 | mainClass = "com.popovanton0.blueprint.app.MainKt" 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 116 | 117 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | blueprint = "2.0.0-alpha01" 3 | compileSdk = "35" 4 | gradlePlugin = "8.7.3" 5 | kotlin = "2.1.0" 6 | compose = "1.7.3" 7 | composeCompiler = "1.5.8" 8 | paparazzi = "1.3.2" 9 | junit = "4.13.2" 10 | testParameterInjector = "1.12" 11 | equalsverifier = "3.14.2" 12 | androidxTestJunit = "1.1.5" 13 | androidxCoreKtx = "1.12.0" 14 | lifecycleRuntimeKtx = "2.7.0" 15 | androidxActivityCompose = "1.8.2" 16 | androidx-benchmark = "1.2.3" 17 | test-runner = "1.5.2" 18 | test-rules = "1.5.0" 19 | benchmark-junit4 = "1.2.3" 20 | uiAndroidStubs = "1.6.0" 21 | androidxAnnotation = "1.9.1" 22 | composeMaterial = "1.3.2" 23 | binaryCompatibility = "0.17.0" 24 | composeIcons = "1.7.8" 25 | composeAndroidx = "1.8.1" 26 | 27 | [libraries] 28 | androidx-coreKtx = { module = "androidx.core:core-ktx", version.ref = "androidxCoreKtx" } 29 | androidx-lifecycleRuntimeKtx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } 30 | androidx-activityCompose = { module = "androidx.activity:activity-compose", version.ref = "androidxActivityCompose" } 31 | androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidxAnnotation" } 32 | 33 | androidx-compose-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "composeIcons" } 34 | androidx-compose-material = { module = "androidx.compose.material3:material3", version.ref = "composeMaterial" } 35 | androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "composeAndroidx" } 36 | androidx-compose-ui = { module = "androidx.compose.ui:ui", version.ref = "composeAndroidx" } 37 | androidx-compose-ui-util = { module = "androidx.compose.ui:ui-util", version.ref = "composeAndroidx" } 38 | androidx-compose-ui-testManifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "composeAndroidx" } 39 | androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "composeAndroidx" } 40 | androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "composeAndroidx" } 41 | androidx-compose-ui-testJunit = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "composeAndroidx" } 42 | 43 | androidx-ui-android-stubs = { group = "androidx.compose.ui", name = "ui-android-stubs", version.ref = "uiAndroidStubs" } 44 | androidx-runner = { group = "androidx.test", name = "runner", version.ref = "test-runner" } 45 | androidx-rules = { group = "androidx.test", name = "rules", version.ref = "test-rules" } 46 | androidx-testJunit = { module = "androidx.test.ext:junit", version.ref = "androidxTestJunit" } 47 | androidx-benchmark-junit4 = { group = "androidx.benchmark", name = "benchmark-junit4", version.ref = "benchmark-junit4" } 48 | junit = { module = "junit:junit", version.ref = "junit" } 49 | equalsverifier = { module = "nl.jqno.equalsverifier:equalsverifier", version.ref = "equalsverifier" } 50 | testParameterInjector = { module = "com.google.testparameterinjector:test-parameter-injector", version.ref = "testParameterInjector" } 51 | 52 | 53 | [plugins] 54 | android-application = { id = "com.android.application", version.ref = "gradlePlugin" } 55 | android-library = { id = "com.android.library", version.ref = "gradlePlugin" } 56 | kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } 57 | paparazzi = { id = "app.cash.paparazzi", version.ref = "paparazzi" } 58 | androidx-benchmark = { id = "androidx.benchmark", version.ref = "androidx-benchmark" } 59 | binaryCompatibility = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binaryCompatibility" } 60 | 61 | kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } 62 | kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } 63 | kotlin-plugin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } 64 | 65 | compose = { id = "org.jetbrains.compose", version.ref = "compose" } 66 | 67 | [bundles] 68 | 69 | -------------------------------------------------------------------------------- /app/src/androidMain/kotlin/com/popovanton0/blueprint/app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint.app 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.foundation.background 7 | import androidx.compose.foundation.isSystemInDarkTheme 8 | import androidx.compose.foundation.layout.Arrangement 9 | import androidx.compose.foundation.layout.Box 10 | import androidx.compose.foundation.layout.Row 11 | import androidx.compose.foundation.layout.fillMaxSize 12 | import androidx.compose.foundation.layout.padding 13 | import androidx.compose.foundation.layout.size 14 | import androidx.compose.material.icons.Icons 15 | import androidx.compose.material.icons.filled.Home 16 | import androidx.compose.material3.Icon 17 | import androidx.compose.material3.MaterialTheme 18 | import androidx.compose.material3.Surface 19 | import androidx.compose.material3.darkColorScheme 20 | import androidx.compose.material3.lightColorScheme 21 | import androidx.compose.runtime.Composable 22 | import androidx.compose.runtime.LaunchedEffect 23 | import androidx.compose.runtime.getValue 24 | import androidx.compose.runtime.mutableFloatStateOf 25 | import androidx.compose.runtime.remember 26 | import androidx.compose.runtime.setValue 27 | import androidx.compose.ui.Modifier 28 | import androidx.compose.ui.graphics.Color 29 | import androidx.compose.ui.graphics.vector.rememberVectorPainter 30 | import androidx.compose.ui.unit.dp 31 | import com.popovanton0.blueprint.Blueprint 32 | import com.popovanton0.blueprint.blueprintId 33 | import com.popovanton0.blueprint.dsl.Position 34 | import kotlinx.coroutines.delay 35 | 36 | class MainActivity : ComponentActivity() { 37 | override fun onCreate(savedInstanceState: Bundle?) { 38 | super.onCreate(savedInstanceState) 39 | setContent { 40 | MaterialTheme(if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()) { 41 | // A surface container using the 'background' color from the theme 42 | Surface( 43 | modifier = Modifier.fillMaxSize(), 44 | color = MaterialTheme.colorScheme.background 45 | ) { 46 | Lab() 47 | return@Surface 48 | val case = remember { RecreateLayersTestCase() } 49 | case.Content() 50 | LaunchedEffect(Unit) { 51 | if (false)repeat(1000000) { 52 | case.toggleState() 53 | delay(25) 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | 62 | private class RecreateLayersTestCase { 63 | 64 | private val range = 1f..50f 65 | private var size by mutableFloatStateOf(range.start) 66 | private var increase = true 67 | private val step = 0.5f 68 | 69 | fun toggleState() { 70 | if (size >= range.endInclusive) increase = false 71 | else if (size <= range.start) increase = true 72 | if (increase) size += step else size -= step 73 | println("size = $size") 74 | } 75 | 76 | @Composable 77 | fun Content() = Box { 78 | Blueprint( 79 | modifier = Modifier.padding(12.dp), 80 | // fontColor = Color.Blue, 81 | // fontSize = 20.sp, 82 | blueprintBuilder = { 83 | widths { 84 | group { 85 | "icon" lineTo "icon" 86 | "box" lineTo "box" 87 | } 88 | group { "icon" lineTo "text" } 89 | group(Position.Vertical.Top) { "icon".center lineTo "box".center } 90 | group(Position.Vertical.Top) { "icon".center lineTo "box".center } 91 | } 92 | if (true) heights { 93 | group { "icon" lineTo "icon" } 94 | group { "icon" lineTo "icon" } 95 | group(Position.Horizontal.End) { "box" lineTo "box" } 96 | group(Position.Horizontal.End) { "box" lineTo "box" } 97 | } 98 | } 99 | ) { 100 | Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { 101 | if (size < 25f) Icon( 102 | modifier = Modifier 103 | .size(20.dp) 104 | .blueprintId("icon"), 105 | painter = rememberVectorPainter(Icons.Default.Home), 106 | contentDescription = null 107 | ) 108 | Box( 109 | modifier = Modifier 110 | .size(size.dp) 111 | .background(Color.Blue) 112 | .blueprintId("box"), 113 | ) 114 | } 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/kotlin/com/popovanton0/blueprint/Dsl.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import com.google.testing.junit.testparameterinjector.TestParameter 4 | import com.google.testing.junit.testparameterinjector.TestParameterInjector 5 | import com.popovanton0.blueprint.dsl.Anchor 6 | import com.popovanton0.blueprint.dsl.BlueprintBuilderScope 7 | import com.popovanton0.blueprint.dsl.Dimension 8 | import com.popovanton0.blueprint.dsl.MeasureUnit 9 | import com.popovanton0.blueprint.dsl.Position.Horizontal.Companion.End 10 | import com.popovanton0.blueprint.dsl.Position.Horizontal.Companion.Start 11 | import com.popovanton0.blueprint.dsl.Position.Vertical.Companion.Bottom 12 | import com.popovanton0.blueprint.dsl.Position.Vertical.Companion.Top 13 | import org.junit.Assert.assertEquals 14 | import org.junit.Assert.assertTrue 15 | import org.junit.Test 16 | import org.junit.runner.RunWith 17 | 18 | @RunWith(TestParameterInjector::class) 19 | internal class Dsl { 20 | 21 | @Suppress("JUnitMalformedDeclaration") 22 | @Test 23 | fun `empty dsl produces empty blueprint`( 24 | @TestParameter("0", "1", "2") horizontalBlockCalls: Int, 25 | @TestParameter("0", "1", "2") verticalBlockCalls: Int, 26 | @TestParameter("0", "1", "2") horizontalGroupBlockCalls: Int, 27 | @TestParameter("0", "1", "2") verticalGroupBlockCalls: Int, 28 | ) { 29 | println("Blueprint") 30 | val actual = BlueprintBuilder { 31 | repeat(horizontalBlockCalls) { 32 | widths { 33 | println(" horizontal") 34 | repeat(horizontalGroupBlockCalls) { 35 | group { } 36 | println(" group") 37 | } 38 | } 39 | } 40 | repeat(verticalBlockCalls) { 41 | heights { 42 | println(" vertical") 43 | repeat(verticalGroupBlockCalls) { 44 | group { } 45 | println(" group") 46 | } 47 | } 48 | } 49 | } 50 | println("=======================\n") 51 | assertTrue(actual.groupCollection.flatMap { it }.isEmpty()) 52 | } 53 | 54 | @Test 55 | fun `typical dsl usage`() { 56 | val actual = BlueprintBuilder { 57 | widths { 58 | group { 59 | "one" lineTo "two" 60 | "two".center lineTo "three".right 61 | } 62 | group(Top) { 63 | "Apple" lineTo "Banana" 64 | "Mango".center lineTo "Avocado".right 65 | } 66 | } 67 | heights { 68 | group { 69 | "Car" lineTo "Bike" 70 | "Plane".center lineTo "Helicopter".bottom 71 | } 72 | group(End) { 73 | "Sock" lineTo "Blouse" 74 | "Shirt".center lineTo "Bow-tie".bottom 75 | } 76 | } 77 | } 78 | 79 | assertEquals(Bottom, actual.horizontalBottomGroups.single().position) 80 | assertEquals(Top, actual.horizontalTopGroups.single().position) 81 | assertEquals(Start, actual.verticalLeftGroups.single().position) 82 | assertEquals(End, actual.verticalRightGroups.single().position) 83 | 84 | assertEquals( 85 | Dimension(Anchor("one", 0f), Anchor("two", 1f), MeasureUnit.Dp), 86 | actual.horizontalBottomGroups.single().dimensions[0], 87 | ) 88 | assertEquals( 89 | Dimension(Anchor("Apple", 0f), Anchor("Banana", 1f), MeasureUnit.Dp), 90 | actual.horizontalTopGroups.single().dimensions[0], 91 | ) 92 | assertEquals( 93 | Dimension(Anchor("Car", 0f), Anchor("Bike", 1f), MeasureUnit.Dp), 94 | actual.verticalLeftGroups.single().dimensions[0], 95 | ) 96 | assertEquals( 97 | Dimension(Anchor("Sock", 0f), Anchor("Blouse", 1f), MeasureUnit.Dp), 98 | actual.verticalRightGroups.single().dimensions[0], 99 | ) 100 | 101 | // second dimension 102 | 103 | assertEquals( 104 | Dimension(Anchor("two", 0.5f), Anchor("three", 1f), MeasureUnit.Dp), 105 | actual.horizontalBottomGroups.single().dimensions[1], 106 | ) 107 | assertEquals( 108 | Dimension(Anchor("Mango", 0.5f), Anchor("Avocado", 1f), MeasureUnit.Dp), 109 | actual.horizontalTopGroups.single().dimensions[1], 110 | ) 111 | assertEquals( 112 | Dimension(Anchor("Plane", 0.5f), Anchor("Helicopter", 1f), MeasureUnit.Dp), 113 | actual.verticalLeftGroups.single().dimensions[1], 114 | ) 115 | assertEquals( 116 | Dimension(Anchor("Shirt", 0.5f), Anchor("Bow-tie", 1f), MeasureUnit.Dp), 117 | actual.verticalRightGroups.single().dimensions[1], 118 | ) 119 | } 120 | 121 | @Suppress("TestFunctionName") 122 | private fun BlueprintBuilder(block: BlueprintBuilderScope.() -> Unit) = 123 | BlueprintBuilderScope().apply(block).toBlueprint() 124 | } 125 | -------------------------------------------------------------------------------- /app/src/androidMain/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /.idea/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /blueprint/api/blueprint.api: -------------------------------------------------------------------------------- 1 | public final class com/popovanton0/blueprint/BlueprintIdKt { 2 | public static final fun blueprintId (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;)Landroidx/compose/ui/Modifier; 3 | public static synthetic fun blueprintId$default (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; 4 | } 5 | 6 | public final class com/popovanton0/blueprint/BlueprintKt { 7 | public static final fun Blueprint-clabC8w (Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/BorderStroke;JJLcom/popovanton0/blueprint/dsl/Arrow;IZZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V 8 | public static final fun getBlueprintEnabled ()Z 9 | public static final fun setBlueprintEnabled (Z)V 10 | } 11 | 12 | public abstract interface annotation class com/popovanton0/blueprint/ExperimentalBlueprintApi : java/lang/annotation/Annotation { 13 | } 14 | 15 | public final class com/popovanton0/blueprint/dsl/Anchor { 16 | public static final field $stable I 17 | public fun equals (Ljava/lang/Object;)Z 18 | public fun hashCode ()I 19 | } 20 | 21 | public final class com/popovanton0/blueprint/dsl/Arrow { 22 | public static final field $stable I 23 | public synthetic fun (FFZILkotlin/jvm/internal/DefaultConstructorMarker;)V 24 | public synthetic fun (FFZLkotlin/jvm/internal/DefaultConstructorMarker;)V 25 | public fun equals (Ljava/lang/Object;)Z 26 | public final fun getAngle ()F 27 | public final fun getLength-D9Ej5fM ()F 28 | public final fun getRoundCap ()Z 29 | public fun hashCode ()I 30 | } 31 | 32 | public final class com/popovanton0/blueprint/dsl/BlueprintBuilderScope { 33 | public static final field $stable I 34 | public final fun heights (Lkotlin/jvm/functions/Function1;)V 35 | public final fun widths (Lkotlin/jvm/functions/Function1;)V 36 | } 37 | 38 | public abstract class com/popovanton0/blueprint/dsl/GroupScope { 39 | public static final field $stable I 40 | public final fun lineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 41 | public final fun spLineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 42 | } 43 | 44 | public final class com/popovanton0/blueprint/dsl/HorizontalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 45 | public static final field $stable I 46 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 47 | public final fun getLeft (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 48 | public final fun getRight (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 49 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 50 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 51 | } 52 | 53 | public final class com/popovanton0/blueprint/dsl/HorizontalScope { 54 | public static final field $stable I 55 | public final fun group-QjWXQlE (ILkotlin/jvm/functions/Function1;)V 56 | public static synthetic fun group-QjWXQlE$default (Lcom/popovanton0/blueprint/dsl/HorizontalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 57 | } 58 | 59 | public final class com/popovanton0/blueprint/dsl/MeasureUnit { 60 | public static final field Companion Lcom/popovanton0/blueprint/dsl/MeasureUnit$Companion; 61 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/MeasureUnit; 62 | public fun equals (Ljava/lang/Object;)Z 63 | public static fun equals-impl (ILjava/lang/Object;)Z 64 | public static final fun equals-impl0 (II)Z 65 | public fun hashCode ()I 66 | public static fun hashCode-impl (I)I 67 | public fun toString ()Ljava/lang/String; 68 | public static fun toString-impl (I)Ljava/lang/String; 69 | public final synthetic fun unbox-impl ()I 70 | } 71 | 72 | public final class com/popovanton0/blueprint/dsl/MeasureUnit$Companion { 73 | public final fun getDp-kfOZ-k0 ()I 74 | public final fun getSp-kfOZ-k0 ()I 75 | } 76 | 77 | public abstract interface class com/popovanton0/blueprint/dsl/Position { 78 | } 79 | 80 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal : com/popovanton0/blueprint/dsl/Position { 81 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Horizontal$Companion; 82 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Horizontal; 83 | public fun equals (Ljava/lang/Object;)Z 84 | public static fun equals-impl (ILjava/lang/Object;)Z 85 | public static final fun equals-impl0 (II)Z 86 | public fun hashCode ()I 87 | public static fun hashCode-impl (I)I 88 | public fun toString ()Ljava/lang/String; 89 | public static fun toString-impl (I)Ljava/lang/String; 90 | public final synthetic fun unbox-impl ()I 91 | } 92 | 93 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal$Companion { 94 | public final fun getEnd-o_BGRZA ()I 95 | public final fun getStart-o_BGRZA ()I 96 | } 97 | 98 | public final class com/popovanton0/blueprint/dsl/Position$Vertical : com/popovanton0/blueprint/dsl/Position { 99 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Vertical$Companion; 100 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Vertical; 101 | public fun equals (Ljava/lang/Object;)Z 102 | public static fun equals-impl (ILjava/lang/Object;)Z 103 | public static final fun equals-impl0 (II)Z 104 | public fun hashCode ()I 105 | public static fun hashCode-impl (I)I 106 | public fun toString ()Ljava/lang/String; 107 | public static fun toString-impl (I)Ljava/lang/String; 108 | public final synthetic fun unbox-impl ()I 109 | } 110 | 111 | public final class com/popovanton0/blueprint/dsl/Position$Vertical$Companion { 112 | public final fun getBottom-6W8Q2GU ()I 113 | public final fun getTop-6W8Q2GU ()I 114 | } 115 | 116 | public final class com/popovanton0/blueprint/dsl/SizeUnits { 117 | public static final field $stable I 118 | public static final field Companion Lcom/popovanton0/blueprint/dsl/SizeUnits$Companion; 119 | public synthetic fun (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V 120 | public synthetic fun (IILkotlin/jvm/internal/DefaultConstructorMarker;)V 121 | public fun equals (Ljava/lang/Object;)Z 122 | public final fun getXUnit-kfOZ-k0 ()I 123 | public final fun getYUnit-kfOZ-k0 ()I 124 | public fun hashCode ()I 125 | } 126 | 127 | public final class com/popovanton0/blueprint/dsl/SizeUnits$Companion { 128 | public final fun getDp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 129 | public final fun getSp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 130 | } 131 | 132 | public final class com/popovanton0/blueprint/dsl/VerticalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 133 | public static final field $stable I 134 | public final fun getBottom (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 135 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 136 | public final fun getTop (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 137 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 138 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 139 | } 140 | 141 | public final class com/popovanton0/blueprint/dsl/VerticalScope { 142 | public static final field $stable I 143 | public final fun group-a3hqG0I (ILkotlin/jvm/functions/Function1;)V 144 | public static synthetic fun group-a3hqG0I$default (Lcom/popovanton0/blueprint/dsl/VerticalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 145 | } 146 | 147 | -------------------------------------------------------------------------------- /blueprint/api/android/blueprint.api: -------------------------------------------------------------------------------- 1 | public final class com/popovanton0/blueprint/BlueprintIdKt { 2 | public static final fun blueprintId (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;)Landroidx/compose/ui/Modifier; 3 | public static synthetic fun blueprintId$default (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; 4 | } 5 | 6 | public final class com/popovanton0/blueprint/BlueprintKt { 7 | public static final fun Blueprint-clabC8w (Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/BorderStroke;JJLcom/popovanton0/blueprint/dsl/Arrow;IZZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V 8 | public static final fun getBlueprintEnabled ()Z 9 | public static final fun setBlueprintEnabled (Z)V 10 | } 11 | 12 | public abstract interface annotation class com/popovanton0/blueprint/ExperimentalBlueprintApi : java/lang/annotation/Annotation { 13 | } 14 | 15 | public final class com/popovanton0/blueprint/dsl/Anchor { 16 | public static final field $stable I 17 | public fun equals (Ljava/lang/Object;)Z 18 | public fun hashCode ()I 19 | } 20 | 21 | public final class com/popovanton0/blueprint/dsl/Arrow { 22 | public static final field $stable I 23 | public synthetic fun (FFZILkotlin/jvm/internal/DefaultConstructorMarker;)V 24 | public synthetic fun (FFZLkotlin/jvm/internal/DefaultConstructorMarker;)V 25 | public fun equals (Ljava/lang/Object;)Z 26 | public final fun getAngle ()F 27 | public final fun getLength-D9Ej5fM ()F 28 | public final fun getRoundCap ()Z 29 | public fun hashCode ()I 30 | } 31 | 32 | public final class com/popovanton0/blueprint/dsl/BlueprintBuilderScope { 33 | public static final field $stable I 34 | public final fun heights (Lkotlin/jvm/functions/Function1;)V 35 | public final fun widths (Lkotlin/jvm/functions/Function1;)V 36 | } 37 | 38 | public abstract class com/popovanton0/blueprint/dsl/GroupScope { 39 | public static final field $stable I 40 | public final fun lineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 41 | public final fun spLineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 42 | } 43 | 44 | public final class com/popovanton0/blueprint/dsl/HorizontalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 45 | public static final field $stable I 46 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 47 | public final fun getLeft (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 48 | public final fun getRight (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 49 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 50 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 51 | } 52 | 53 | public final class com/popovanton0/blueprint/dsl/HorizontalScope { 54 | public static final field $stable I 55 | public final fun group-QjWXQlE (ILkotlin/jvm/functions/Function1;)V 56 | public static synthetic fun group-QjWXQlE$default (Lcom/popovanton0/blueprint/dsl/HorizontalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 57 | } 58 | 59 | public final class com/popovanton0/blueprint/dsl/MeasureUnit { 60 | public static final field Companion Lcom/popovanton0/blueprint/dsl/MeasureUnit$Companion; 61 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/MeasureUnit; 62 | public fun equals (Ljava/lang/Object;)Z 63 | public static fun equals-impl (ILjava/lang/Object;)Z 64 | public static final fun equals-impl0 (II)Z 65 | public fun hashCode ()I 66 | public static fun hashCode-impl (I)I 67 | public fun toString ()Ljava/lang/String; 68 | public static fun toString-impl (I)Ljava/lang/String; 69 | public final synthetic fun unbox-impl ()I 70 | } 71 | 72 | public final class com/popovanton0/blueprint/dsl/MeasureUnit$Companion { 73 | public final fun getDp-kfOZ-k0 ()I 74 | public final fun getSp-kfOZ-k0 ()I 75 | } 76 | 77 | public abstract interface class com/popovanton0/blueprint/dsl/Position { 78 | } 79 | 80 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal : com/popovanton0/blueprint/dsl/Position { 81 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Horizontal$Companion; 82 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Horizontal; 83 | public fun equals (Ljava/lang/Object;)Z 84 | public static fun equals-impl (ILjava/lang/Object;)Z 85 | public static final fun equals-impl0 (II)Z 86 | public fun hashCode ()I 87 | public static fun hashCode-impl (I)I 88 | public fun toString ()Ljava/lang/String; 89 | public static fun toString-impl (I)Ljava/lang/String; 90 | public final synthetic fun unbox-impl ()I 91 | } 92 | 93 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal$Companion { 94 | public final fun getEnd-o_BGRZA ()I 95 | public final fun getStart-o_BGRZA ()I 96 | } 97 | 98 | public final class com/popovanton0/blueprint/dsl/Position$Vertical : com/popovanton0/blueprint/dsl/Position { 99 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Vertical$Companion; 100 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Vertical; 101 | public fun equals (Ljava/lang/Object;)Z 102 | public static fun equals-impl (ILjava/lang/Object;)Z 103 | public static final fun equals-impl0 (II)Z 104 | public fun hashCode ()I 105 | public static fun hashCode-impl (I)I 106 | public fun toString ()Ljava/lang/String; 107 | public static fun toString-impl (I)Ljava/lang/String; 108 | public final synthetic fun unbox-impl ()I 109 | } 110 | 111 | public final class com/popovanton0/blueprint/dsl/Position$Vertical$Companion { 112 | public final fun getBottom-6W8Q2GU ()I 113 | public final fun getTop-6W8Q2GU ()I 114 | } 115 | 116 | public final class com/popovanton0/blueprint/dsl/SizeUnits { 117 | public static final field $stable I 118 | public static final field Companion Lcom/popovanton0/blueprint/dsl/SizeUnits$Companion; 119 | public synthetic fun (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V 120 | public synthetic fun (IILkotlin/jvm/internal/DefaultConstructorMarker;)V 121 | public fun equals (Ljava/lang/Object;)Z 122 | public final fun getXUnit-kfOZ-k0 ()I 123 | public final fun getYUnit-kfOZ-k0 ()I 124 | public fun hashCode ()I 125 | } 126 | 127 | public final class com/popovanton0/blueprint/dsl/SizeUnits$Companion { 128 | public final fun getDp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 129 | public final fun getSp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 130 | } 131 | 132 | public final class com/popovanton0/blueprint/dsl/VerticalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 133 | public static final field $stable I 134 | public final fun getBottom (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 135 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 136 | public final fun getTop (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 137 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 138 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 139 | } 140 | 141 | public final class com/popovanton0/blueprint/dsl/VerticalScope { 142 | public static final field $stable I 143 | public final fun group-a3hqG0I (ILkotlin/jvm/functions/Function1;)V 144 | public static synthetic fun group-a3hqG0I$default (Lcom/popovanton0/blueprint/dsl/VerticalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 145 | } 146 | 147 | -------------------------------------------------------------------------------- /blueprint/api/desktop/blueprint.api: -------------------------------------------------------------------------------- 1 | public final class com/popovanton0/blueprint/BlueprintIdKt { 2 | public static final fun blueprintId (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;)Landroidx/compose/ui/Modifier; 3 | public static synthetic fun blueprintId$default (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; 4 | } 5 | 6 | public final class com/popovanton0/blueprint/BlueprintKt { 7 | public static final fun Blueprint-clabC8w (Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/BorderStroke;JJLcom/popovanton0/blueprint/dsl/Arrow;IZZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V 8 | public static final fun getBlueprintEnabled ()Z 9 | public static final fun setBlueprintEnabled (Z)V 10 | } 11 | 12 | public abstract interface annotation class com/popovanton0/blueprint/ExperimentalBlueprintApi : java/lang/annotation/Annotation { 13 | } 14 | 15 | public final class com/popovanton0/blueprint/dsl/Anchor { 16 | public static final field $stable I 17 | public fun equals (Ljava/lang/Object;)Z 18 | public fun hashCode ()I 19 | } 20 | 21 | public final class com/popovanton0/blueprint/dsl/Arrow { 22 | public static final field $stable I 23 | public synthetic fun (FFZILkotlin/jvm/internal/DefaultConstructorMarker;)V 24 | public synthetic fun (FFZLkotlin/jvm/internal/DefaultConstructorMarker;)V 25 | public fun equals (Ljava/lang/Object;)Z 26 | public final fun getAngle ()F 27 | public final fun getLength-D9Ej5fM ()F 28 | public final fun getRoundCap ()Z 29 | public fun hashCode ()I 30 | } 31 | 32 | public final class com/popovanton0/blueprint/dsl/BlueprintBuilderScope { 33 | public static final field $stable I 34 | public final fun heights (Lkotlin/jvm/functions/Function1;)V 35 | public final fun widths (Lkotlin/jvm/functions/Function1;)V 36 | } 37 | 38 | public abstract class com/popovanton0/blueprint/dsl/GroupScope { 39 | public static final field $stable I 40 | public final fun lineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 41 | public final fun spLineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 42 | } 43 | 44 | public final class com/popovanton0/blueprint/dsl/HorizontalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 45 | public static final field $stable I 46 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 47 | public final fun getLeft (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 48 | public final fun getRight (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 49 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 50 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 51 | } 52 | 53 | public final class com/popovanton0/blueprint/dsl/HorizontalScope { 54 | public static final field $stable I 55 | public final fun group-QjWXQlE (ILkotlin/jvm/functions/Function1;)V 56 | public static synthetic fun group-QjWXQlE$default (Lcom/popovanton0/blueprint/dsl/HorizontalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 57 | } 58 | 59 | public final class com/popovanton0/blueprint/dsl/MeasureUnit { 60 | public static final field Companion Lcom/popovanton0/blueprint/dsl/MeasureUnit$Companion; 61 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/MeasureUnit; 62 | public fun equals (Ljava/lang/Object;)Z 63 | public static fun equals-impl (ILjava/lang/Object;)Z 64 | public static final fun equals-impl0 (II)Z 65 | public fun hashCode ()I 66 | public static fun hashCode-impl (I)I 67 | public fun toString ()Ljava/lang/String; 68 | public static fun toString-impl (I)Ljava/lang/String; 69 | public final synthetic fun unbox-impl ()I 70 | } 71 | 72 | public final class com/popovanton0/blueprint/dsl/MeasureUnit$Companion { 73 | public final fun getDp-kfOZ-k0 ()I 74 | public final fun getSp-kfOZ-k0 ()I 75 | } 76 | 77 | public abstract interface class com/popovanton0/blueprint/dsl/Position { 78 | } 79 | 80 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal : com/popovanton0/blueprint/dsl/Position { 81 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Horizontal$Companion; 82 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Horizontal; 83 | public fun equals (Ljava/lang/Object;)Z 84 | public static fun equals-impl (ILjava/lang/Object;)Z 85 | public static final fun equals-impl0 (II)Z 86 | public fun hashCode ()I 87 | public static fun hashCode-impl (I)I 88 | public fun toString ()Ljava/lang/String; 89 | public static fun toString-impl (I)Ljava/lang/String; 90 | public final synthetic fun unbox-impl ()I 91 | } 92 | 93 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal$Companion { 94 | public final fun getEnd-o_BGRZA ()I 95 | public final fun getStart-o_BGRZA ()I 96 | } 97 | 98 | public final class com/popovanton0/blueprint/dsl/Position$Vertical : com/popovanton0/blueprint/dsl/Position { 99 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Vertical$Companion; 100 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Vertical; 101 | public fun equals (Ljava/lang/Object;)Z 102 | public static fun equals-impl (ILjava/lang/Object;)Z 103 | public static final fun equals-impl0 (II)Z 104 | public fun hashCode ()I 105 | public static fun hashCode-impl (I)I 106 | public fun toString ()Ljava/lang/String; 107 | public static fun toString-impl (I)Ljava/lang/String; 108 | public final synthetic fun unbox-impl ()I 109 | } 110 | 111 | public final class com/popovanton0/blueprint/dsl/Position$Vertical$Companion { 112 | public final fun getBottom-6W8Q2GU ()I 113 | public final fun getTop-6W8Q2GU ()I 114 | } 115 | 116 | public final class com/popovanton0/blueprint/dsl/SizeUnits { 117 | public static final field $stable I 118 | public static final field Companion Lcom/popovanton0/blueprint/dsl/SizeUnits$Companion; 119 | public synthetic fun (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V 120 | public synthetic fun (IILkotlin/jvm/internal/DefaultConstructorMarker;)V 121 | public fun equals (Ljava/lang/Object;)Z 122 | public final fun getXUnit-kfOZ-k0 ()I 123 | public final fun getYUnit-kfOZ-k0 ()I 124 | public fun hashCode ()I 125 | } 126 | 127 | public final class com/popovanton0/blueprint/dsl/SizeUnits$Companion { 128 | public final fun getDp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 129 | public final fun getSp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 130 | } 131 | 132 | public final class com/popovanton0/blueprint/dsl/VerticalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 133 | public static final field $stable I 134 | public final fun getBottom (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 135 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 136 | public final fun getTop (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 137 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 138 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 139 | } 140 | 141 | public final class com/popovanton0/blueprint/dsl/VerticalScope { 142 | public static final field $stable I 143 | public final fun group-a3hqG0I (ILkotlin/jvm/functions/Function1;)V 144 | public static synthetic fun group-a3hqG0I$default (Lcom/popovanton0/blueprint/dsl/VerticalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 145 | } 146 | 147 | -------------------------------------------------------------------------------- /blueprint-no-op/api/android/blueprint-no-op.api: -------------------------------------------------------------------------------- 1 | public final class com/popovanton0/blueprint/BlueprintIdKt { 2 | public static final fun blueprintId (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;)Landroidx/compose/ui/Modifier; 3 | public static synthetic fun blueprintId$default (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; 4 | } 5 | 6 | public final class com/popovanton0/blueprint/BlueprintKt { 7 | public static final fun Blueprint-clabC8w (Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/BorderStroke;JJLcom/popovanton0/blueprint/dsl/Arrow;IZZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V 8 | public static final fun getBlueprintEnabled ()Z 9 | public static final fun setBlueprintEnabled (Z)V 10 | } 11 | 12 | public abstract interface annotation class com/popovanton0/blueprint/ExperimentalBlueprintApi : java/lang/annotation/Annotation { 13 | } 14 | 15 | public final class com/popovanton0/blueprint/dsl/Anchor { 16 | public static final field $stable I 17 | public fun equals (Ljava/lang/Object;)Z 18 | public fun hashCode ()I 19 | } 20 | 21 | public final class com/popovanton0/blueprint/dsl/Arrow { 22 | public static final field $stable I 23 | public synthetic fun (FFZILkotlin/jvm/internal/DefaultConstructorMarker;)V 24 | public synthetic fun (FFZLkotlin/jvm/internal/DefaultConstructorMarker;)V 25 | public fun equals (Ljava/lang/Object;)Z 26 | public final fun getAngle ()F 27 | public final fun getLength-D9Ej5fM ()F 28 | public final fun getRoundCap ()Z 29 | public fun hashCode ()I 30 | } 31 | 32 | public final class com/popovanton0/blueprint/dsl/BlueprintBuilderScope { 33 | public static final field $stable I 34 | public final fun heights (Lkotlin/jvm/functions/Function1;)V 35 | public final fun widths (Lkotlin/jvm/functions/Function1;)V 36 | } 37 | 38 | public abstract class com/popovanton0/blueprint/dsl/GroupScope { 39 | public static final field $stable I 40 | public final fun lineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 41 | public final fun spLineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 42 | } 43 | 44 | public final class com/popovanton0/blueprint/dsl/HorizontalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 45 | public static final field $stable I 46 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 47 | public final fun getLeft (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 48 | public final fun getRight (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 49 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 50 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 51 | } 52 | 53 | public final class com/popovanton0/blueprint/dsl/HorizontalScope { 54 | public static final field $stable I 55 | public final fun group-QjWXQlE (ILkotlin/jvm/functions/Function1;)V 56 | public static synthetic fun group-QjWXQlE$default (Lcom/popovanton0/blueprint/dsl/HorizontalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 57 | } 58 | 59 | public final class com/popovanton0/blueprint/dsl/MeasureUnit { 60 | public static final field Companion Lcom/popovanton0/blueprint/dsl/MeasureUnit$Companion; 61 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/MeasureUnit; 62 | public fun equals (Ljava/lang/Object;)Z 63 | public static fun equals-impl (ILjava/lang/Object;)Z 64 | public static final fun equals-impl0 (II)Z 65 | public fun hashCode ()I 66 | public static fun hashCode-impl (I)I 67 | public fun toString ()Ljava/lang/String; 68 | public static fun toString-impl (I)Ljava/lang/String; 69 | public final synthetic fun unbox-impl ()I 70 | } 71 | 72 | public final class com/popovanton0/blueprint/dsl/MeasureUnit$Companion { 73 | public final fun getDp-kfOZ-k0 ()I 74 | public final fun getSp-kfOZ-k0 ()I 75 | } 76 | 77 | public abstract interface class com/popovanton0/blueprint/dsl/Position { 78 | } 79 | 80 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal : com/popovanton0/blueprint/dsl/Position { 81 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Horizontal$Companion; 82 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Horizontal; 83 | public fun equals (Ljava/lang/Object;)Z 84 | public static fun equals-impl (ILjava/lang/Object;)Z 85 | public static final fun equals-impl0 (II)Z 86 | public fun hashCode ()I 87 | public static fun hashCode-impl (I)I 88 | public fun toString ()Ljava/lang/String; 89 | public static fun toString-impl (I)Ljava/lang/String; 90 | public final synthetic fun unbox-impl ()I 91 | } 92 | 93 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal$Companion { 94 | public final fun getEnd-o_BGRZA ()I 95 | public final fun getStart-o_BGRZA ()I 96 | } 97 | 98 | public final class com/popovanton0/blueprint/dsl/Position$Vertical : com/popovanton0/blueprint/dsl/Position { 99 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Vertical$Companion; 100 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Vertical; 101 | public fun equals (Ljava/lang/Object;)Z 102 | public static fun equals-impl (ILjava/lang/Object;)Z 103 | public static final fun equals-impl0 (II)Z 104 | public fun hashCode ()I 105 | public static fun hashCode-impl (I)I 106 | public fun toString ()Ljava/lang/String; 107 | public static fun toString-impl (I)Ljava/lang/String; 108 | public final synthetic fun unbox-impl ()I 109 | } 110 | 111 | public final class com/popovanton0/blueprint/dsl/Position$Vertical$Companion { 112 | public final fun getBottom-6W8Q2GU ()I 113 | public final fun getTop-6W8Q2GU ()I 114 | } 115 | 116 | public final class com/popovanton0/blueprint/dsl/SizeUnits { 117 | public static final field $stable I 118 | public static final field Companion Lcom/popovanton0/blueprint/dsl/SizeUnits$Companion; 119 | public synthetic fun (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V 120 | public synthetic fun (IILkotlin/jvm/internal/DefaultConstructorMarker;)V 121 | public fun equals (Ljava/lang/Object;)Z 122 | public final fun getXUnit-kfOZ-k0 ()I 123 | public final fun getYUnit-kfOZ-k0 ()I 124 | public fun hashCode ()I 125 | } 126 | 127 | public final class com/popovanton0/blueprint/dsl/SizeUnits$Companion { 128 | public final fun getDp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 129 | public final fun getSp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 130 | } 131 | 132 | public final class com/popovanton0/blueprint/dsl/VerticalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 133 | public static final field $stable I 134 | public final fun getBottom (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 135 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 136 | public final fun getTop (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 137 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 138 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 139 | } 140 | 141 | public final class com/popovanton0/blueprint/dsl/VerticalScope { 142 | public static final field $stable I 143 | public final fun group-a3hqG0I (ILkotlin/jvm/functions/Function1;)V 144 | public static synthetic fun group-a3hqG0I$default (Lcom/popovanton0/blueprint/dsl/VerticalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 145 | } 146 | 147 | -------------------------------------------------------------------------------- /blueprint-no-op/api/desktop/blueprint-no-op.api: -------------------------------------------------------------------------------- 1 | public final class com/popovanton0/blueprint/BlueprintIdKt { 2 | public static final fun blueprintId (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;)Landroidx/compose/ui/Modifier; 3 | public static synthetic fun blueprintId$default (Landroidx/compose/ui/Modifier;Ljava/lang/String;Lcom/popovanton0/blueprint/dsl/SizeUnits;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; 4 | } 5 | 6 | public final class com/popovanton0/blueprint/BlueprintKt { 7 | public static final fun Blueprint-clabC8w (Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/BorderStroke;Landroidx/compose/foundation/BorderStroke;JJLcom/popovanton0/blueprint/dsl/Arrow;IZZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V 8 | public static final fun getBlueprintEnabled ()Z 9 | public static final fun setBlueprintEnabled (Z)V 10 | } 11 | 12 | public abstract interface annotation class com/popovanton0/blueprint/ExperimentalBlueprintApi : java/lang/annotation/Annotation { 13 | } 14 | 15 | public final class com/popovanton0/blueprint/dsl/Anchor { 16 | public static final field $stable I 17 | public fun equals (Ljava/lang/Object;)Z 18 | public fun hashCode ()I 19 | } 20 | 21 | public final class com/popovanton0/blueprint/dsl/Arrow { 22 | public static final field $stable I 23 | public synthetic fun (FFZILkotlin/jvm/internal/DefaultConstructorMarker;)V 24 | public synthetic fun (FFZLkotlin/jvm/internal/DefaultConstructorMarker;)V 25 | public fun equals (Ljava/lang/Object;)Z 26 | public final fun getAngle ()F 27 | public final fun getLength-D9Ej5fM ()F 28 | public final fun getRoundCap ()Z 29 | public fun hashCode ()I 30 | } 31 | 32 | public final class com/popovanton0/blueprint/dsl/BlueprintBuilderScope { 33 | public static final field $stable I 34 | public final fun heights (Lkotlin/jvm/functions/Function1;)V 35 | public final fun widths (Lkotlin/jvm/functions/Function1;)V 36 | } 37 | 38 | public abstract class com/popovanton0/blueprint/dsl/GroupScope { 39 | public static final field $stable I 40 | public final fun lineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 41 | public final fun spLineTo (Lcom/popovanton0/blueprint/dsl/Anchor;Lcom/popovanton0/blueprint/dsl/Anchor;)V 42 | } 43 | 44 | public final class com/popovanton0/blueprint/dsl/HorizontalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 45 | public static final field $stable I 46 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 47 | public final fun getLeft (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 48 | public final fun getRight (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 49 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 50 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 51 | } 52 | 53 | public final class com/popovanton0/blueprint/dsl/HorizontalScope { 54 | public static final field $stable I 55 | public final fun group-QjWXQlE (ILkotlin/jvm/functions/Function1;)V 56 | public static synthetic fun group-QjWXQlE$default (Lcom/popovanton0/blueprint/dsl/HorizontalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 57 | } 58 | 59 | public final class com/popovanton0/blueprint/dsl/MeasureUnit { 60 | public static final field Companion Lcom/popovanton0/blueprint/dsl/MeasureUnit$Companion; 61 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/MeasureUnit; 62 | public fun equals (Ljava/lang/Object;)Z 63 | public static fun equals-impl (ILjava/lang/Object;)Z 64 | public static final fun equals-impl0 (II)Z 65 | public fun hashCode ()I 66 | public static fun hashCode-impl (I)I 67 | public fun toString ()Ljava/lang/String; 68 | public static fun toString-impl (I)Ljava/lang/String; 69 | public final synthetic fun unbox-impl ()I 70 | } 71 | 72 | public final class com/popovanton0/blueprint/dsl/MeasureUnit$Companion { 73 | public final fun getDp-kfOZ-k0 ()I 74 | public final fun getSp-kfOZ-k0 ()I 75 | } 76 | 77 | public abstract interface class com/popovanton0/blueprint/dsl/Position { 78 | } 79 | 80 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal : com/popovanton0/blueprint/dsl/Position { 81 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Horizontal$Companion; 82 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Horizontal; 83 | public fun equals (Ljava/lang/Object;)Z 84 | public static fun equals-impl (ILjava/lang/Object;)Z 85 | public static final fun equals-impl0 (II)Z 86 | public fun hashCode ()I 87 | public static fun hashCode-impl (I)I 88 | public fun toString ()Ljava/lang/String; 89 | public static fun toString-impl (I)Ljava/lang/String; 90 | public final synthetic fun unbox-impl ()I 91 | } 92 | 93 | public final class com/popovanton0/blueprint/dsl/Position$Horizontal$Companion { 94 | public final fun getEnd-o_BGRZA ()I 95 | public final fun getStart-o_BGRZA ()I 96 | } 97 | 98 | public final class com/popovanton0/blueprint/dsl/Position$Vertical : com/popovanton0/blueprint/dsl/Position { 99 | public static final field Companion Lcom/popovanton0/blueprint/dsl/Position$Vertical$Companion; 100 | public static final synthetic fun box-impl (I)Lcom/popovanton0/blueprint/dsl/Position$Vertical; 101 | public fun equals (Ljava/lang/Object;)Z 102 | public static fun equals-impl (ILjava/lang/Object;)Z 103 | public static final fun equals-impl0 (II)Z 104 | public fun hashCode ()I 105 | public static fun hashCode-impl (I)I 106 | public fun toString ()Ljava/lang/String; 107 | public static fun toString-impl (I)Ljava/lang/String; 108 | public final synthetic fun unbox-impl ()I 109 | } 110 | 111 | public final class com/popovanton0/blueprint/dsl/Position$Vertical$Companion { 112 | public final fun getBottom-6W8Q2GU ()I 113 | public final fun getTop-6W8Q2GU ()I 114 | } 115 | 116 | public final class com/popovanton0/blueprint/dsl/SizeUnits { 117 | public static final field $stable I 118 | public static final field Companion Lcom/popovanton0/blueprint/dsl/SizeUnits$Companion; 119 | public synthetic fun (IIILkotlin/jvm/internal/DefaultConstructorMarker;)V 120 | public synthetic fun (IILkotlin/jvm/internal/DefaultConstructorMarker;)V 121 | public fun equals (Ljava/lang/Object;)Z 122 | public final fun getXUnit-kfOZ-k0 ()I 123 | public final fun getYUnit-kfOZ-k0 ()I 124 | public fun hashCode ()I 125 | } 126 | 127 | public final class com/popovanton0/blueprint/dsl/SizeUnits$Companion { 128 | public final fun getDp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 129 | public final fun getSp ()Lcom/popovanton0/blueprint/dsl/SizeUnits; 130 | } 131 | 132 | public final class com/popovanton0/blueprint/dsl/VerticalGroupScope : com/popovanton0/blueprint/dsl/GroupScope { 133 | public static final field $stable I 134 | public final fun getBottom (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 135 | public final fun getCenter (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 136 | public final fun getTop (Ljava/lang/String;)Lcom/popovanton0/blueprint/dsl/Anchor; 137 | public final fun lineTo (Ljava/lang/String;Ljava/lang/String;)V 138 | public final fun spLineTo (Ljava/lang/String;Ljava/lang/String;)V 139 | } 140 | 141 | public final class com/popovanton0/blueprint/dsl/VerticalScope { 142 | public static final field $stable I 143 | public final fun group-a3hqG0I (ILkotlin/jvm/functions/Function1;)V 144 | public static synthetic fun group-a3hqG0I$default (Lcom/popovanton0/blueprint/dsl/VerticalScope;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V 145 | } 146 | 147 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📐 Blueprint 2 | 3 | [![Release](https://jitpack.io/v/popovanton0/blueprint.svg)](https://jitpack.io/#popovanton0/blueprint) 4 | [![Introductory Medium Article](https://img.shields.io/badge/medium-article-grey?labelColor=black&logo=medium&logoColor=white&link=https://proandroiddev.com/blueprint-visualizing-paddings-in-jetpack-compose-eb62413c6d74)](https://proandroiddev.com/blueprint-visualizing-paddings-in-jetpack-compose-eb62413c6d74) 5 | ![License](https://img.shields.io/github/license/popovanton0/Blueprint?color=blue) 6 | 7 | Visualize the dimensions of your composables on a blueprint 8 | 9 | ![Blueprint Usage Example](images/navbar-light.png#gh-light-mode-only) 10 | ![Blueprint Usage Example](images/navbar-dark.png#gh-dark-mode-only) 11 | 12 | [Introductory Medium Article](https://proandroiddev.com/blueprint-visualizing-paddings-in-jetpack-compose-eb62413c6d74) 13 | 14 | ## The Problem 15 | 16 | Have you ever desired to see, what *exactly* is that padding's value while looking at the composable 17 | preview window? Especially when you are developing a button with 5 color styles, 3 sizes, and 2 18 | optional icons; and each combination of these parameters has different paddings? 19 | 20 | Combinatorial explosion of UI components in design systems requires having a lot of context about 21 | paddings, dp's, sizes, corner radiuses, and other dimensional information in your head at the 22 | same time. 23 | 24 | ![Many combinations of buttons](images/combinations-light.png#gh-light-mode-only) 25 | ![Many combinations of buttons](images/combinations-dark.png#gh-dark-mode-only) 26 | 27 | In addition, code to produce those combinations can get tricky to analyze. So, verification also 28 | becomes hard: you make screenshots, move them to Figma, overlay them on top, and try to see the 29 | difference. Tedious 😩! 30 | 31 | ## The Solution 32 | 33 | The Blueprint library provides a way to visualize dimensional information in your UI using a simple 34 | DSL-based definition: 35 | 36 | 1. Just wrap your target UI in a `Blueprint` composable 37 | 2. Mark children 38 | with [`Modifier.blueprintId(id: String)`](https://github.com/popovanton0/Blueprint/blob/main/blueprint/src/main/java/com/popovanton0/blueprint/BlueprintId.kt) 39 | modifier 40 | 3. Write the blueprint definition 41 | 42 | ```kotlin 43 | Blueprint( 44 | blueprintBuilder = { 45 | widths { 46 | group { 47 | "item0".right lineTo "item1".left 48 | "item0" lineTo "item0" 49 | "item2" lineTo "item3" 50 | } 51 | } 52 | heights { 53 | group { "item0Icon" lineTo "item0Text" } 54 | group { "item0" lineTo "item0" } 55 | group(End) { "item3Icon".bottom lineTo "item3Text".top } 56 | } 57 | } 58 | ) { 59 | val items = remember { listOf("Songs", "Artists", "Playlists", "Settings") } 60 | NavigationBar { 61 | items.forEachIndexed { index, item -> 62 | NavigationBarItem( 63 | modifier = Modifier.blueprintId("item$index"), 64 | icon = { Icon(Modifier.blueprintId("item${index}Icon"), TODO()) }, 65 | label = { Text(Modifier.blueprintId("item${index}Text"), TODO()) }, 66 | selected = index == 0, 67 | onClick = { TODO() } 68 | ) 69 | } 70 | } 71 | } 72 | ``` 73 | 74 | ### Preview 75 | 76 | ![Blueprint Usage Example](images/navbar-light.png#gh-light-mode-only) 77 | ![Blueprint Usage Example](images/navbar-dark.png#gh-dark-mode-only) 78 | 79 | ### And another example: 80 | 81 | ![Blueprint Usage Example](images/button-light.png#gh-light-mode-only) 82 | ![Blueprint Usage Example](images/button-dark.png#gh-dark-mode-only) 83 | 84 | ### Correct arrow padding rendering animation 85 | 86 | https://github.com/popovanton0/Blueprint/assets/15000556/7a90b534-3c7e-437a-8e08-1fdd4329c752 87 | 88 |
89 | Debug 90 | 91 | https://github.com/popovanton0/Blueprint/assets/15000556/535a016f-0ca9-41d2-8e52-2ed7b36fbdc0 92 | 93 |
94 | 95 |
96 | More examples 97 |
98 | These are snapshots from snapshot testing: 99 | 100 | | | | 101 | |----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 102 | | ![almost_none_space_to_draw](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_almost_none_space_to_draw.png) | ![no_blueprint_if_globally_disabled](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_no_blueprint_if_globally_disabled.png) | 103 | | ![arrow_customization 0](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[0.0].png) | ![not_enough_space_to_draw](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_not_enough_space_to_draw.png) | 104 | | ![arrow_customization 15](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[15.0].png) | ![padding_not_applied](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_padding_not_applied.png) | 105 | | ![arrow_customization 45](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[45.0].png) | ![reacts_to_blueprint_builder_update_(with_green)](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_reacts_to_blueprint_builder_update_(with_green).png) | 106 | | ![arrow_customization 90](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_arrow_customization[90.0].png) | ![reacts_to_blueprint_builder_update_(without_green)](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_reacts_to_blueprint_builder_update_(without_green).png) | 107 | | ![basicTest](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_basicTest.png) | ![size_labels](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_size_labels.png) | 108 | | ![correct_line_widths_and_alignments](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_correct_line_widths_and_alignments.png) | ![when_blueprint_is_disabled_it_is_not_shown](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_blueprint_is_disabled_it_is_not_shown.png) | 109 | | ![customFontSizeAndColor](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_customFontSizeAndColor.png) | ![when_specifying_blueprint_ids_that_are_not_referenced_in_the_composable_no_dimensions_are_shown](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_not_referenced_in_the_composable_no_dimensions_are_shown.png) | 110 | | ![emptyBlueprint](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_emptyBlueprint.png) | ![when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(with_green)](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(with_green).png) | 111 | | ![fractional_dp_values_rendering](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_fractional_dp_values_rendering.png) | ![when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(without_green)](/blueprint/src/test/snapshots/images/com.popovanton0.blueprint_BlueprintScreenshotTest_when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden_(without_green).png) | 112 | 113 |
114 | 115 | ## Features 116 | 117 | You can customize 118 | 119 | 1. Line and border strokes (width and color) 120 | 2. Font size and color 121 | 3. Arrow style (length, angle, round or square cap) 122 | 4. Decimal precision of the dimensional values 123 | 124 | Of course, Blueprint works in Android Studio's Preview✨! 125 | 126 | Also, you can disable all the overhead of this library in your release builds by either: 127 | 128 | 1. Disabling blueprint rendering 129 | using [`blueprintEnabled`](https://github.com/popovanton0/Blueprint/blob/main/blueprint/src/main/java/com/popovanton0/blueprint/Blueprint.kt) 130 | property. 131 | 2. Using the `no-op` version of the library: 132 | ```kotlin 133 | dependencies { 134 | debugImplementation("com.github.popovanton0.blueprint:blueprint:1.0.0-alpha05") 135 | releaseImplementation("com.github.popovanton0.blueprint:blueprint-no-op:1.0.0-alpha05") 136 | } 137 | ``` 138 | 139 | ## Getting Started 140 | 141 | [![Release](https://jitpack.io/v/popovanton0/blueprint.svg)](https://jitpack.io/#popovanton0/blueprint) 142 | 143 |
144 | Groovy 145 | 146 | Add the following code to your project's *root* `build.gradle` file: 147 | 148 | ```groovy 149 | repositories { 150 | maven { url "https://jitpack.io" } 151 | } 152 | ``` 153 | 154 | Next, add the dependency below to your _module_'s `build.gradle` file: 155 | 156 | ```gradle 157 | dependencies { 158 | implementation "com.github.popovanton0.blueprint:blueprint:1.0.0-alpha05" 159 | } 160 | ``` 161 | 162 |
163 | 164 |
165 | Kotlin 166 | 167 | Add the following code to your project's *root* `settings.gradle.kts` file: 168 | 169 | ```kotlin 170 | dependencyResolutionManagement { 171 | // ... 172 | repositories { 173 | // ... 174 | maven { url = uri("https://jitpack.io") } 175 | } 176 | } 177 | ``` 178 | 179 | Next, add the dependency below to your _module_'s `build.gradle.kts` file: 180 | 181 | ```kotlin 182 | dependencies { 183 | implementation("com.github.popovanton0.blueprint:blueprint:1.0.0-alpha05") 184 | } 185 | ``` 186 | 187 | Or using Gradle Version Catalog: 188 | 189 | ```toml 190 | [versions] 191 | blueprint = "1.0.0-alpha05" 192 | 193 | [libraries] 194 | blueprint = { module = "com.github.popovanton0.blueprint:blueprint", version.ref = "blueprint" } 195 | ``` 196 | 197 |
198 | 199 | > [!WARNING] 200 | > Do not use this dependency notation: `com.github.popovanton0:blueprint:1.0.0-alpha05`. 201 | > It doesn't work! 202 | 203 | ### Licence 204 | 205 | ``` 206 | Copyright 2023 Anton Popov 207 | 208 | Licensed under the Apache License, Version 2.0 (the "License"); 209 | you may not use this file except in compliance with the License. 210 | You may obtain a copy of the License at 211 | 212 | http://www.apache.org/licenses/LICENSE-2.0 213 | 214 | Unless required by applicable law or agreed to in writing, software 215 | distributed under the License is distributed on an "AS IS" BASIS, 216 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 217 | See the License for the specific language governing permissions and 218 | limitations under the License. 219 | ``` -------------------------------------------------------------------------------- /blueprint/src/androidUnitTest/kotlin/com/popovanton0/blueprint/BlueprintScreenshotTest.kt: -------------------------------------------------------------------------------- 1 | package com.popovanton0.blueprint 2 | 3 | import androidx.compose.foundation.BorderStroke 4 | import androidx.compose.foundation.background 5 | import androidx.compose.foundation.border 6 | import androidx.compose.foundation.layout.Box 7 | import androidx.compose.foundation.layout.Column 8 | import androidx.compose.foundation.layout.Row 9 | import androidx.compose.foundation.layout.fillMaxSize 10 | import androidx.compose.foundation.layout.fillMaxWidth 11 | import androidx.compose.foundation.layout.padding 12 | import androidx.compose.foundation.layout.requiredSize 13 | import androidx.compose.foundation.layout.size 14 | import androidx.compose.material.icons.Icons 15 | import androidx.compose.material.icons.filled.Home 16 | import androidx.compose.material3.Button 17 | import androidx.compose.material3.Icon 18 | import androidx.compose.material3.MaterialTheme 19 | import androidx.compose.material3.Surface 20 | import androidx.compose.material3.Text 21 | import androidx.compose.runtime.Composable 22 | import androidx.compose.runtime.getValue 23 | import androidx.compose.runtime.mutableStateOf 24 | import androidx.compose.runtime.setValue 25 | import androidx.compose.ui.Alignment 26 | import androidx.compose.ui.BiasAlignment 27 | import androidx.compose.ui.Modifier 28 | import androidx.compose.ui.graphics.Color 29 | import androidx.compose.ui.graphics.vector.rememberVectorPainter 30 | import androidx.compose.ui.tooling.preview.datasource.LoremIpsum 31 | import androidx.compose.ui.unit.Dp 32 | import androidx.compose.ui.unit.dp 33 | import androidx.compose.ui.unit.sp 34 | import app.cash.paparazzi.DeviceConfig.Companion.PIXEL_5 35 | import app.cash.paparazzi.Paparazzi 36 | import com.android.resources.Density 37 | import com.google.testing.junit.testparameterinjector.TestParameter 38 | import com.google.testing.junit.testparameterinjector.TestParameterInjector 39 | import com.popovanton0.blueprint.dsl.Arrow 40 | import com.popovanton0.blueprint.dsl.Position.Horizontal.Companion.End 41 | import com.popovanton0.blueprint.dsl.Position.Horizontal.Companion.Start 42 | import com.popovanton0.blueprint.dsl.Position.Vertical.Companion.Bottom 43 | import com.popovanton0.blueprint.dsl.Position.Vertical.Companion.Top 44 | import com.popovanton0.blueprint.dsl.SizeUnits 45 | import org.junit.Rule 46 | import org.junit.Test 47 | import org.junit.runner.RunWith 48 | import kotlin.math.roundToInt 49 | 50 | @RunWith(TestParameterInjector::class) 51 | internal class BlueprintScreenshotTest { 52 | @get:Rule 53 | val paparazzi = Paparazzi( 54 | deviceConfig = PIXEL_5.copy( 55 | screenWidth = 1800, 56 | screenHeight = 1800, 57 | density = Density.XXXHIGH, 58 | softButtons = false, 59 | ), 60 | ) 61 | 62 | @Test 63 | fun basicTest() = paparazzi.snapshotWrapper { 64 | Blueprint(blueprintBuilder = { 65 | widths { 66 | group { 67 | "icon" lineTo "icon" 68 | "text" lineTo "text" 69 | } 70 | group { "icon" lineTo "text" } 71 | group(Top) { "icon".center lineTo "text".center } 72 | group(Top) { "icon".center lineTo "text".center } 73 | } 74 | heights { 75 | group { "icon" lineTo "icon" } 76 | group { "icon" lineTo "icon" } 77 | group(End) { "text" lineTo "text" } 78 | group(End) { "text" lineTo "text" } 79 | } 80 | }) { 81 | TestButton() 82 | } 83 | } 84 | 85 | @Test 86 | fun customFontSizeAndColor() = paparazzi.snapshotWrapper { 87 | Blueprint(blueprintBuilder = { 88 | widths { 89 | group { 90 | "icon" lineTo "icon" 91 | "text" lineTo "text" 92 | } 93 | group { "icon" lineTo "text" } 94 | group(Top) { "icon".center lineTo "text".center } 95 | group(Top) { "icon".center lineTo "text".center } 96 | } 97 | heights { 98 | group { "icon" lineTo "icon" } 99 | group { "icon" lineTo "icon" } 100 | group(End) { "text" lineTo "text" } 101 | group(End) { "text" lineTo "text" } 102 | } 103 | }, fontSize = 14.sp, fontColor = Color.Blue) { 104 | TestButton() 105 | } 106 | } 107 | 108 | @Test 109 | fun emptyBlueprint() = paparazzi.snapshotWrapper { 110 | Blueprint(blueprintBuilder = {}) { 111 | TestButton() 112 | } 113 | } 114 | 115 | @Test 116 | fun when_blueprint_is_disabled_it_is_not_shown() = paparazzi.snapshotWrapper { 117 | Blueprint( 118 | enabled = false, 119 | blueprintBuilder = { widths { group(Top) { "icon" lineTo "icon" } } }, 120 | content = { TestButton() } 121 | ) 122 | } 123 | 124 | @Test 125 | fun when_specifying_blueprint_ids_that_are_not_referenced_in_the_composable_no_dimensions_are_shown() = 126 | paparazzi.snapshotWrapper { 127 | Blueprint(blueprintBuilder = { widths { group { "lorem1" lineTo "lorem2" } } }) { 128 | TestButton() 129 | } 130 | } 131 | 132 | @Test 133 | fun correct_line_widths_and_alignments() = paparazzi.snapshotWrapper { 134 | Blueprint( 135 | lineStroke = BorderStroke(3.dp, Color.Red), 136 | blueprintBuilder = { 137 | widths { 138 | group { "2".right lineTo "3".left } 139 | group { "2".center lineTo "3".center } 140 | group { "2".center lineTo "3".left } 141 | group { "2".left lineTo "3".center } 142 | group { "2".center lineTo "3".right } 143 | group { "2" lineTo "3" } 144 | 145 | group(Top) { 146 | "1".left lineTo "1".center 147 | "1".right lineTo "3".left 148 | "3".center lineTo "3".right 149 | } 150 | group(Top) { "1".center lineTo "3".left } 151 | group(Top) { "1".left lineTo "3".left } 152 | group(Top) { "1".center lineTo "3".center } 153 | group(Top) { "1" lineTo "3" } 154 | } 155 | heights { 156 | group { 157 | "1".top lineTo "1".center 158 | "1".center lineTo "1".bottom 159 | "1".bottom lineTo "2".top 160 | "2".top lineTo "2".center 161 | } 162 | group { "1".center lineTo "2".center } 163 | group { "1" lineTo "1" } 164 | 165 | group(End) { "1".bottom lineTo "3".bottom } 166 | } 167 | } 168 | ) { 169 | TestUI() 170 | } 171 | } 172 | 173 | @Suppress("JUnitMalformedDeclaration") 174 | @Test 175 | fun arrow_customization( 176 | @TestParameter("0", "15", "45", "90") angle: Float, 177 | ) { 178 | paparazzi.snapshotWrapper { 179 | Blueprint( 180 | lineStroke = BorderStroke(6.dp, Color.Red), 181 | arrow = Arrow(length = 6.dp * 3, angle = angle, roundCap = true), 182 | blueprintBuilder = { 183 | widths { 184 | group(Top) { "1" lineTo "3" } 185 | group(Bottom) { "1" lineTo "3" } 186 | } 187 | heights { 188 | group(Start) { "1".bottom lineTo "3".bottom } 189 | group(End) { "1".bottom lineTo "3".bottom } 190 | } 191 | }, 192 | content = { TestUI() } 193 | ) 194 | } 195 | } 196 | 197 | @Test 198 | fun not_enough_space_to_draw() = paparazzi.snapshotWrapper { 199 | Box( 200 | modifier = Modifier 201 | .requiredSize(50.dp) 202 | .border(1.dp, Color.Magenta) 203 | ) { 204 | Blueprint(blueprintBuilder = { 205 | widths { group(Top) { "1" lineTo "3" } } 206 | heights { group { "1".bottom lineTo "3".bottom } } 207 | }, content = { TestUI() }) 208 | } 209 | } 210 | 211 | @Test 212 | fun almost_none_space_to_draw() = paparazzi.snapshotWrapper { 213 | Box( 214 | modifier = Modifier 215 | .requiredSize(10.dp) 216 | .border(1.dp, Color.Magenta) 217 | ) { 218 | Blueprint(blueprintBuilder = { 219 | widths { 220 | group(Top) { "1" lineTo "3" } 221 | group { "2" lineTo "3" } 222 | } 223 | heights { group { "1".bottom lineTo "3".bottom } } 224 | }, content = { TestUI() }) 225 | } 226 | } 227 | 228 | @Test 229 | fun fractional_dp_values_rendering() = paparazzi.snapshotWrapper { 230 | Blueprint(blueprintBuilder = { 231 | widths { group { "1" lineTo "1" } } 232 | heights { group { "1" lineTo "1" } } 233 | }, precision = 3) { 234 | Box( 235 | modifier = Modifier 236 | .size(41.5.dp, 29.5.dp) 237 | .background(Color.Green) 238 | .blueprintId("1") 239 | ) 240 | } 241 | } 242 | 243 | @Composable 244 | private fun LoremText(modifier: Modifier = Modifier, words: Int = 10) = 245 | Text( 246 | modifier = modifier, text = LoremIpsum(words).values.joinToString(separator = " ") 247 | ) 248 | 249 | @Test 250 | fun padding_not_applied() = paparazzi.snapshotWrapper { 251 | Row(modifier = Modifier.fillMaxWidth()) { 252 | LoremText(modifier = Modifier.weight(1f), words = 20) 253 | Column(modifier = Modifier.weight(1f)) { 254 | LoremText() 255 | Blueprint( 256 | blueprintBuilder = { 257 | widths { 258 | repeat(2) { group { "icon" lineTo "text" } } 259 | repeat(2) { group(Top) { "icon" lineTo "text" } } 260 | } 261 | heights { 262 | repeat(2) { group { "icon" lineTo "icon" } } 263 | repeat(2) { group(End) { "icon" lineTo "icon" } } 264 | } 265 | }, 266 | applyPadding = false, 267 | fontColor = Color.Blue, 268 | ) { 269 | TestButton() 270 | } 271 | LoremText() 272 | } 273 | LoremText(modifier = Modifier.weight(1f), words = 20) 274 | } 275 | } 276 | 277 | @Test 278 | fun size_labels() = paparazzi.snapshotWrapper { 279 | Blueprint(blueprintBuilder = { 280 | widths { group { "1" lineTo "1" } } 281 | heights { group { "1" lineTo "1" } } 282 | }, content = { TestUI(showSizeLabels = true) }) 283 | } 284 | 285 | @Test 286 | fun no_blueprint_if_globally_disabled() { 287 | blueprintEnabled = false 288 | paparazzi.snapshotWrapper { 289 | Blueprint(blueprintBuilder = { 290 | widths { group { "1" lineTo "1" } } 291 | heights { group { "1" lineTo "1" } } 292 | }, content = { TestUI() }) 293 | } 294 | blueprintEnabled = true 295 | } 296 | 297 | @Test 298 | fun when_specifying_blueprint_ids_that_are_then_removed_from_the_composition_dimensions_are_shown_and_then_hidden() { 299 | var showGreen by mutableStateOf(true) 300 | val content = @Composable { 301 | Blueprint(blueprintBuilder = { 302 | widths { 303 | group(Top) { "green" lineTo "green" } 304 | group { "blue" lineTo "blue" } 305 | } 306 | }) { 307 | Column { 308 | if (showGreen) Box( 309 | modifier = Modifier 310 | .size(20.dp) 311 | .background(Color.Green) 312 | .blueprintId("green") 313 | ) 314 | Box( 315 | modifier = Modifier 316 | .size(30.dp) 317 | .background(Color.Blue) 318 | .blueprintId("blue") 319 | ) 320 | } 321 | } 322 | } 323 | paparazzi.snapshotWrapper(name = "(with green)") { content() } 324 | showGreen = false 325 | paparazzi.snapshotWrapper(name = "(without green)") { content() } 326 | } 327 | 328 | // todo add tests for absent arrow when dimension label does not fit 329 | 330 | @Test 331 | fun reacts_to_blueprint_builder_update() { 332 | var showGreenSize by mutableStateOf(true) 333 | val content = @Composable { 334 | Blueprint(blueprintBuilder = { 335 | widths { 336 | group { "2" lineTo "2" } 337 | if (showGreenSize) group { "1" lineTo "1" } 338 | } 339 | }) { 340 | TestUI() 341 | } 342 | } 343 | paparazzi.snapshotWrapper(name = "(with green)") { content() } 344 | showGreenSize = false 345 | paparazzi.snapshotWrapper(name = "(without green)") { content() } 346 | } 347 | 348 | private fun Paparazzi.snapshotWrapper( 349 | name: String? = null, 350 | composable: @Composable () -> Unit 351 | ): Unit = snapshot(name) { 352 | MaterialTheme { 353 | Surface(modifier = Modifier.fillMaxSize(), color = Color.White) { 354 | Box(modifier = Modifier.padding(8.dp)) { 355 | composable() 356 | } 357 | } 358 | } 359 | } 360 | 361 | @Composable 362 | private fun TestUI(showSizeLabels: Boolean = false) { 363 | val spacerWidth = 20.dp 364 | Column { 365 | val size = 40.dp 366 | Box( 367 | modifier = Modifier 368 | .size(size) 369 | .background(Color.Green) 370 | .blueprintId("1", if (showSizeLabels) SizeUnits.Dp else null), 371 | contentAlignment = Alignment.Center 372 | ) { 373 | Text(text = "${size.value.roundToInt()}dp", fontSize = 6.sp) 374 | } 375 | Spacer(Modifier.align(BiasAlignment.Horizontal(0.7f)), spacerWidth) 376 | Row { 377 | val size1 = 50.dp 378 | Box( 379 | modifier = Modifier 380 | .size(size1) 381 | .background(Color.Blue) 382 | .blueprintId("2", if (showSizeLabels) SizeUnits.Dp else null), 383 | contentAlignment = Alignment.Center 384 | ) { 385 | Text(text = "${size1.value.roundToInt()}dp", fontSize = 6.sp) 386 | } 387 | Spacer(modifier = Modifier.align(Alignment.CenterVertically), spacerWidth = spacerWidth) 388 | Box( 389 | modifier = Modifier 390 | .size(size1) 391 | .background(Color.Yellow) 392 | .blueprintId("3", if (showSizeLabels) SizeUnits.Dp else null), 393 | contentAlignment = Alignment.Center 394 | ) { 395 | Text(text = "${size1.value.roundToInt()}dp", fontSize = 6.sp) 396 | } 397 | } 398 | } 399 | } 400 | 401 | @Composable 402 | private fun Spacer(modifier: Modifier = Modifier, spacerWidth: Dp) { 403 | Box( 404 | modifier = modifier 405 | .size(spacerWidth) 406 | .background(Color.Green.copy(alpha = 0.2f)), 407 | contentAlignment = Alignment.Center 408 | ) { 409 | Text(text = "${spacerWidth.value.roundToInt()}dp", fontSize = 6.sp) 410 | } 411 | } 412 | 413 | @Composable 414 | private fun TestButton() = Button(onClick = { }) { 415 | Icon( 416 | modifier = Modifier 417 | .size(20.dp) 418 | .blueprintId("icon"), 419 | painter = rememberVectorPainter(Icons.Default.Home), 420 | contentDescription = null 421 | ) 422 | Text( 423 | modifier = Modifier.blueprintId("text"), 424 | text = "Lorem", 425 | ) 426 | } 427 | } --------------------------------------------------------------------------------