├── .github
└── workflows
│ ├── publish.yml
│ └── test.yml
├── .gitignore
├── .idea
└── copyright
│ ├── Touchlane.xml
│ └── profiles_settings.xml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── touchlane
│ │ └── gridpad
│ │ └── example
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── touchlane
│ │ │ └── gridpad
│ │ │ └── example
│ │ │ ├── GridPadExampleApplication.kt
│ │ │ ├── MainActivity.kt
│ │ │ └── ui
│ │ │ ├── component
│ │ │ ├── BlueprintBox.kt
│ │ │ ├── EngineeringCalculatorPad.kt
│ │ │ ├── InteractivePinPad.kt
│ │ │ ├── PadButton.kt
│ │ │ ├── PinPad.kt
│ │ │ ├── SimpleCalculatorPad.kt
│ │ │ └── SimplePriorityCalculatorPad.kt
│ │ │ └── theme
│ │ │ ├── Color.kt
│ │ │ ├── Theme.kt
│ │ │ └── Type.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-anydpi-v33
│ │ └── ic_launcher.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ └── data_extraction_rules.xml
│ └── test
│ └── java
│ └── com
│ └── touchlane
│ └── gridpad
│ └── example
│ └── ExampleUnitTest.kt
├── build-logic
├── convention
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ ├── AndroidApplicationConventionPlugin.kt
│ │ ├── AndroidComposeConventionPlugin.kt
│ │ ├── AndroidDetektConventionPlugin.kt
│ │ ├── AndroidJacocoConventionPlugin.kt
│ │ ├── AndroidKotlinConventionPlugin.kt
│ │ ├── AndroidKotlinExplicitApiConventionPlugin.kt
│ │ ├── AndroidLibraryConventionPlugin.kt
│ │ ├── PublishNexusModuleConventionPlugin.kt
│ │ ├── PublishNexusProjectConventionPlugin.kt
│ │ └── com
│ │ └── touchlane
│ │ └── gridpad
│ │ ├── AndroidApplication.kt
│ │ ├── AndroidCommon.kt
│ │ ├── AndroidCompose.kt
│ │ ├── AndroidJacoco.kt
│ │ ├── AndroidLibrary.kt
│ │ ├── AndroidLibraryPublishing.kt
│ │ ├── Kotlin.kt
│ │ ├── PublishingSetupRepository.kt
│ │ ├── PublishingUpload.kt
│ │ └── publishing
│ │ ├── EnvironmentPublishingCredentialsLoader.kt
│ │ ├── FilePublishingCredentialsLoader.kt
│ │ ├── PublishingCredentialsDelegate.kt
│ │ ├── PublishingCredentialsLoader.kt
│ │ └── PublishingProperties.kt
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
└── settings.gradle.kts
├── build.gradle.kts
├── config
└── detekt
│ └── detekt.yml
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── gridpad
├── .gitignore
├── api
│ └── gridpad.api
├── artifact.properties
├── build.gradle.kts
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── touchlane
│ │ └── gridpad
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── com
│ │ └── touchlane
│ │ └── gridpad
│ │ ├── GridPadCells.kt
│ │ ├── GridPadDiagnosticLogger.kt
│ │ ├── GridPadDsl.kt
│ │ ├── GridPadItemScope.kt
│ │ ├── GridPadItemScopeImpl.kt
│ │ ├── GridPadPlacementPolicy.kt
│ │ ├── GridPadScopeImpl.kt
│ │ ├── GridPadScopeMarker.kt
│ │ └── GridPadSpanAnchor.kt
│ └── test
│ └── kotlin
│ └── com
│ └── touchlane
│ └── gridpad
│ ├── GridPadCellsUnitTest.kt
│ ├── GridPadDiagnosticLoggerUnitTest.kt
│ ├── GridPadPlacementPolicyUnitTest.kt
│ ├── GridPadScopeTest.kt
│ └── LoggerTest.kt
└── settings.gradle.kts
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | release:
5 | # Run this workflow when a new GitHub release is created
6 | types: [released]
7 |
8 | jobs:
9 | publish:
10 | name: Release build and publish
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Check out code
14 | uses: actions/checkout@v2
15 | - name: Set up JDK 17
16 | uses: actions/setup-java@v2
17 | with:
18 | distribution: adopt
19 | java-version: 17
20 |
21 | # Builds the release artifacts of the library
22 | - name: Release build
23 | run: ./gradlew :gridpad:assemble
24 |
25 | # Runs upload, and then closes & releases the repository
26 | - name: Publish to MavenCentral
27 | run: ./gradlew publishGridpadPublicationToSonatypeRepository --max-workers 1 closeAndReleaseSonatypeStagingRepository
28 | env:
29 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
30 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
31 | SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
32 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
33 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
34 | SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Quality Control
2 |
3 | on:
4 | push:
5 | branches: ['*']
6 |
7 | pull_request:
8 | branches: ['*']
9 |
10 | jobs:
11 | quality-control:
12 | name: Quality Control
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Check out code
16 | uses: actions/checkout@v2
17 | - name: Set up JDK 17
18 | uses: actions/setup-java@v2
19 | with:
20 | distribution: adopt
21 | java-version: 17
22 |
23 | # Run static analyze
24 | - name: Run static analyze
25 | run: ./gradlew :gridpad:detekt
26 |
27 | # Run unit testing
28 | - name: Run unit testing
29 | run: ./gradlew :gridpad:test
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | # Android Studio 3 in .gitignore file.
48 | .idea/caches
49 | .idea/modules.xml
50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
51 | .idea/navEditor.xml
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 | .cxx/
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 | /.idea/inspectionProfiles/
87 | /.idea/.gitignore
88 | /.idea/.name
89 | /.idea/androidTestResultsUserPreferences.xml
90 | /.idea/compiler.xml
91 | /.idea/kotlinc.xml
92 | /.idea/misc.xml
93 | /.idea/deploymentTargetDropDown.xml
94 |
--------------------------------------------------------------------------------
/.idea/copyright/Touchlane.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | ## Version 1.1.2
5 |
6 | _2023-07-13_
7 |
8 | * **Fix**: size distribution algorithm
9 | * Dependency updates
10 |
11 | ## Version 1.1.1
12 |
13 | _2023-05-23_
14 |
15 | * Dependency updates
16 |
17 | ## Version 1.1.0
18 |
19 | _2023-03-06_
20 |
21 | * **API Change**: helper extension signature from
22 | `GridPadCellSize.Companion.weight(sizes: FloatArray)` to
23 | `GridPadCellSize.Companion.weight(vararg sizes: Float)`
24 |
25 | ## Version 1.0.0
26 |
27 | _2022-12-28_
28 |
29 | * **New**: added `GridPadPlacementPolicy` class that used to control implicit placement policy
30 | for items
31 | * **New**: added `GridPadDiagnosticLogger` diagnostic class to receive information about skipped
32 | items
33 | * **API Change**: to `GridPad` added `placementPolicy` property
34 | * **API Change**: `GridPadScope.item()` split to two methods - explicit and implicit
35 | * **Behavior Change**: implicit placement of elements depends on `placementPolicy` property
36 | * **Behavior Change**: span expands depends on `placementPolicy` property
37 |
38 | The new API shouldn't affect your code by default. Only one case can be affected by library
39 | update - cases when only one of the `row` or `column` parameters was defined in GridPad.item.
40 | This way of using is no more acceptable for not enough clear behavior reasons.
41 |
42 | ## Version 0.0.4
43 |
44 | _2022-12-20_
45 |
46 | * **API Change**: GridPad DSL is limited to a Kotlin context receiver
47 | * **Fix**: size distribution algorithm
48 | * test coverage improvement
49 |
50 | ## Version 0.0.3
51 |
52 | _2022-12-09_
53 |
54 | * **Fix**: added missing source code
55 |
56 | ## Version 0.0.2
57 |
58 | _2022-12-07_
59 |
60 | * **Remove**: unused dependencies
61 |
62 | ## Version 0.0.1
63 |
64 | _2022-12-07_
65 |
66 | * First alpha release
67 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Touchlane LLC tech@touchlane.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | @file:Suppress("UnstableApiUsage")
26 | @Suppress("DSL_SCOPE_VIOLATION") // Remove when fixed https://youtrack.jetbrains.com/issue/KTIJ-19369
27 | plugins {
28 | id("gridpad.android.application")
29 | id("gridpad.jetbrains.kotlin.android")
30 | id("gridpad.android.compose")
31 | }
32 |
33 | android {
34 | namespace = "com.touchlane.gridpad.example"
35 |
36 | defaultConfig {
37 | applicationId = "com.touchlane.gridpad.example"
38 | versionCode = 1
39 | versionName = "1.0"
40 |
41 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
42 | }
43 |
44 | buildTypes {
45 | getByName("release") {
46 | isMinifyEnabled = false
47 | proguardFiles(
48 | getDefaultProguardFile("proguard-android-optimize.txt"),
49 | "proguard-rules.pro"
50 | )
51 | }
52 | }
53 | }
54 |
55 | dependencies {
56 | implementation(project(":gridpad"))
57 | implementation(libs.androidx.activity.compose)
58 | implementation(libs.androidx.compose.material.icons)
59 | implementation(libs.androidx.compose.material3)
60 | implementation(libs.androidx.compose.runtime)
61 | implementation(libs.androidx.compose.ui)
62 | implementation(libs.androidx.compose.ui.tooling.preview)
63 | implementation(libs.androidx.core.ktx)
64 | implementation(libs.androidx.lifecycle.runtime.ktx)
65 | testImplementation(libs.junit4)
66 | androidTestImplementation(libs.androidx.test.ext)
67 | androidTestImplementation(libs.androidx.test.espresso.core)
68 | androidTestImplementation(libs.androidx.compose.ui.test)
69 | debugImplementation(libs.androidx.compose.ui.tooling)
70 | debugImplementation(libs.androidx.compose.ui.testManifest)
71 | }
--------------------------------------------------------------------------------
/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/touchlane/gridpad/example/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example
26 |
27 | import androidx.test.platform.app.InstrumentationRegistry
28 | import androidx.test.ext.junit.runners.AndroidJUnit4
29 |
30 | import org.junit.Test
31 | import org.junit.runner.RunWith
32 |
33 | import org.junit.Assert.*
34 |
35 | /**
36 | * Instrumented test, which will execute on an Android device.
37 | *
38 | * See [testing documentation](http://d.android.com/tools/testing).
39 | */
40 | @RunWith(AndroidJUnit4::class)
41 | class ExampleInstrumentedTest {
42 | @Test
43 | fun useAppContext() {
44 | // Context of the app under test.
45 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
46 | assertEquals("com.touchlane.gridpad.example", appContext.packageName)
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
24 |
25 |
27 |
28 |
38 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/GridPadExampleApplication.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example
26 |
27 | import android.app.Application
28 | import android.util.Log
29 | import com.touchlane.gridpad.GridPadDiagnosticLogger
30 |
31 | class GridPadExampleApplication : Application() {
32 |
33 | override fun onCreate() {
34 | super.onCreate()
35 | GridPadDiagnosticLogger.skippingItemListener = { message ->
36 | Log.w("GridPad", message)
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/component/BlueprintBox.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.component
26 |
27 | import androidx.compose.foundation.Canvas
28 | import androidx.compose.foundation.background
29 | import androidx.compose.foundation.layout.Box
30 | import androidx.compose.foundation.layout.fillMaxSize
31 | import androidx.compose.foundation.layout.padding
32 | import androidx.compose.foundation.layout.wrapContentSize
33 | import androidx.compose.material3.MaterialTheme
34 | import androidx.compose.material3.Text
35 | import androidx.compose.runtime.Composable
36 | import androidx.compose.ui.Modifier
37 | import androidx.compose.ui.graphics.Color
38 | import androidx.compose.ui.graphics.PathEffect
39 | import androidx.compose.ui.graphics.drawscope.Stroke
40 | import androidx.compose.ui.platform.LocalDensity
41 | import androidx.compose.ui.text.style.TextAlign
42 | import androidx.compose.ui.tooling.preview.Preview
43 | import androidx.compose.ui.unit.dp
44 | import com.touchlane.gridpad.example.ui.theme.AndreaBlue
45 | import com.touchlane.gridpad.example.ui.theme.HeatWave
46 |
47 | @Composable
48 | fun BlueprintBox() {
49 | val stroke = Stroke(
50 | width = with(LocalDensity.current) { 1.dp.toPx() },
51 | pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
52 | )
53 | Box(
54 | modifier = Modifier
55 | .fillMaxSize()
56 | .padding(1.dp)
57 | ) {
58 | Canvas(modifier = Modifier.fillMaxSize()) {
59 | drawRect(color = Color.White, style = stroke)
60 | }
61 | }
62 | }
63 |
64 | @Composable
65 | fun ContentBlueprintBox(text: String = "") {
66 | val stroke = Stroke(
67 | width = with(LocalDensity.current) { 2.dp.toPx() },
68 | pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
69 | )
70 | Box(
71 | modifier = Modifier
72 | .fillMaxSize()
73 | .padding(1.dp)
74 | .background(Color.White)
75 | ) {
76 | Canvas(modifier = Modifier.fillMaxSize()) {
77 | drawRect(color = HeatWave, style = stroke)
78 | }
79 | Text(
80 | modifier = Modifier
81 | .fillMaxSize()
82 | .wrapContentSize(),
83 | text = text,
84 | style = MaterialTheme.typography.bodyMedium,
85 | color = AndreaBlue,
86 | textAlign = TextAlign.Center
87 | )
88 | }
89 | }
90 |
91 | @Preview(widthDp = 86, heightDp = 86)
92 | @Composable
93 | fun BlueprintBoxPreview() {
94 | BlueprintBox()
95 | }
96 |
97 | @Preview(widthDp = 86, heightDp = 86)
98 | @Composable
99 | fun ContentBlueprintBoxPreview() {
100 | ContentBlueprintBox("[0;0]")
101 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/component/InteractivePinPad.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.component
26 |
27 | import androidx.compose.foundation.background
28 | import androidx.compose.foundation.layout.*
29 | import androidx.compose.foundation.shape.RoundedCornerShape
30 | import androidx.compose.material3.MaterialTheme
31 | import androidx.compose.material3.Text
32 | import androidx.compose.runtime.*
33 | import androidx.compose.ui.Alignment
34 | import androidx.compose.ui.Modifier
35 | import androidx.compose.ui.draw.clip
36 | import androidx.compose.ui.tooling.preview.Preview
37 | import androidx.compose.ui.unit.dp
38 | import com.touchlane.gridpad.example.ui.theme.GridPadExampleTheme
39 |
40 | @Composable
41 | fun InteractivePinPad(modifier: Modifier = Modifier) {
42 | var digits by remember { mutableStateOf("") }
43 | Column(modifier = modifier) {
44 | Box(
45 | modifier = Modifier
46 | .fillMaxWidth()
47 | .padding(8.dp)
48 | .clip(RoundedCornerShape(size = 8.dp))
49 | .background(MaterialTheme.colorScheme.surface),
50 | contentAlignment = Alignment.Center
51 | ) {
52 | Text(
53 | modifier = Modifier.padding(8.dp),
54 | text = digits,
55 | style = MaterialTheme.typography.displayMedium,
56 | color = MaterialTheme.colorScheme.onSurface
57 | )
58 | }
59 | Spacer(modifier = Modifier.height(16.dp))
60 | PinPad(
61 | modifier = Modifier
62 | .fillMaxWidth()
63 | .aspectRatio(1.2f)
64 | ) { action ->
65 | when (action) {
66 | 'r' -> {
67 | if (digits.isNotEmpty()) {
68 | digits = digits.substring(0, digits.length - 1)
69 | }
70 | }
71 | else -> {
72 | if (digits.length < 6) {
73 | digits += action
74 | }
75 | }
76 | }
77 | }
78 | }
79 | }
80 |
81 | @Preview(showBackground = true, widthDp = 300)
82 | @Composable
83 | fun InteractivePinPadPreview() {
84 | GridPadExampleTheme {
85 | InteractivePinPad()
86 | }
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/component/PadButton.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.component
26 |
27 | import androidx.compose.animation.core.LinearOutSlowInEasing
28 | import androidx.compose.animation.core.animateDpAsState
29 | import androidx.compose.animation.core.tween
30 | import androidx.compose.foundation.interaction.MutableInteractionSource
31 | import androidx.compose.foundation.interaction.collectIsPressedAsState
32 | import androidx.compose.foundation.layout.*
33 | import androidx.compose.foundation.shape.RoundedCornerShape
34 | import androidx.compose.material.icons.Icons
35 | import androidx.compose.material.icons.filled.Backspace
36 | import androidx.compose.material3.*
37 | import androidx.compose.runtime.*
38 | import androidx.compose.ui.Modifier
39 | import androidx.compose.ui.graphics.Color
40 | import androidx.compose.ui.graphics.takeOrElse
41 | import androidx.compose.ui.graphics.vector.ImageVector
42 | import androidx.compose.ui.text.TextStyle
43 | import androidx.compose.ui.tooling.preview.Preview
44 | import androidx.compose.ui.unit.Dp
45 | import androidx.compose.ui.unit.dp
46 | import com.touchlane.gridpad.example.ui.theme.GridPadExampleTheme
47 |
48 | @Composable
49 | fun LargeTextPadButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier) {
50 | TextPadButton(
51 | text = text,
52 | onClick = onClick,
53 | style = MaterialTheme.typography.displaySmall,
54 | modifier = modifier
55 | )
56 | }
57 |
58 | @Composable
59 | fun MediumTextPadButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier) {
60 | TextPadButton(
61 | text = text,
62 | onClick = onClick,
63 | style = MaterialTheme.typography.headlineMedium,
64 | modifier = modifier
65 | )
66 | }
67 |
68 | @Composable
69 | fun SmallTextPadButton(text: String, onClick: () -> Unit, modifier: Modifier = Modifier) {
70 | TextPadButton(
71 | text = text,
72 | onClick = onClick,
73 | style = MaterialTheme.typography.titleMedium,
74 | modifier = modifier
75 | )
76 | }
77 |
78 | @Composable
79 | fun TextPadButton(
80 | text: String,
81 | style: TextStyle,
82 | onClick: () -> Unit,
83 | modifier: Modifier = Modifier
84 | ) {
85 | PadButton(onClick = onClick, modifier = modifier) {
86 | Text(text = text, style = style, color = PadButtonTheme.colors.content)
87 | }
88 | }
89 |
90 | @Composable
91 | fun IconPadButton(icon: ImageVector, onClick: () -> Unit, modifier: Modifier = Modifier) {
92 | PadButton(onClick = onClick, modifier = modifier) {
93 | val tint = PadButtonTheme.colors.content.takeOrElse {
94 | LocalContentColor.current
95 | }
96 | Icon(
97 | icon,
98 | contentDescription = null,
99 | modifier = Modifier.size(32.dp),
100 | tint = tint
101 | )
102 | }
103 | }
104 |
105 | @Composable
106 | fun PadButton(
107 | onClick: () -> Unit,
108 | modifier: Modifier = Modifier,
109 | content: @Composable RowScope.() -> Unit
110 | ) {
111 | val interactionSource = remember { MutableInteractionSource() }
112 | val isPressed by interactionSource.collectIsPressedAsState()
113 | val corner: Dp by animateDpAsState(
114 | if (isPressed) 20.dp else 50.dp,
115 | tween(150, easing = LinearOutSlowInEasing)
116 | )
117 | val containerColor = PadButtonTheme.colors.background.takeOrElse {
118 | MaterialTheme.colorScheme.primary
119 | }
120 | val contentColor = PadButtonTheme.colors.content.takeOrElse {
121 | MaterialTheme.colorScheme.onPrimary
122 | }
123 | val disabledContainerColor = containerColor.takeOrElse {
124 | MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)
125 | }
126 | val disabledContentColor = contentColor.takeOrElse {
127 | MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)
128 | }
129 | val colors = ButtonDefaults.buttonColors(
130 | containerColor = containerColor,
131 | contentColor = contentColor,
132 | disabledContainerColor = disabledContainerColor,
133 | disabledContentColor = disabledContentColor
134 | )
135 | Button(
136 | onClick = onClick,
137 | modifier = modifier
138 | .fillMaxSize()
139 | .padding(4.dp),
140 | shape = RoundedCornerShape(corner),
141 | colors = colors,
142 | contentPadding = PaddingValues(0.dp),
143 | interactionSource = interactionSource
144 | ) {
145 | content()
146 | }
147 | }
148 |
149 | @Immutable
150 | data class PadButtonColors(
151 | val content: Color,
152 | val background: Color
153 | ) {
154 | companion object {
155 | val Default = PadButtonColors(
156 | content = Color.Unspecified,
157 | background = Color.Unspecified
158 | )
159 | }
160 | }
161 |
162 | val LocalPadButtonColors = staticCompositionLocalOf {
163 | PadButtonColors.Default
164 | }
165 |
166 | @Composable
167 | fun PadButtonTheme(
168 | padButtonColors: PadButtonColors = PadButtonColors.Default,
169 | content: @Composable () -> Unit
170 | ) {
171 | CompositionLocalProvider(
172 | LocalPadButtonColors provides padButtonColors,
173 | content = content
174 | )
175 | }
176 |
177 | object PadButtonTheme {
178 | val colors: PadButtonColors
179 | @Composable
180 | get() = LocalPadButtonColors.current
181 | }
182 |
183 | @ButtonPreviews
184 | @Composable
185 | fun LargeTextPadButtonPreview() {
186 | GridPadExampleTheme {
187 | LargeTextPadButton("1", {})
188 | }
189 | }
190 |
191 | @ButtonPreviews
192 | @Composable
193 | fun MediumPadButtonPreview() {
194 | GridPadExampleTheme {
195 | MediumTextPadButton("2", {})
196 | }
197 | }
198 |
199 | @ButtonPreviews
200 | @Composable
201 | fun SmallPadButtonPreview() {
202 | GridPadExampleTheme {
203 | SmallTextPadButton("3", {})
204 | }
205 | }
206 |
207 | @ButtonPreviews
208 | @Composable
209 | fun IconPadButtonPreview() {
210 | GridPadExampleTheme {
211 | IconPadButton(Icons.Default.Backspace, {})
212 | }
213 | }
214 |
215 | @Preview(
216 | name = "Large 128",
217 | group = "PadButton",
218 | widthDp = 128,
219 | heightDp = 128,
220 | )
221 | @Preview(
222 | name = "Medium 86",
223 | group = "PadButton",
224 | widthDp = 86,
225 | heightDp = 86,
226 | )
227 | @Preview(
228 | name = "Medium Horizontal 128x86",
229 | group = "PadButton",
230 | widthDp = 128,
231 | heightDp = 86,
232 | )
233 | @Preview(
234 | name = "Medium Vertical 86x128",
235 | group = "PadButton",
236 | widthDp = 86,
237 | heightDp = 128,
238 | )
239 | annotation class ButtonPreviews
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/component/PinPad.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.component
26 |
27 | import androidx.compose.material.icons.Icons
28 | import androidx.compose.material.icons.filled.Backspace
29 | import androidx.compose.runtime.Composable
30 | import androidx.compose.runtime.CompositionLocalProvider
31 | import androidx.compose.runtime.Immutable
32 | import androidx.compose.runtime.staticCompositionLocalOf
33 | import androidx.compose.ui.Modifier
34 | import androidx.compose.ui.graphics.Color
35 | import androidx.compose.ui.tooling.preview.Preview
36 | import com.touchlane.gridpad.GridPad
37 | import com.touchlane.gridpad.GridPadCells
38 | import com.touchlane.gridpad.GridPadPlacementPolicy
39 | import com.touchlane.gridpad.GridPadPlacementPolicy.VerticalDirection.BOTTOM_TOP
40 | import com.touchlane.gridpad.example.ui.theme.GridPadExampleTheme
41 |
42 | @Composable
43 | fun PinPad(modifier: Modifier = Modifier, onClick: (action: Char) -> Unit = {}) {
44 | PadButtonTheme(
45 | padButtonColors = PadButtonColors(
46 | content = PinPadTheme.colors.content,
47 | background = PinPadTheme.colors.background
48 | )
49 | ) {
50 | GridPad(
51 | cells = GridPadCells.Builder(rowCount = 4, columnCount = 3).build(),
52 | placementPolicy = GridPadPlacementPolicy(verticalDirection = BOTTOM_TOP),
53 | modifier = modifier
54 | ) {
55 | //row 3
56 | item(row = 3, column = 1) {
57 | LargeTextPadButton(text = "0", onClick = { onClick('0') })
58 | }
59 | item {
60 | PadButtonTheme(
61 | padButtonColors = PadButtonColors(
62 | content = PinPadTheme.colors.removeContent,
63 | background = PinPadTheme.colors.background
64 | )
65 | ) {
66 | IconPadButton(icon = Icons.Default.Backspace, onClick = { onClick('r') })
67 | }
68 | }
69 | //row 2
70 | item {
71 | LargeTextPadButton(text = "1", onClick = { onClick('1') })
72 | }
73 | item {
74 | LargeTextPadButton(text = "2", onClick = { onClick('2') })
75 | }
76 | item {
77 | LargeTextPadButton(text = "3", onClick = { onClick('3') })
78 | }
79 | //row 1
80 | item {
81 | LargeTextPadButton(text = "4", onClick = { onClick('4') })
82 | }
83 | item {
84 | LargeTextPadButton(text = "5", onClick = { onClick('5') })
85 | }
86 | item {
87 | LargeTextPadButton(text = "6", onClick = { onClick('6') })
88 | }
89 | //row 0
90 | item {
91 | LargeTextPadButton(text = "7", onClick = { onClick('7') })
92 | }
93 | item {
94 | LargeTextPadButton(text = "8", onClick = { onClick('8') })
95 | }
96 | item {
97 | LargeTextPadButton(text = "9", onClick = { onClick('9') })
98 | }
99 | }
100 | }
101 | }
102 |
103 | @Immutable
104 | data class PinPadColors(
105 | val content: Color,
106 | val removeContent: Color,
107 | val background: Color
108 | ) {
109 | companion object {
110 | val Default = PinPadColors(
111 | content = Color.Unspecified,
112 | removeContent = Color.Unspecified,
113 | background = Color.Unspecified
114 | )
115 | }
116 | }
117 |
118 | val LocalPinPadColors = staticCompositionLocalOf {
119 | PinPadColors.Default
120 | }
121 |
122 | @Composable
123 | fun PinPadTheme(
124 | colors: PinPadColors = PinPadColors.Default,
125 | content: @Composable () -> Unit
126 | ) {
127 | CompositionLocalProvider(
128 | LocalPinPadColors provides colors,
129 | content = content
130 | )
131 | }
132 |
133 | object PinPadTheme {
134 | val colors: PinPadColors
135 | @Composable
136 | get() = LocalPinPadColors.current
137 | }
138 |
139 | @Preview(showBackground = true, widthDp = 300, heightDp = 300)
140 | @Preview(showBackground = true, widthDp = 300, heightDp = 400)
141 | @Composable
142 | fun PinPadPreview() {
143 | GridPadExampleTheme {
144 | PinPad()
145 | }
146 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/component/SimpleCalculatorPad.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.component
26 |
27 | import androidx.compose.material.icons.Icons
28 | import androidx.compose.material.icons.filled.Backspace
29 | import androidx.compose.runtime.Composable
30 | import androidx.compose.runtime.CompositionLocalProvider
31 | import androidx.compose.runtime.Immutable
32 | import androidx.compose.runtime.staticCompositionLocalOf
33 | import androidx.compose.ui.Modifier
34 | import androidx.compose.ui.graphics.Color
35 | import androidx.compose.ui.tooling.preview.Preview
36 | import com.touchlane.gridpad.GridPad
37 | import com.touchlane.gridpad.GridPadCells
38 | import com.touchlane.gridpad.example.ui.theme.GridPadExampleTheme
39 |
40 | @Composable
41 | fun SimpleCalculatorPad(modifier: Modifier = Modifier) {
42 | PadButtonTheme(
43 | padButtonColors = PadButtonColors(
44 | content = SimpleCalculatorPadTheme.colors.content,
45 | background = SimpleCalculatorPadTheme.colors.background
46 | )
47 | ) {
48 | GridPad(
49 | cells = GridPadCells.Builder(rowCount = 5, columnCount = 4).build(),
50 | modifier = modifier
51 | ) {
52 | //row 0
53 | item {
54 | RemoveTheme {
55 | LargeTextPadButton(text = "C", onClick = {})
56 | }
57 | }
58 | item {
59 | ActionTheme {
60 | LargeTextPadButton(text = "÷", onClick = {})
61 | }
62 | }
63 | item {
64 | ActionTheme {
65 | LargeTextPadButton(text = "×", onClick = {})
66 | }
67 | }
68 | item {
69 | RemoveTheme {
70 | IconPadButton(icon = Icons.Default.Backspace, onClick = {})
71 | }
72 | }
73 | //row 1
74 | item {
75 | LargeTextPadButton(text = "7", onClick = {})
76 | }
77 | item {
78 | LargeTextPadButton(text = "8", onClick = {})
79 | }
80 | item {
81 | LargeTextPadButton(text = "9", onClick = {})
82 | }
83 | item {
84 | ActionTheme {
85 | LargeTextPadButton(text = "−", onClick = {})
86 | }
87 | }
88 | //row 1
89 | item {
90 | LargeTextPadButton(text = "4", onClick = {})
91 | }
92 | item {
93 | LargeTextPadButton(text = "5", onClick = {})
94 | }
95 | item {
96 | LargeTextPadButton(text = "6", onClick = {})
97 | }
98 | item {
99 | ActionTheme {
100 | LargeTextPadButton(text = "+", onClick = {})
101 | }
102 | }
103 | //row 2
104 | item {
105 | LargeTextPadButton(text = "1", onClick = {})
106 | }
107 | item {
108 | LargeTextPadButton(text = "2", onClick = {})
109 | }
110 | item {
111 | LargeTextPadButton(text = "3", onClick = {})
112 | }
113 | item(rowSpan = 2) {
114 | ActionTheme {
115 | LargeTextPadButton(text = "=", onClick = {})
116 | }
117 | }
118 | //row 3
119 | item(row = 4, column = 0) {
120 | LargeTextPadButton(text = ".", onClick = {})
121 | }
122 | item(columnSpan = 2) {
123 | LargeTextPadButton(text = "0", onClick = {})
124 | }
125 | }
126 | }
127 | }
128 |
129 | @Composable
130 | private fun RemoveTheme(content: @Composable () -> Unit) {
131 | PadButtonTheme(
132 | padButtonColors = PadButtonColors(
133 | content = SimpleCalculatorPadTheme.colors.removeContent,
134 | background = SimpleCalculatorPadTheme.colors.background
135 | )
136 | ) {
137 | content()
138 | }
139 | }
140 |
141 | @Composable
142 | private fun ActionTheme(content: @Composable () -> Unit) {
143 | PadButtonTheme(
144 | padButtonColors = PadButtonColors(
145 | content = SimpleCalculatorPadTheme.colors.actionsContent,
146 | background = SimpleCalculatorPadTheme.colors.background
147 | )
148 | ) {
149 | content()
150 | }
151 | }
152 |
153 | @Immutable
154 | data class SimpleCalculatorPadColors(
155 | val content: Color,
156 | val removeContent: Color,
157 | val actionsContent: Color,
158 | val background: Color
159 | ) {
160 | companion object {
161 | val Default = SimpleCalculatorPadColors(
162 | content = Color.Unspecified,
163 | removeContent = Color.Unspecified,
164 | actionsContent = Color.Unspecified,
165 | background = Color.Unspecified
166 | )
167 | }
168 | }
169 |
170 | val LocalSimpleCalculatorPadColors = staticCompositionLocalOf {
171 | SimpleCalculatorPadColors.Default
172 | }
173 |
174 | @Composable
175 | fun SimpleCalculatorPadTheme(
176 | colors: SimpleCalculatorPadColors = SimpleCalculatorPadColors.Default,
177 | content: @Composable () -> Unit
178 | ) {
179 | CompositionLocalProvider(
180 | LocalSimpleCalculatorPadColors provides colors,
181 | content = content
182 | )
183 | }
184 |
185 | object SimpleCalculatorPadTheme {
186 | val colors: SimpleCalculatorPadColors
187 | @Composable
188 | get() = LocalSimpleCalculatorPadColors.current
189 | }
190 |
191 | @Preview(showBackground = true, widthDp = 400, heightDp = 500)
192 | @Preview(showBackground = true, widthDp = 400, heightDp = 400)
193 | @Composable
194 | fun SimpleCalculatorPadPreview() {
195 | GridPadExampleTheme {
196 | SimpleCalculatorPad()
197 | }
198 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/component/SimplePriorityCalculatorPad.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.component
26 |
27 | import androidx.compose.material.icons.Icons
28 | import androidx.compose.material.icons.filled.Backspace
29 | import androidx.compose.runtime.Composable
30 | import androidx.compose.runtime.CompositionLocalProvider
31 | import androidx.compose.runtime.Immutable
32 | import androidx.compose.runtime.staticCompositionLocalOf
33 | import androidx.compose.ui.Modifier
34 | import androidx.compose.ui.graphics.Color
35 | import androidx.compose.ui.tooling.preview.Preview
36 | import androidx.compose.ui.unit.dp
37 | import com.touchlane.gridpad.GridPad
38 | import com.touchlane.gridpad.GridPadCellSize
39 | import com.touchlane.gridpad.GridPadCells
40 | import com.touchlane.gridpad.example.ui.theme.GridPadExampleTheme
41 |
42 | @Composable
43 | fun SimplePriorityCalculatorPad(modifier: Modifier = Modifier) {
44 | PadButtonTheme(
45 | padButtonColors = PadButtonColors(
46 | content = SimplePriorityCalculatorPadTheme.colors.content,
47 | background = SimplePriorityCalculatorPadTheme.colors.background
48 | )
49 | ) {
50 | GridPad(
51 | cells = GridPadCells.Builder(rowCount = 5, columnCount = 5)
52 | .rowSize(0, GridPadCellSize.Fixed(64.dp)).build(), modifier = modifier
53 | ) {
54 | //row 0
55 | item {
56 | RemoveTheme {
57 | MediumTextPadButton(text = "C", onClick = {})
58 | }
59 | }
60 | item(columnSpan = 2) {
61 | ActionTheme {
62 | MediumTextPadButton(text = "(", onClick = {})
63 | }
64 | }
65 | item(columnSpan = 2) {
66 | ActionTheme {
67 | MediumTextPadButton(text = ")", onClick = {})
68 | }
69 | }
70 | //row 1
71 | item {
72 | LargeTextPadButton(text = "7", onClick = {})
73 | }
74 | item {
75 | LargeTextPadButton(text = "8", onClick = {})
76 | }
77 | item {
78 | LargeTextPadButton(text = "9", onClick = {})
79 | }
80 | item {
81 | ActionTheme {
82 | LargeTextPadButton(text = "×", onClick = {})
83 | }
84 | }
85 | item {
86 | ActionTheme {
87 | LargeTextPadButton(text = "÷", onClick = {})
88 | }
89 | }
90 | //row 2
91 | item {
92 | LargeTextPadButton(text = "4", onClick = {})
93 | }
94 | item {
95 | LargeTextPadButton(text = "5", onClick = {})
96 | }
97 | item {
98 | LargeTextPadButton(text = "6", onClick = {})
99 | }
100 | item(rowSpan = 2) {
101 | ActionTheme {
102 | LargeTextPadButton(text = "−", onClick = {})
103 | }
104 | }
105 | item(rowSpan = 2) {
106 | ActionTheme {
107 | LargeTextPadButton(text = "+", onClick = {})
108 | }
109 | }
110 | //row 3
111 | item(row = 3, column = 0) {
112 | LargeTextPadButton(text = "1", onClick = {})
113 | }
114 | item {
115 | LargeTextPadButton(text = "2", onClick = {})
116 | }
117 | item {
118 | LargeTextPadButton(text = "3", onClick = {})
119 | }
120 | //row 4
121 | item(row = 4, column = 0) {
122 | LargeTextPadButton(text = "0", onClick = {})
123 | }
124 | item {
125 | LargeTextPadButton(text = ".", onClick = {})
126 | }
127 | item {
128 | RemoveTheme {
129 | IconPadButton(icon = Icons.Default.Backspace, onClick = {})
130 | }
131 | }
132 | item(columnSpan = 2) {
133 | ActionTheme {
134 | LargeTextPadButton(text = "=", onClick = {})
135 | }
136 | }
137 | }
138 | }
139 | }
140 |
141 | @Composable
142 | private fun RemoveTheme(content: @Composable () -> Unit) {
143 | PadButtonTheme(
144 | padButtonColors = PadButtonColors(
145 | content = SimplePriorityCalculatorPadTheme.colors.content,
146 | background = SimplePriorityCalculatorPadTheme.colors.removeBackground
147 | )
148 | ) {
149 | content()
150 | }
151 | }
152 |
153 | @Composable
154 | private fun ActionTheme(content: @Composable () -> Unit) {
155 | PadButtonTheme(
156 | padButtonColors = PadButtonColors(
157 | content = SimplePriorityCalculatorPadTheme.colors.content,
158 | background = SimplePriorityCalculatorPadTheme.colors.actionsBackground
159 | )
160 | ) {
161 | content()
162 | }
163 | }
164 |
165 | @Immutable
166 | data class SimplePriorityCalculatorPadColors(
167 | val content: Color,
168 | val background: Color,
169 | val removeBackground: Color,
170 | val actionsBackground: Color
171 | ) {
172 | companion object {
173 | val Default = SimplePriorityCalculatorPadColors(
174 | content = Color.Unspecified,
175 | background = Color.Unspecified,
176 | removeBackground = Color.Unspecified,
177 | actionsBackground = Color.Unspecified
178 | )
179 | }
180 | }
181 |
182 | val LocalSimplePriorityCalculatorPadColors = staticCompositionLocalOf {
183 | SimplePriorityCalculatorPadColors.Default
184 | }
185 |
186 | @Composable
187 | fun SimplePriorityCalculatorPadTheme(
188 | colors: SimplePriorityCalculatorPadColors = SimplePriorityCalculatorPadColors.Default,
189 | content: @Composable () -> Unit
190 | ) {
191 | CompositionLocalProvider(
192 | LocalSimplePriorityCalculatorPadColors provides colors, content = content
193 | )
194 | }
195 |
196 | object SimplePriorityCalculatorPadTheme {
197 | val colors: SimplePriorityCalculatorPadColors
198 | @Composable get() = LocalSimplePriorityCalculatorPadColors.current
199 | }
200 |
201 | @Preview(showBackground = true, widthDp = 500, heightDp = 600)
202 | @Preview(showBackground = true, widthDp = 500, heightDp = 400)
203 | @Composable
204 | fun SimplePriorityCalculatorPadPreview() {
205 | GridPadExampleTheme {
206 | SimplePriorityCalculatorPad()
207 | }
208 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.theme
26 |
27 | import androidx.compose.ui.graphics.Color
28 |
29 | val HeatWave = Color(0xFFFF7900)
30 | val BarneyPurple = Color(0xFF990099)
31 | val AswadBlack = Color(0xFF16181c)
32 | val AndreaBlue = Color(0xFF4175e2)
33 |
34 | val White = Color(0xFFFFFFFF)
35 |
36 | val BabyBlueEyes = Color(0XFF9CCAFF)
37 | val LightSteelBlue = Color(0XFFBAC8DB)
38 | val Melon = Color(0XFFFFB4A5)
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.theme
26 |
27 | import android.app.Activity
28 | import androidx.compose.material3.MaterialTheme
29 | import androidx.compose.material3.darkColorScheme
30 | import androidx.compose.runtime.Composable
31 | import androidx.compose.runtime.SideEffect
32 | import androidx.compose.ui.graphics.toArgb
33 | import androidx.compose.ui.platform.LocalView
34 | import androidx.core.view.WindowCompat
35 |
36 | private val DarkColorScheme = darkColorScheme(
37 | background = AswadBlack,
38 | surface = AswadBlack,
39 | primary = BabyBlueEyes,
40 | secondary = LightSteelBlue,
41 | tertiary = Melon
42 | )
43 |
44 | @Composable
45 | fun GridPadExampleTheme(
46 | content: @Composable () -> Unit
47 | ) {
48 | val colorScheme = DarkColorScheme
49 | val view = LocalView.current
50 | if (!view.isInEditMode) {
51 | SideEffect {
52 | val window = (view.context as Activity).window
53 | window.statusBarColor = colorScheme.primary.toArgb()
54 | WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = true
55 | }
56 | }
57 |
58 | MaterialTheme(
59 | colorScheme = colorScheme,
60 | typography = Typography,
61 | content = content
62 | )
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/touchlane/gridpad/example/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example.ui.theme
26 |
27 | import androidx.compose.material3.Typography
28 | import androidx.compose.ui.text.TextStyle
29 | import androidx.compose.ui.text.font.FontFamily
30 | import androidx.compose.ui.text.font.FontWeight
31 | import androidx.compose.ui.unit.sp
32 |
33 | // Set of Material typography styles to start with
34 | val Typography = Typography(
35 | bodyLarge = TextStyle(
36 | fontFamily = FontFamily.Default,
37 | fontWeight = FontWeight.Normal,
38 | fontSize = 16.sp,
39 | lineHeight = 24.sp,
40 | letterSpacing = 0.5.sp
41 | )
42 | /* Other default text styles to override
43 | titleLarge = TextStyle(
44 | fontFamily = FontFamily.Default,
45 | fontWeight = FontWeight.Normal,
46 | fontSize = 22.sp,
47 | lineHeight = 28.sp,
48 | letterSpacing = 0.sp
49 | ),
50 | labelSmall = TextStyle(
51 | fontFamily = FontFamily.Default,
52 | fontWeight = FontWeight.Medium,
53 | fontSize = 11.sp,
54 | lineHeight = 16.sp,
55 | letterSpacing = 0.5.sp
56 | )
57 | */
58 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
24 |
25 |
31 |
32 |
33 |
39 |
42 |
45 |
46 |
47 |
48 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
31 |
34 |
39 |
44 |
49 |
54 |
59 |
64 |
69 |
74 |
79 |
84 |
89 |
94 |
99 |
104 |
109 |
114 |
119 |
124 |
129 |
134 |
139 |
144 |
149 |
154 |
159 |
164 |
169 |
174 |
179 |
184 |
189 |
194 |
195 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 | #FFBB86FC
28 | #FF6200EE
29 | #FF3700B3
30 | #FF03DAC5
31 | #FF018786
32 | #FF000000
33 | #FFFFFFFF
34 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 | GridPad Example
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
24 |
25 |
32 |
33 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
24 |
25 |
30 |
31 |
32 |
36 |
37 |
43 |
--------------------------------------------------------------------------------
/app/src/test/java/com/touchlane/gridpad/example/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.example
26 |
27 | import org.junit.Test
28 |
29 | import org.junit.Assert.*
30 |
31 | /**
32 | * Example local unit test, which will execute on the development machine (host).
33 | *
34 | * See [testing documentation](http://d.android.com/tools/testing).
35 | */
36 | class ExampleUnitTest {
37 | @Test
38 | fun addition_isCorrect() {
39 | assertEquals(4, 2 + 2)
40 | }
41 | }
--------------------------------------------------------------------------------
/build-logic/convention/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | plugins {
26 | `kotlin-dsl`
27 | }
28 |
29 | group = "com.touchlane.gridpad.buildlogic"
30 |
31 | java {
32 | sourceCompatibility = JavaVersion.VERSION_17
33 | targetCompatibility = JavaVersion.VERSION_17
34 | }
35 |
36 | dependencies {
37 | compileOnly(libs.android.gradlePlugin)
38 | compileOnly(libs.kotlin.gradlePlugin)
39 | compileOnly(libs.nexus.publish.gradlePlugin)
40 | }
41 |
42 | gradlePlugin {
43 | plugins {
44 | register("androidApplication") {
45 | id = "gridpad.android.application"
46 | implementationClass = "AndroidApplicationConventionPlugin"
47 | }
48 | register("androidKotlin") {
49 | id = "gridpad.jetbrains.kotlin.android"
50 | implementationClass = "AndroidKotlinConventionPlugin"
51 | }
52 | register("androidKotlinExplicitApi") {
53 | id = "gridpad.jetbrains.kotlin.android.explicit"
54 | implementationClass = "AndroidKotlinExplicitApiConventionPlugin"
55 | }
56 | register("androidLibrary") {
57 | id = "gridpad.android.library"
58 | implementationClass = "AndroidLibraryConventionPlugin"
59 | }
60 | register("androidCompose") {
61 | id = "gridpad.android.compose"
62 | implementationClass = "AndroidComposeConventionPlugin"
63 | }
64 | register("publishNexusProject") {
65 | id = "gridpad.github.gradle-nexus.publish-plugin-project"
66 | implementationClass = "PublishNexusProjectConventionPlugin"
67 | }
68 | register("publishNexusModule") {
69 | id = "gridpad.github.gradle-nexus.publish-plugin-module"
70 | implementationClass = "PublishNexusModuleConventionPlugin"
71 | }
72 | register("androidJacoco") {
73 | id = "gridpad.jacoco"
74 | implementationClass = "AndroidJacocoConventionPlugin"
75 | }
76 | register("androidDetekt") {
77 | id = "gridpad.detekt"
78 | implementationClass = "AndroidDetektConventionPlugin"
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import com.android.build.api.dsl.ApplicationExtension
26 | import com.touchlane.gridpad.configureAndroidApplication
27 | import com.touchlane.gridpad.configureAndroidCommon
28 | import org.gradle.api.Plugin
29 | import org.gradle.api.Project
30 | import org.gradle.kotlin.dsl.configure
31 |
32 | class AndroidApplicationConventionPlugin : Plugin {
33 | override fun apply(target: Project) {
34 | with(target) {
35 | with(pluginManager) {
36 | apply("com.android.application")
37 | }
38 |
39 | extensions.configure {
40 | configureAndroidCommon(this)
41 | configureAndroidApplication(this)
42 | }
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidComposeConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import com.android.build.api.dsl.ApplicationExtension
26 | import com.android.build.api.dsl.LibraryExtension
27 | import com.touchlane.gridpad.configureAndroidCompose
28 | import org.gradle.api.Plugin
29 | import org.gradle.api.Project
30 |
31 | class AndroidComposeConventionPlugin : Plugin {
32 | override fun apply(target: Project) {
33 | with(target) {
34 | extensions.findByType(ApplicationExtension::class.java)?.apply {
35 | configureAndroidCompose(this)
36 | }
37 | extensions.findByType(LibraryExtension::class.java)?.apply {
38 | configureAndroidCompose(this)
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidDetektConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import org.gradle.api.Plugin
26 | import org.gradle.api.Project
27 |
28 | /*
29 | * MIT License
30 | *
31 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
32 | *
33 | * Permission is hereby granted, free of charge, to any person obtaining a copy
34 | * of this software and associated documentation files (the "Software"), to deal
35 | * in the Software without restriction, including without limitation the rights
36 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37 | * copies of the Software, and to permit persons to whom the Software is
38 | * furnished to do so, subject to the following conditions:
39 | *
40 | * The above copyright notice and this permission notice shall be included in all
41 | * copies or substantial portions of the Software.
42 | *
43 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
49 | * SOFTWARE.
50 | */
51 |
52 | class AndroidDetektConventionPlugin : Plugin {
53 | override fun apply(target: Project) {
54 | with(target) {
55 | with(pluginManager) {
56 | apply("io.gitlab.arturbosch.detekt")
57 | }
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidJacocoConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import com.android.build.api.dsl.ApplicationExtension
26 | import com.android.build.api.dsl.LibraryExtension
27 | import com.touchlane.gridpad.configureAndroidJacoco
28 | import com.touchlane.gridpad.limits
29 | import org.gradle.api.Plugin
30 | import org.gradle.api.Project
31 | import org.gradle.kotlin.dsl.extra
32 | import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
33 |
34 | class AndroidJacocoConventionPlugin : Plugin {
35 | override fun apply(target: Project) {
36 | with(target) {
37 | with(pluginManager) {
38 | apply("jacoco")
39 | }
40 | extra.set("limits", limits)
41 | val jacoco = extensions.getByType(JacocoPluginExtension::class.java)
42 | extensions.findByType(ApplicationExtension::class.java)?.apply {
43 | configureAndroidJacoco(this, jacoco)
44 | }
45 | extensions.findByType(LibraryExtension::class.java)?.apply {
46 | configureAndroidJacoco(this, jacoco)
47 | }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidKotlinConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import com.android.build.api.dsl.ApplicationExtension
26 | import com.android.build.api.dsl.LibraryExtension
27 | import com.touchlane.gridpad.configureKotlin
28 | import org.gradle.api.Plugin
29 | import org.gradle.api.Project
30 |
31 | class AndroidKotlinConventionPlugin : Plugin {
32 | override fun apply(target: Project) {
33 | with(target) {
34 | with(pluginManager) {
35 | apply("org.jetbrains.kotlin.android")
36 | }
37 |
38 | extensions.findByType(ApplicationExtension::class.java)?.apply {
39 | configureKotlin(this)
40 | }
41 | extensions.findByType(LibraryExtension::class.java)?.apply {
42 | configureKotlin(this)
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidKotlinExplicitApiConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import org.gradle.api.Plugin
26 | import org.gradle.api.Project
27 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
28 |
29 | /*
30 | * MIT License
31 | *
32 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
33 | *
34 | * Permission is hereby granted, free of charge, to any person obtaining a copy
35 | * of this software and associated documentation files (the "Software"), to deal
36 | * in the Software without restriction, including without limitation the rights
37 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38 | * copies of the Software, and to permit persons to whom the Software is
39 | * furnished to do so, subject to the following conditions:
40 | *
41 | * The above copyright notice and this permission notice shall be included in all
42 | * copies or substantial portions of the Software.
43 | *
44 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
50 | * SOFTWARE.
51 | */
52 |
53 | private const val EXPLICIT_API = "-Xexplicit-api=strict"
54 |
55 | class AndroidKotlinExplicitApiConventionPlugin : Plugin {
56 | override fun apply(target: Project) {
57 | target.tasks
58 | .matching { it is KotlinCompile && !it.name.contains("test", ignoreCase = true) }
59 | .configureEach {
60 | if (!project.hasProperty("kotlin.optOutExplicitApi")) {
61 | val kotlinCompile = this as KotlinCompile
62 | if (EXPLICIT_API !in kotlinCompile.kotlinOptions.freeCompilerArgs) {
63 | kotlinCompile.kotlinOptions.freeCompilerArgs += EXPLICIT_API
64 | }
65 | }
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import com.android.build.gradle.LibraryExtension
26 | import com.touchlane.gridpad.configureAndroidCommon
27 | import com.touchlane.gridpad.configureAndroidLibrary
28 | import org.gradle.api.Plugin
29 | import org.gradle.api.Project
30 | import org.gradle.kotlin.dsl.configure
31 |
32 | class AndroidLibraryConventionPlugin : Plugin {
33 | override fun apply(target: Project) {
34 | with(target) {
35 | with(pluginManager) {
36 | apply("com.android.library")
37 | apply("org.jetbrains.dokka")
38 | apply("org.jetbrains.kotlinx.binary-compatibility-validator")
39 | }
40 |
41 | extensions.configure {
42 | configureAndroidCommon(this)
43 | configureAndroidLibrary(this)
44 | }
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/PublishNexusModuleConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import com.android.build.api.dsl.LibraryExtension
26 | import com.touchlane.gridpad.configureAndroidLibraryPublishing
27 | import com.touchlane.gridpad.configurePublishingUpload
28 | import org.gradle.api.Plugin
29 | import org.gradle.api.Project
30 | import org.gradle.api.publish.PublishingExtension
31 | import org.gradle.kotlin.dsl.configure
32 |
33 |
34 | /*
35 | * MIT License
36 | *
37 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
38 | *
39 | * Permission is hereby granted, free of charge, to any person obtaining a copy
40 | * of this software and associated documentation files (the "Software"), to deal
41 | * in the Software without restriction, including without limitation the rights
42 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43 | * copies of the Software, and to permit persons to whom the Software is
44 | * furnished to do so, subject to the following conditions:
45 | *
46 | * The above copyright notice and this permission notice shall be included in all
47 | * copies or substantial portions of the Software.
48 | *
49 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
55 | * SOFTWARE.
56 | */
57 |
58 | class PublishNexusModuleConventionPlugin : Plugin {
59 | override fun apply(target: Project) {
60 | with(target) {
61 | with(pluginManager) {
62 | apply("maven-publish")
63 | apply("signing")
64 | }
65 | extensions.configure {
66 | configureAndroidLibraryPublishing(this)
67 | }
68 | afterEvaluate {
69 | extensions.configure {
70 | configurePublishingUpload(this)
71 | }
72 | }
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/PublishNexusProjectConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | import com.touchlane.gridpad.configurePublishingRepository
26 | import io.github.gradlenexus.publishplugin.NexusPublishExtension
27 | import org.gradle.api.Plugin
28 | import org.gradle.api.Project
29 | import org.gradle.kotlin.dsl.configure
30 |
31 | /*
32 | * MIT License
33 | *
34 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
35 | *
36 | * Permission is hereby granted, free of charge, to any person obtaining a copy
37 | * of this software and associated documentation files (the "Software"), to deal
38 | * in the Software without restriction, including without limitation the rights
39 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40 | * copies of the Software, and to permit persons to whom the Software is
41 | * furnished to do so, subject to the following conditions:
42 | *
43 | * The above copyright notice and this permission notice shall be included in all
44 | * copies or substantial portions of the Software.
45 | *
46 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
52 | * SOFTWARE.
53 | */
54 |
55 | class PublishNexusProjectConventionPlugin : Plugin {
56 | override fun apply(target: Project) {
57 | with(target) {
58 | extensions.configure {
59 | configurePublishingRepository(this)
60 | }
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/AndroidApplication.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.android.build.api.dsl.ApplicationExtension
28 |
29 | internal fun configureAndroidApplication(
30 | extension: ApplicationExtension,
31 | ) = extension.apply {
32 | defaultConfig {
33 | targetSdk = 34
34 | }
35 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/AndroidCommon.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.android.build.api.dsl.CommonExtension
28 |
29 | @Suppress("UnstableApiUsage")
30 | internal fun configureAndroidCommon(
31 | extension: CommonExtension<*, *, *, *, *>,
32 | ) = extension.apply {
33 | compileSdk = 34
34 |
35 | defaultConfig {
36 | minSdk = 21
37 | vectorDrawables {
38 | useSupportLibrary = true
39 | }
40 | }
41 |
42 | buildFeatures {
43 | compose = true
44 | aidl = false
45 | buildConfig = false
46 | renderScript = false
47 | shaders = false
48 | }
49 |
50 | packaging {
51 | resources {
52 | excludes += "/META-INF/{AL2.0,LGPL2.1}"
53 | }
54 | }
55 |
56 | testOptions {
57 | unitTests {
58 | isIncludeAndroidResources = true
59 | isReturnDefaultValues = true
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/AndroidCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.android.build.api.dsl.CommonExtension
28 | import org.gradle.api.Project
29 | import org.gradle.api.artifacts.VersionCatalogsExtension
30 | import org.gradle.kotlin.dsl.dependencies
31 | import org.gradle.kotlin.dsl.getByType
32 |
33 | @Suppress("UnstableApiUsage")
34 | internal fun Project.configureAndroidCompose(
35 | commonExtension: CommonExtension<*, *, *, *, *>,
36 | ) = commonExtension.apply {
37 | val libs = extensions.getByType().named("libs")
38 |
39 | buildFeatures {
40 | compose = true
41 | }
42 |
43 | composeOptions {
44 | kotlinCompilerExtensionVersion =
45 | libs.findVersion("androidxComposeCompiler").get().toString()
46 | }
47 |
48 | dependencies {
49 | val bom = libs.findLibrary("androidx-compose-bom").get()
50 | add("implementation", platform(bom))
51 | add("androidTestImplementation", platform(bom))
52 | }
53 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/AndroidJacoco.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.android.build.api.dsl.CommonExtension
28 | import groovy.xml.XmlSlurper
29 | import groovy.xml.slurpersupport.NodeChild
30 | import org.gradle.api.GradleException
31 | import org.gradle.api.Project
32 | import org.gradle.kotlin.dsl.extra
33 | import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
34 | import org.gradle.testing.jacoco.tasks.JacocoReport
35 | import java.io.File
36 | import java.util.*
37 | import kotlin.math.roundToInt
38 |
39 | private val excludedFiles = mutableSetOf(
40 | "**/R.class",
41 | "**/R$*.class",
42 | "**/*\$ViewInjector*.*",
43 | "**/*\$ViewBinder*.*",
44 | "**/BuildConfig.*",
45 | "**/Manifest*.*",
46 | "**/*Factory*",
47 | "**/*_MembersInjector*",
48 | "**/*Module*",
49 | "**/*Component*",
50 | "**android**",
51 | "**/BR.class"
52 | )
53 |
54 | internal val limits = mutableMapOf(
55 | "instruction" to 0.0,
56 | "branch" to 0.0,
57 | "line" to 0.0,
58 | "complexity" to 0.0,
59 | "method" to 0.0,
60 | "class" to 0.0
61 | )
62 |
63 | @Suppress("UnstableApiUsage")
64 | internal fun Project.configureAndroidJacoco(
65 | extension: CommonExtension<*, *, *, *, *>, jacoco: JacocoPluginExtension
66 | ) = afterEvaluate {
67 |
68 | val buildTypes = extension.buildTypes.map { type -> type.name }
69 | var productFlavors = extension.productFlavors.map { flavor -> flavor.name }
70 |
71 | if (productFlavors.isEmpty()) {
72 | productFlavors = productFlavors + ""
73 | }
74 |
75 | productFlavors.forEach { flavorName ->
76 | buildTypes.forEach { buildTypeName ->
77 | val sourceName: String
78 | val sourcePath: String
79 |
80 | if (flavorName.isEmpty()) {
81 | sourceName = buildTypeName
82 | sourcePath = buildTypeName
83 | } else {
84 | sourceName = "${flavorName}${buildTypeName.capitalize(Locale.ENGLISH)}"
85 | sourcePath = "${flavorName}/${buildTypeName}"
86 | }
87 |
88 | val testTaskName = "test${sourceName.capitalize(Locale.ENGLISH)}UnitTest"
89 |
90 | registerCodeCoverageTask(
91 | jacoco = jacoco,
92 | testTaskName = testTaskName,
93 | sourceName = sourceName,
94 | sourcePath = sourcePath,
95 | flavorName = flavorName,
96 | buildTypeName = buildTypeName
97 | )
98 | }
99 | }
100 | }
101 |
102 | private fun Project.registerCodeCoverageTask(
103 | jacoco: JacocoPluginExtension,
104 | testTaskName: String,
105 | sourceName: String,
106 | sourcePath: String,
107 | flavorName: String,
108 | buildTypeName: String
109 | ) {
110 | tasks.register("${testTaskName}Coverage", JacocoReport::class.java) {
111 | dependsOn(testTaskName)
112 | group = "Reporting"
113 | description =
114 | "Generate Jacoco coverage reports on the ${sourceName.capitalize(Locale.ENGLISH)} build."
115 |
116 | val javaDirectories = fileTree(
117 | "${project.buildDir}/intermediates/classes/${sourcePath}"
118 | ) { exclude(excludedFiles) }
119 |
120 | val kotlinDirectories = fileTree(
121 | "${project.buildDir}/tmp/kotlin-classes/${sourcePath}"
122 | ) { exclude(excludedFiles) }
123 |
124 | val coverageSrcDirectories = listOf(
125 | "src/main/java",
126 | "src/$flavorName/java",
127 | "src/$buildTypeName/java",
128 | "src/main/kotlin",
129 | "src/$flavorName/kotlin",
130 | "src/$buildTypeName/kotlin"
131 | )
132 |
133 | classDirectories.setFrom(files(javaDirectories, kotlinDirectories))
134 | additionalClassDirs.setFrom(files(coverageSrcDirectories))
135 | sourceDirectories.setFrom(files(coverageSrcDirectories))
136 | executionData.setFrom(
137 | files("${project.buildDir}/jacoco/${testTaskName}.exec")
138 | )
139 |
140 | reports {
141 | xml.required.set(true)
142 | html.required.set(true)
143 | }
144 |
145 | doLast {
146 | jacocoTestReport(jacoco, "${testTaskName}Coverage")
147 | }
148 | }
149 | }
150 |
151 | @Suppress("UNCHECKED_CAST")
152 | private fun Project.jacocoTestReport(jacoco: JacocoPluginExtension, testTaskName: String) {
153 | val reportsDirectory = jacoco.reportsDirectory.asFile.get()
154 | val report = file("$reportsDirectory/${testTaskName}/${testTaskName}.xml")
155 |
156 | logger.lifecycle("Checking coverage results: $report")
157 |
158 | val metrics = report.extractTestsCoveredByType()
159 | val limits = project.extra["limits"] as Map
160 |
161 | val failures = metrics.filter { entry ->
162 | entry.value < limits[entry.key]!!
163 | }.map { entry ->
164 | "- ${entry.key} coverage rate is: ${entry.value}%, minimum is ${limits[entry.key]}%"
165 | }
166 |
167 | if (failures.isNotEmpty()) {
168 | logger.quiet("------------------ Code Coverage Failed -----------------------")
169 | failures.forEach { logger.quiet(it) }
170 | logger.quiet("---------------------------------------------------------------")
171 | throw GradleException("Code coverage failed")
172 | }
173 |
174 | logger.quiet("------------------ Code Coverage Success -----------------------")
175 | metrics.forEach { entry ->
176 | logger.quiet("- ${entry.key} coverage rate is: ${entry.value}%")
177 | }
178 | logger.quiet("---------------------------------------------------------------")
179 | }
180 |
181 | @Suppress("UNCHECKED_CAST")
182 | private fun File.extractTestsCoveredByType(): Map {
183 | val xmlReader = XmlSlurper().apply {
184 | setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
185 | setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
186 | }
187 |
188 | val counterNodes: List = xmlReader
189 | .parse(this).parent()
190 | .children()
191 | .filter {
192 | (it as NodeChild).name() == "counter"
193 | } as List
194 |
195 | return counterNodes.associate { nodeChild ->
196 | val type = nodeChild.attributes()["type"].toString().toLowerCase(Locale.ENGLISH)
197 |
198 | val covered = nodeChild.attributes()["covered"].toString().toDouble()
199 | val missed = nodeChild.attributes()["missed"].toString().toDouble()
200 | val percentage = ((covered / (covered + missed)) * 10000.0).roundToInt() / 100.0
201 |
202 | Pair(type, percentage)
203 | }
204 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/AndroidLibrary.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.android.build.api.dsl.LibraryExtension
28 |
29 | internal fun configureAndroidLibrary(
30 | extension: LibraryExtension,
31 | ) = extension.apply {
32 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/AndroidLibraryPublishing.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.android.build.api.dsl.LibraryExtension
28 |
29 | @Suppress("UnstableApiUsage")
30 | internal fun configureAndroidLibraryPublishing(
31 | extension: LibraryExtension,
32 | ) = extension.apply {
33 | publishing {
34 | multipleVariants {
35 | withSourcesJar()
36 | withJavadocJar()
37 | allVariants()
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/Kotlin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.android.build.api.dsl.CommonExtension
28 | import org.gradle.api.JavaVersion
29 | import org.gradle.api.Project
30 | import org.gradle.api.plugins.ExtensionAware
31 | import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
32 |
33 | internal fun Project.configureKotlin(
34 | commonExtension: CommonExtension<*, *, *, *, *>,
35 | ) = commonExtension.apply {
36 | compileOptions {
37 | sourceCompatibility = JavaVersion.VERSION_11
38 | targetCompatibility = JavaVersion.VERSION_11
39 | }
40 |
41 | kotlinOptions {
42 | if (findProperty("gridpad.enableComposeCompilerReports") != null) {
43 | freeCompilerArgs = listOf(
44 | *freeCompilerArgs.toTypedArray(), *composeMetricsArgs().toTypedArray()
45 | )
46 | }
47 | jvmTarget = JavaVersion.VERSION_11.toString()
48 | }
49 | }
50 |
51 | private fun CommonExtension<*, *, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) {
52 | (this as ExtensionAware).extensions.configure("kotlinOptions", block)
53 | }
54 |
55 | private fun Project.composeMetricsArgs(): List {
56 | val metricsPath = rootProject.composeMetricsPath()
57 | return listOf(
58 | "-P",
59 | "$ARG_COMPOSE_REPORTS_DESTINATION=$metricsPath",
60 | "-P",
61 | "$ARG_COMPOSE_METRICS_DESTINATION=$metricsPath"
62 | )
63 | }
64 |
65 | private fun Project.composeMetricsPath(): String {
66 | return "${buildDir.absolutePath}/compose_metrics"
67 | }
68 |
69 | private const val ARG_COMPOSE_REPORTS_DESTINATION =
70 | "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination"
71 | private const val ARG_COMPOSE_METRICS_DESTINATION =
72 | "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination"
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/PublishingSetupRepository.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.touchlane.gridpad.publishing.PublishingCredentialsDelegate
28 | import io.github.gradlenexus.publishplugin.NexusPublishExtension
29 | import org.gradle.api.Project
30 |
31 | internal fun Project.configurePublishingRepository(
32 | extension: NexusPublishExtension
33 | ) = extension.apply {
34 | val credentials = PublishingCredentialsDelegate.from(this@configurePublishingRepository)
35 | with(repositories.sonatype()) {
36 | stagingProfileId.set(credentials.sonatypeStagingProfileId)
37 | username.set(credentials.ossrhUsername)
38 | password.set(credentials.ossrhPassword)
39 | nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
40 | snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
41 | }
42 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/PublishingUpload.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.android.build.gradle.LibraryExtension
28 | import com.android.builder.model.SourceProvider
29 | import com.touchlane.gridpad.publishing.PublishingCredentialsDelegate
30 | import com.touchlane.gridpad.publishing.PublishingProperties
31 | import org.gradle.api.Project
32 | import org.gradle.api.publish.PublishingExtension
33 | import org.gradle.api.publish.maven.MavenPublication
34 | import org.gradle.api.tasks.SourceSetContainer
35 | import org.gradle.api.tasks.TaskProvider
36 | import org.gradle.jvm.tasks.Jar
37 | import org.gradle.kotlin.dsl.*
38 | import org.gradle.plugins.signing.SigningExtension
39 |
40 | internal fun Project.configurePublishingUpload(
41 | extension: PublishingExtension
42 | ) = extension.apply {
43 | val javadoc = javadoc()
44 |
45 | val properties = PublishingProperties.load(this@configurePublishingUpload)
46 |
47 | publications {
48 | create(properties.publicationName) {
49 | from(components["release"])
50 | groupId = properties.groupId
51 | artifactId = properties.artifactId
52 | version = properties.version
53 |
54 | artifact(javadoc.get())
55 |
56 | pom {
57 | name.set("Touchlane ${project.name}")
58 | description.set(properties.pomDescription)
59 | url.set(properties.pomUrl)
60 | licenses {
61 | license {
62 | name.set("MIT")
63 | url.set("https://choosealicense.com/licenses/mit/")
64 | }
65 | }
66 | developers {
67 | developer {
68 | id.set("touchlane")
69 | name.set("Touchlane LLC")
70 | email.set("tech.touchlane@gmail.com")
71 | }
72 | }
73 | scm {
74 | connection.set(properties.scmConnection)
75 | developerConnection.set(properties.scmDeveloperConnection)
76 | url.set(properties.scmUrl)
77 | }
78 | }
79 | }
80 | }
81 |
82 | val credentials = PublishingCredentialsDelegate.from(rootProject)
83 |
84 | configure {
85 | if (credentials.isExists) {
86 | if (credentials.signingKeyId.isNotBlank()) {
87 | useInMemoryPgpKeys(
88 | credentials.signingKeyId,
89 | credentials.signingKey,
90 | credentials.signingPassword
91 | )
92 | } else {
93 | useInMemoryPgpKeys(
94 | credentials.signingKey,
95 | credentials.signingPassword
96 | )
97 | }
98 | sign(extension.publications[properties.publicationName])
99 | sign(configurations["archives"])
100 | } else {
101 | println("Signing skipped: not found credentials")
102 | }
103 | }
104 | }
105 |
106 | internal fun Project.javadoc(): TaskProvider {
107 | val javadocJar: TaskProvider by tasks.registering(Jar::class) {
108 | archiveClassifier.set("javadoc")
109 |
110 | val dokkaJavadocTask = tasks.getByName("dokkaJavadoc")
111 |
112 | from(dokkaJavadocTask)
113 | dependsOn(dokkaJavadocTask)
114 | }
115 | return javadocJar
116 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/publishing/EnvironmentPublishingCredentialsLoader.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.publishing
26 |
27 | internal class EnvironmentPublishingCredentialsLoader :
28 | PublishingCredentialsLoader {
29 |
30 | override val name: String = "Environment Loader"
31 |
32 | override fun canLoad(): Boolean {
33 | return !System.getenv(KEY_OSSRH_USERNAME).isNullOrBlank()
34 | }
35 |
36 | override fun loadTo(target: PublishingCredentialsDelegate) {
37 | target.ossrhUsername = System.getenv(KEY_OSSRH_USERNAME) ?: ""
38 | target.ossrhPassword = System.getenv(KEY_OSSRH_PASSWORD) ?: ""
39 | target.sonatypeStagingProfileId = System.getenv(KEY_SONATYPE_STAGING_PROFILE_ID) ?: ""
40 | target.signingKeyId = System.getenv(KEY_SIGNING_KEY_ID) ?: ""
41 | target.signingPassword = System.getenv(KEY_SIGNING_PASSWORD) ?: ""
42 | target.signingKey = System.getenv(KEY_SIGNING_KEY) ?: ""
43 | }
44 |
45 | private companion object {
46 | const val KEY_OSSRH_USERNAME = "OSSRH_USERNAME"
47 | const val KEY_OSSRH_PASSWORD = "OSSRH_PASSWORD"
48 | const val KEY_SONATYPE_STAGING_PROFILE_ID = "SONATYPE_STAGING_PROFILE_ID"
49 | const val KEY_SIGNING_KEY_ID = "SIGNING_KEY_ID"
50 | const val KEY_SIGNING_PASSWORD = "SIGNING_PASSWORD"
51 | const val KEY_SIGNING_KEY = "SIGNING_KEY"
52 | }
53 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/publishing/FilePublishingCredentialsLoader.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.publishing
26 |
27 | import com.touchlane.gridpad.publishing.PublishingCredentialsDelegate
28 | import java.io.File
29 | import java.io.FileInputStream
30 | import java.util.*
31 |
32 | internal class FilePublishingCredentialsLoader(private val file: File) :
33 | PublishingCredentialsLoader {
34 |
35 | override val name: String = "File Loader"
36 |
37 | override fun canLoad(): Boolean {
38 | return file.exists()
39 | }
40 |
41 | override fun loadTo(target: PublishingCredentialsDelegate) {
42 | val fileProperties = Properties()
43 | FileInputStream(file).use { stream -> fileProperties.load(stream) }
44 | fileProperties.forEach { key, value ->
45 | if (key is String && value is String) {
46 | target[key] = value
47 | }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/publishing/PublishingCredentialsDelegate.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.publishing
26 |
27 | import org.gradle.api.Project
28 | import org.gradle.api.plugins.ExtraPropertiesExtension
29 | import org.gradle.kotlin.dsl.extra
30 |
31 | internal class PublishingCredentialsDelegate private constructor(private val properties: ExtraPropertiesExtension) {
32 |
33 | val isExists: Boolean
34 | get() = signingKey.isNotBlank()
35 |
36 | var ossrhUsername: String
37 | get() {
38 | return this[KEY_OSSRH_USERNAME]
39 | }
40 | set(value) {
41 | this[KEY_OSSRH_USERNAME] = value
42 | }
43 |
44 | var ossrhPassword: String
45 | get() {
46 | return this[KEY_OSSRH_PASSWORD]
47 | }
48 | set(value) {
49 | this[KEY_OSSRH_PASSWORD] = value
50 | }
51 |
52 | var sonatypeStagingProfileId: String
53 | get() {
54 | return this[KEY_SONATYPE_STAGING_PROFILE_ID]
55 | }
56 | set(value) {
57 | this[KEY_SONATYPE_STAGING_PROFILE_ID] = value
58 | }
59 |
60 | var signingKeyId: String
61 | get() {
62 | return this[KEY_SIGNING_KEY_ID]
63 | }
64 | set(value) {
65 | this[KEY_SIGNING_KEY_ID] = value
66 | }
67 |
68 | var signingPassword: String
69 | get() {
70 | return this[KEY_SIGNING_PASSWORD]
71 | }
72 | set(value) {
73 | this[KEY_SIGNING_PASSWORD] = value
74 | }
75 |
76 | var signingKey: String
77 | get() {
78 | return this[KEY_SIGNING_KEY]
79 | }
80 | set(value) {
81 | this[KEY_SIGNING_KEY] = value
82 | }
83 |
84 | operator fun set(key: String, value: String) {
85 | properties[key] = value
86 | }
87 |
88 | operator fun get(key: String): String {
89 | if (!properties.has(key)) {
90 | return ""
91 | }
92 | val value = properties[key]
93 | return if (value == null || value !is String) {
94 | ""
95 | } else {
96 | value
97 | }
98 | }
99 |
100 | companion object {
101 | private const val KEY_OSSRH_USERNAME = "ossrhUsername"
102 | private const val KEY_OSSRH_PASSWORD = "ossrhPassword"
103 | private const val KEY_SONATYPE_STAGING_PROFILE_ID = "sonatypeStagingProfileId"
104 | private const val KEY_SIGNING_KEY_ID = "signing.keyId"
105 | private const val KEY_SIGNING_PASSWORD = "signing.password"
106 | private const val KEY_SIGNING_KEY = "signing.key"
107 |
108 | fun from(target: Project): PublishingCredentialsDelegate {
109 | val loaders = listOf(
110 | FilePublishingCredentialsLoader(target.file("local.properties")),
111 | EnvironmentPublishingCredentialsLoader()
112 | )
113 | val credentials = PublishingCredentialsDelegate(target.extra)
114 | loaders.forEach {
115 | if (it.canLoad()) {
116 | it.loadTo(credentials)
117 | println("Load credentials from ${it.name} completed.")
118 | return@forEach
119 | } else {
120 | println("Load credentials from ${it.name} skipped.")
121 | }
122 | }
123 | return credentials
124 | }
125 | }
126 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/publishing/PublishingCredentialsLoader.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.publishing
26 |
27 | import com.touchlane.gridpad.publishing.PublishingCredentialsDelegate
28 |
29 | internal interface PublishingCredentialsLoader {
30 |
31 | val name: String
32 |
33 | fun canLoad(): Boolean
34 |
35 | fun loadTo(target: PublishingCredentialsDelegate)
36 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/touchlane/gridpad/publishing/PublishingProperties.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad.publishing
26 |
27 | import org.gradle.api.Project
28 | import java.io.FileInputStream
29 | import java.util.*
30 |
31 | data class PublishingProperties(
32 | val groupId: String,
33 | val artifactId: String,
34 | val version: String,
35 | val publicationName: String,
36 | val pomDescription: String,
37 | val pomUrl: String,
38 | val scmConnection: String,
39 | val scmDeveloperConnection: String,
40 | val scmUrl: String,
41 | ) {
42 | companion object {
43 | fun load(target: Project): PublishingProperties {
44 | val secretPropsFile = target.file("artifact.properties")
45 | val properties = mutableMapOf()
46 | if (secretPropsFile.exists()) {
47 | val fileProperties = Properties()
48 | FileInputStream(secretPropsFile).use { stream -> fileProperties.load(stream) }
49 | fileProperties.forEach { key, value ->
50 | if (key is String) {
51 | properties[key] = value
52 | }
53 | }
54 | }
55 | return PublishingProperties(
56 | groupId = properties.stringOrEmpty("groupId"),
57 | artifactId = properties.stringOrEmpty("artifactId"),
58 | version = properties.stringOrEmpty("version"),
59 | publicationName = properties.stringOrEmpty("publicationName"),
60 | pomDescription = properties.stringOrEmpty("pomDescription"),
61 | pomUrl = properties.stringOrEmpty("pomUrl"),
62 | scmConnection = properties.stringOrEmpty("scmConnection"),
63 | scmDeveloperConnection = properties.stringOrEmpty("scmDeveloperConnection"),
64 | scmUrl = properties.stringOrEmpty("scmUrl")
65 | )
66 | }
67 | }
68 | }
69 |
70 | private fun Map.stringOrEmpty(key: String): String {
71 | val value = this[key]
72 | return if (value is String) {
73 | return value
74 | } else {
75 | ""
76 | }
77 | }
--------------------------------------------------------------------------------
/build-logic/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle properties are not passed to included builds https://github.com/gradle/gradle/issues/2534
2 | org.gradle.parallel=true
3 | org.gradle.caching=true
4 | org.gradle.configureondemand=true
5 |
--------------------------------------------------------------------------------
/build-logic/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/build-logic/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/build-logic/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Nov 09 17:00:58 CET 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/build-logic/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | @Suppress("UnstableApiUsage")
26 | dependencyResolutionManagement {
27 | repositories {
28 | google()
29 | mavenCentral()
30 | gradlePluginPortal()
31 | }
32 | versionCatalogs {
33 | create("libs") {
34 | from(files("../gradle/libs.versions.toml"))
35 | }
36 | }
37 | }
38 |
39 | rootProject.name = "build-logic"
40 | include(":convention")
41 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | @file:Suppress("DSL_SCOPE_VIOLATION")
26 |
27 | import java.util.Locale
28 |
29 | plugins {
30 | alias(libs.plugins.android.application) apply false
31 | alias(libs.plugins.android.library) apply false
32 | alias(libs.plugins.detekt) apply false
33 | alias(libs.plugins.dokka) apply false
34 | alias(libs.plugins.kotlin.android) apply false
35 | alias(libs.plugins.kotlin.compatibilityValidator) apply false
36 | alias(libs.plugins.kotlin.kover) apply false
37 | alias(libs.plugins.nexus.publish)
38 | alias(libs.plugins.versions.checker)
39 | alias(libs.plugins.versions.updater)
40 | id("gridpad.github.gradle-nexus.publish-plugin-project")
41 | }
42 |
43 | tasks.withType {
44 | rejectVersionIf {
45 | isNonStable(candidate.version) && !isNonStable(currentVersion)
46 | }
47 | }
48 |
49 | fun isNonStable(version: String): Boolean {
50 | val stableKeyword = listOf("RELEASE", "FINAL", "GA").any { version.uppercase(Locale.getDefault())
51 | .contains(it) }
52 | val regex = "^[0-9,.v-]+(-r)?$".toRegex()
53 | val isStable = stableKeyword || regex.matches(version)
54 | return isStable.not()
55 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #
24 |
25 | # Project-wide Gradle settings.
26 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
27 | org.gradle.parallel=true
28 | android.useAndroidX=true
29 | # Kotlin code style for this project: "official" or "obsolete":
30 | kotlin.code.style=official
31 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | androidGradlePlugin = "8.2.0"
3 | androidxActivity = "1.8.1"
4 | androidxComposeBom = "2023.10.01"
5 | # @keep for plugin, not used directly
6 | androidxComposeCompiler = "1.5.6"
7 | androidxCore = "1.12.0"
8 | androidxEspresso = "3.5.1"
9 | androidxLifecycleRuntime = "2.6.2"
10 | androidxTestExt = "1.1.5"
11 | detekt = "1.23.0"
12 | dokka = "1.8.20"
13 | junit4 = "4.13.2"
14 | # @pin to use with compose
15 | kotlin = "1.9.21"
16 | kotlinCompatibilityValidator = "0.13.2"
17 | kotlinxCollectionsImmutable = "0.3.5"
18 | kover = "0.7.2"
19 | nexusPublish = "1.3.0"
20 | robolectric = "4.10.3"
21 | versionsChecker = "0.47.0"
22 | versionsUpdater = "0.8.1"
23 |
24 | [libraries]
25 | # @keep for the included build-logic
26 | android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" }
27 | androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidxActivity" }
28 | androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidxComposeBom" }
29 | # @keep for the updates checking
30 | androidx-compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "androidxComposeCompiler" }
31 | androidx-compose-material-icons = { module = "androidx.compose.material:material-icons-extended" }
32 | androidx-compose-material3 = { module = "androidx.compose.material3:material3" }
33 | androidx-compose-runtime = { module = "androidx.compose.runtime:runtime" }
34 | androidx-compose-ui = { module = "androidx.compose.ui:ui" }
35 | androidx-compose-ui-test = { module = "androidx.compose.ui:ui-test-junit4" }
36 | androidx-compose-ui-testManifest = { module = "androidx.compose.ui:ui-test-manifest" }
37 | androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
38 | androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
39 | androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidxCore" }
40 | androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidxLifecycleRuntime" }
41 | androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidxEspresso" }
42 | androidx-test-ext = { module = "androidx.test.ext:junit-ktx", version.ref = "androidxTestExt" }
43 | # @keep for the included build-logic
44 | detekt-gradlePlugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" }
45 | junit4 = { module = "junit:junit", version.ref = "junit4" }
46 | kotlin-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutable" }
47 | # @keep for the included build-logic
48 | kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
49 | kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
50 | # @keep for the included build-logic
51 | nexus-publish-gradlePlugin = { module = "io.github.gradle-nexus:publish-plugin", version.ref = "nexusPublish" }
52 | robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
53 |
54 | [plugins]
55 | android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
56 | android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }
57 | detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
58 | dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
59 | kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
60 | kotlin-compatibilityValidator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "kotlinCompatibilityValidator" }
61 | kotlin-kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
62 | nexus-publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexusPublish" }
63 | versions-checker = { id = "com.github.ben-manes.versions", version.ref = "versionsChecker" }
64 | versions-updater = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionsUpdater" }
65 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/gridpad/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/gridpad/artifact.properties:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #
24 |
25 | # Artifact related properties
26 | groupId=com.touchlane
27 | artifactId=gridpad
28 | version=1.1.2
29 | publicationName=gridpad
30 | pomDescription=Jetpack Compose layout
31 | pomUrl=https://github.com/touchlane/gridpad-android
32 | scmConnection=scm:git:https://github.com/touchlane/gridpad-android.git
33 | scmDeveloperConnection=scm:git:ssh://git@github.com:touchlane/gridpad-android.git
34 | scmUrl=https://github.com/touchlane/gridpad-android
35 |
--------------------------------------------------------------------------------
/gridpad/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | @file:Suppress("UnstableApiUsage")
26 |
27 | @Suppress("DSL_SCOPE_VIOLATION") // Remove when fixed https://youtrack.jetbrains.com/issue/KTIJ-19369
28 | plugins {
29 | id("gridpad.android.library")
30 | id("gridpad.android.compose")
31 | id("gridpad.jetbrains.kotlin.android")
32 | id("gridpad.jetbrains.kotlin.android.explicit")
33 | id("gridpad.github.gradle-nexus.publish-plugin-module")
34 | id("gridpad.jacoco")
35 | id("gridpad.detekt")
36 | }
37 |
38 | // see details in build-logic/convention/src/main/com/touchlane/gridpad/AndroidJacoco.kt
39 | // codecov temporary doesn't work with compose correctly
40 | // https://github.com/jacoco/jacoco/issues/1208
41 | val limits = extra["limits"] as MutableMap
42 | limits["instruction"] = 80.0
43 | limits["branch"] = 80.0
44 | extra.set("limits", limits)
45 |
46 | android {
47 | namespace = "com.touchlane.gridpad"
48 |
49 | defaultConfig {
50 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
51 | consumerProguardFiles("consumer-rules.pro")
52 | }
53 |
54 | buildTypes {
55 | release {
56 | isMinifyEnabled = false
57 | proguardFiles(
58 | getDefaultProguardFile("proguard-android-optimize.txt"),
59 | "proguard-rules.pro"
60 | )
61 | }
62 | }
63 | }
64 |
65 | dependencies {
66 | implementation(libs.androidx.compose.ui)
67 | implementation(libs.kotlin.collections.immutable)
68 | testImplementation(libs.androidx.compose.material3)
69 | testImplementation(libs.androidx.compose.ui.test)
70 | testImplementation(libs.androidx.compose.ui.testManifest)
71 | testImplementation(libs.androidx.test.ext)
72 | testImplementation(libs.junit4)
73 | testImplementation(libs.robolectric)
74 | androidTestImplementation(libs.androidx.compose.ui.test)
75 | androidTestImplementation(libs.androidx.compose.ui.testManifest)
76 | androidTestImplementation(libs.androidx.compose.ui.tooling)
77 | androidTestImplementation(libs.androidx.test.espresso.core)
78 | androidTestImplementation(libs.androidx.test.ext)
79 | }
--------------------------------------------------------------------------------
/gridpad/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/touchlane/gridpad-android/5ce0dcbe08cfe4cc3949b6c25454b4983e9f75c5/gridpad/consumer-rules.pro
--------------------------------------------------------------------------------
/gridpad/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.
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
--------------------------------------------------------------------------------
/gridpad/src/androidTest/java/com/touchlane/gridpad/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import androidx.test.platform.app.InstrumentationRegistry
28 | import androidx.test.ext.junit.runners.AndroidJUnit4
29 |
30 | import org.junit.Test
31 | import org.junit.runner.RunWith
32 |
33 | import org.junit.Assert.*
34 |
35 | /**
36 | * Instrumented test, which will execute on an Android device.
37 | *
38 | * See [testing documentation](http://d.android.com/tools/testing).
39 | */
40 | @RunWith(AndroidJUnit4::class)
41 | class ExampleInstrumentedTest {
42 | @Test
43 | fun useAppContext() {
44 | // Context of the app under test.
45 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
46 | assertEquals("com.touchlane.gridpad.test", appContext.packageName)
47 | }
48 | }
--------------------------------------------------------------------------------
/gridpad/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/gridpad/src/main/kotlin/com/touchlane/gridpad/GridPadCells.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import androidx.annotation.VisibleForTesting
28 | import androidx.compose.ui.unit.Dp
29 | import androidx.compose.ui.unit.dp
30 | import kotlinx.collections.immutable.ImmutableList
31 | import kotlinx.collections.immutable.toImmutableList
32 |
33 | /**
34 | * Non-modifiable class that store information about grid: rows and columns count, size information.
35 | */
36 | public data class GridPadCells(
37 | /**
38 | * Contains information about size of each row
39 | */
40 | val rowSizes: ImmutableList,
41 | /**
42 | * Contains information about size of each column
43 | */
44 | val columnSizes: ImmutableList
45 | ) {
46 | public constructor(
47 | rowSizes: Iterable, columnSizes: Iterable
48 | ) : this(rowSizes = rowSizes.toImmutableList(), columnSizes = columnSizes.toImmutableList())
49 |
50 | /**
51 | * Creating a grid with [GridPadCellSize.Weight] sizes
52 | * where [GridPadCellSize.Weight.size] equal 1.
53 | */
54 | public constructor(rowCount: Int, columnCount: Int) : this(
55 | rowSizes = GridPadCellSize.weight(rowCount),
56 | columnSizes = GridPadCellSize.weight(columnCount)
57 | )
58 |
59 | /**
60 | * Rows count. It's guaranteed that [rowCount] will be equal `rowSizes.size`
61 | */
62 | val rowCount: Int = rowSizes.size
63 |
64 | /**
65 | * Columns count. It's guaranteed that [columnCount] will be equal `columnSizes.size`
66 | */
67 | val columnCount: Int = columnSizes.size
68 |
69 | /**
70 | * Calculated total size of all rows.
71 | */
72 | internal val rowsTotalSize: TotalSize = rowSizes.calculateTotalSize()
73 |
74 | /**
75 | * Calculated total size of all columns.
76 | */
77 | internal val columnsTotalSize: TotalSize = columnSizes.calculateTotalSize()
78 |
79 | /**
80 | * @param rowCount grid row count
81 | * @param columnCount grid column count
82 | */
83 | public class Builder(rowCount: Int, columnCount: Int) {
84 |
85 | /**
86 | * List of row sizes
87 | */
88 | private val rowSizes: MutableList = GridPadCellSize.weight(rowCount)
89 |
90 | /**
91 | * List of column sizes
92 | */
93 | private val columnSizes: MutableList = GridPadCellSize.weight(columnCount)
94 |
95 | /**
96 | * Set size for specific row
97 | *
98 | * @param index index of row
99 | * @param size row's size
100 | */
101 | public fun rowSize(index: Int, size: GridPadCellSize): Builder = apply {
102 | rowSizes[index] = size
103 | }
104 |
105 | /**
106 | * Set size for all rows
107 | *
108 | * @param size rows size
109 | */
110 | public fun rowsSize(size: GridPadCellSize): Builder = apply {
111 | rowSizes.fill(size)
112 | }
113 |
114 | /**
115 | * Set size for specific column
116 | *
117 | * @param index index of column
118 | * @param size column's size
119 | */
120 | public fun columnSize(index: Int, size: GridPadCellSize): Builder = apply {
121 | columnSizes[index] = size
122 | }
123 |
124 | /**
125 | * Set size for all columns
126 | *
127 | * @param size columns size
128 | */
129 | public fun columnsSize(size: GridPadCellSize): Builder = apply {
130 | columnSizes.fill(size)
131 | }
132 |
133 | public fun build(): GridPadCells {
134 | return GridPadCells(
135 | rowSizes = rowSizes, columnSizes = columnSizes
136 | )
137 | }
138 | }
139 | }
140 |
141 | /**
142 | * Calculate the total size for the defined cell sizes list.
143 | */
144 | @VisibleForTesting
145 | internal fun Iterable.calculateTotalSize(): TotalSize {
146 | var totalWeightSize = 0f
147 | var totalFixedSize = 0f.dp
148 | forEach {
149 | when (it) {
150 | is GridPadCellSize.Weight -> totalWeightSize += it.size
151 | is GridPadCellSize.Fixed -> totalFixedSize += it.size
152 | }
153 | }
154 | return TotalSize(weight = totalWeightSize, fixed = totalFixedSize)
155 | }
156 |
157 | /**
158 | * Total size for rows or columns information.
159 | */
160 | internal data class TotalSize(
161 | /**
162 | * Total weight for all rows or columns.
163 | * Can be 0 in cases where all rows or columns have [GridPadCellSize.Fixed] size.
164 | */
165 | val weight: Float,
166 |
167 | /**
168 | * Total size for all rows or columns.
169 | * Can be 0 in cases where all rows or columns have [GridPadCellSize.Weight] size.
170 | */
171 | val fixed: Dp
172 | )
173 |
174 | /**
175 | * Class describes grid cell size
176 | */
177 | public sealed class GridPadCellSize {
178 |
179 | /**
180 | * Fixed grid cell size in Dp.
181 | *
182 | * @param size size in Dp, should be greater than 0
183 | */
184 | public data class Fixed(val size: Dp) : GridPadCellSize() {
185 | init {
186 | check(size.value > 0) { "size have to be > 0" }
187 | }
188 | }
189 |
190 | /**
191 | * Weight grid cell size.
192 | *
193 | * @param size size, should be greater than 0
194 | */
195 | public data class Weight(val size: Float = 1f) : GridPadCellSize() {
196 | init {
197 | check(size > 0) { "size have to be > 0" }
198 | }
199 | }
200 |
201 | public companion object
202 | }
203 |
204 | /**
205 | * Create a list with length [count] of fixed cell sizes with size [size] in dp.
206 | *
207 | * @param count list size
208 | * @param size size in dp
209 | */
210 | public fun GridPadCellSize.Companion.fixed(count: Int, size: Dp): MutableList {
211 | return mutableListOfElement(count, GridPadCellSize.Fixed(size = size))
212 | }
213 |
214 | /**
215 | * Create a list of fixed cell sizes with passed fixed sizes in dp.
216 | *
217 | * @param sizes array of fixed sizes in dp
218 | *
219 | * TODO: replace to vararg after fix https://youtrack.jetbrains.com/issue/KT-33565/Allow-vararg-parameter-of-inline-class-type
220 | */
221 | public fun GridPadCellSize.Companion.fixed(sizes: Array): MutableList {
222 | return sizes.map { GridPadCellSize.Fixed(size = it) }.toMutableList()
223 | }
224 |
225 | /**
226 | * Create a list with length [count] of weight cell sizes with weight size [size].
227 | *
228 | * @param count list size
229 | * @param size weight size
230 | */
231 | public fun GridPadCellSize.Companion.weight(
232 | count: Int,
233 | size: Float = 1f
234 | ): MutableList {
235 | return mutableListOfElement(count, GridPadCellSize.Weight(size = size))
236 | }
237 |
238 | /**
239 | * Create a list of weight cell sizes with passed weight sizes.
240 | *
241 | * @param sizes array of weight sizes
242 | */
243 | public fun GridPadCellSize.Companion.weight(vararg sizes: Float): MutableList {
244 | return sizes.map { GridPadCellSize.Weight(size = it) }.toMutableList()
245 | }
246 |
247 | private fun mutableListOfElement(size: Int, fillElement: T): MutableList {
248 | return (0 until size).map { fillElement }.toMutableList()
249 | }
250 |
--------------------------------------------------------------------------------
/gridpad/src/main/kotlin/com/touchlane/gridpad/GridPadDiagnosticLogger.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | /**
28 | * Used to send diagnostic signals.
29 | * Default implementation is `null` and doing nothing, to handle need to set custom
30 | * [skippingItemListener].
31 | */
32 | public object GridPadDiagnosticLogger {
33 |
34 | /**
35 | * Called when item has been skipped due to out the grid bounds.
36 | */
37 | public var skippingItemListener: ((message: String) -> Unit)? = null
38 |
39 | /**
40 | * Send skipped item signal
41 | *
42 | * @param message detailed message
43 | */
44 | internal fun onItemSkipped(message: () -> String) {
45 | skippingItemListener?.invoke(message())
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/gridpad/src/main/kotlin/com/touchlane/gridpad/GridPadItemScope.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import androidx.compose.runtime.Stable
28 |
29 | @Stable
30 | @GridPadScopeMarker
31 | public interface GridPadItemScope
32 |
--------------------------------------------------------------------------------
/gridpad/src/main/kotlin/com/touchlane/gridpad/GridPadItemScopeImpl.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | internal object GridPadItemScopeImpl : GridPadItemScope
28 |
--------------------------------------------------------------------------------
/gridpad/src/main/kotlin/com/touchlane/gridpad/GridPadPlacementPolicy.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | /**
28 | * Implicit placement policy for items.
29 | * There are two major types of settings here: the main axis of placement presented by the [mainAxis]
30 | * property and the direction of placement presented by [horizontalDirection] and [verticalDirection] properties.
31 | *
32 | * The [mainAxis] property describes which axis would be used to find the next position.
33 | * For example, [MainAxis.HORIZONTAL] means that firstly next position will look in a current row
34 | * and if there isn't a place for the item algorithm will move to the next row.
35 | *
36 | * The [horizontalDirection] property describes the direction for choosing the next item on the
37 | * horizontal axis: left or right side, depending on LTR or RTL settings.
38 | *
39 | * The [verticalDirection] property describes the direction for choosing the next item on the vertical
40 | * axis: above or below.
41 | *
42 | * @param mainAxis the main axis for selecting the next location
43 | * @param horizontalDirection horizontal placement policy
44 | * @param verticalDirection vertical placement policy
45 | */
46 | public data class GridPadPlacementPolicy(
47 | val mainAxis: MainAxis = MainAxis.HORIZONTAL,
48 | val horizontalDirection: HorizontalDirection = HorizontalDirection.START_END,
49 | val verticalDirection: VerticalDirection = VerticalDirection.TOP_BOTTOM
50 | ) {
51 | /**
52 | * Anchor for spanned cells
53 | */
54 | internal val anchor: GridPadSpanAnchor = run {
55 | val horizontalDirection = when (this.horizontalDirection) {
56 | HorizontalDirection.START_END -> GridPadSpanAnchor.Horizontal.START
57 | HorizontalDirection.END_START -> GridPadSpanAnchor.Horizontal.END
58 | }
59 | val verticalDirection = when (this.verticalDirection) {
60 | VerticalDirection.TOP_BOTTOM -> GridPadSpanAnchor.Vertical.TOP
61 | VerticalDirection.BOTTOM_TOP -> GridPadSpanAnchor.Vertical.BOTTOM
62 | }
63 | GridPadSpanAnchor(horizontalDirection, verticalDirection)
64 | }
65 |
66 | /**
67 | * Main axis of placement
68 | */
69 | public enum class MainAxis {
70 | HORIZONTAL, VERTICAL
71 | }
72 |
73 | /**
74 | * Horizontal placement policy
75 | */
76 | public enum class HorizontalDirection {
77 | START_END, END_START
78 | }
79 |
80 | /**
81 | * Vertical placement policy
82 | */
83 | public enum class VerticalDirection {
84 | TOP_BOTTOM, BOTTOM_TOP
85 | }
86 |
87 | public companion object {
88 | public val DEFAULT: GridPadPlacementPolicy = GridPadPlacementPolicy()
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/gridpad/src/main/kotlin/com/touchlane/gridpad/GridPadScopeMarker.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | /**
28 | * DSL marker.
29 | */
30 | @DslMarker
31 | public annotation class GridPadScopeMarker
32 |
--------------------------------------------------------------------------------
/gridpad/src/main/kotlin/com/touchlane/gridpad/GridPadSpanAnchor.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | /**
28 | * Anchor for spanned cells
29 | */
30 | internal data class GridPadSpanAnchor(val horizontal: Horizontal, val vertical: Vertical) {
31 |
32 | /**
33 | * Horizontal anchor position
34 | */
35 | enum class Horizontal {
36 | START, END
37 | }
38 |
39 | /**
40 | * Vertical anchor position
41 | */
42 | enum class Vertical {
43 | TOP, BOTTOM
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/gridpad/src/test/kotlin/com/touchlane/gridpad/GridPadCellsUnitTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import androidx.compose.ui.unit.dp
28 | import kotlinx.collections.immutable.toImmutableList
29 | import org.junit.Assert.assertEquals
30 | import org.junit.Assert.assertThrows
31 | import org.junit.Test
32 |
33 | /**
34 | * Tests for GridPadCells
35 | */
36 | class GridPadCellsUnitTest : LoggerTest() {
37 | @Test
38 | fun `Check equals() and hashCode() for the same GridPadCells`() {
39 | val left = GridPadCells.Builder(2, 4)
40 | .columnSize(1, GridPadCellSize.Weight(2f))
41 | .rowSize(0, GridPadCellSize.Fixed(24.dp)).build()
42 | val right = GridPadCells.Builder(2, 4)
43 | .columnSize(1, GridPadCellSize.Weight(2f))
44 | .rowSize(0, GridPadCellSize.Fixed(24.dp)).build()
45 | assertEquals(left.hashCode(), right.hashCode())
46 | assertEquals(left, right)
47 | }
48 |
49 | @Test
50 | fun `Check internal fields`() {
51 | val cells = GridPadCells.Builder(2, 4)
52 | .columnSize(0, GridPadCellSize.Fixed(12.dp))
53 | .columnSize(1, GridPadCellSize.Weight(2f))
54 | .columnSize(2, GridPadCellSize.Fixed(10.dp))
55 | .rowSize(0, GridPadCellSize.Weight(3f))
56 | .rowSize(1, GridPadCellSize.Fixed(24.dp)).build()
57 | assertEquals(2, cells.rowCount)
58 | assertEquals(4, cells.columnCount)
59 | assertEquals(24.dp, cells.rowsTotalSize.fixed)
60 | assertEquals(3f, cells.rowsTotalSize.weight)
61 | assertEquals(22.dp, cells.columnsTotalSize.fixed)
62 | assertEquals(3f, cells.rowsTotalSize.weight)
63 | assertEquals(
64 | cells.rowSizes,
65 | listOf(GridPadCellSize.Weight(3f), GridPadCellSize.Fixed(24.dp)).toImmutableList()
66 | )
67 | assertEquals(
68 | cells.columnSizes,
69 | listOf(
70 | GridPadCellSize.Fixed(12.dp),
71 | GridPadCellSize.Weight(2f),
72 | GridPadCellSize.Fixed(10.dp),
73 | GridPadCellSize.Weight(1f)
74 | ).toImmutableList()
75 | )
76 | }
77 |
78 | @Test
79 | fun `Check constructors of GridPadCells`() {
80 | val left = GridPadCells.Builder(2, 2).build()
81 | assertEquals(left, GridPadCells(rowCount = 2, columnCount = 2))
82 | assertEquals(
83 | left, GridPadCells(
84 | rowSizes = GridPadCellSize.weight(2),
85 | columnSizes = GridPadCellSize.weight(2)
86 | )
87 | )
88 | }
89 |
90 | @Test
91 | fun `Check GridPadCells_Builder methods`() {
92 | assertEquals(
93 | GridPadCells.Builder(2, 2)
94 | .rowSize(0, GridPadCellSize.Weight(3f))
95 | .rowSize(1, GridPadCellSize.Weight(3f))
96 | .columnSize(0, GridPadCellSize.Weight(2f))
97 | .columnSize(1, GridPadCellSize.Weight(2f))
98 | .build(),
99 | GridPadCells.Builder(2, 2)
100 | .rowsSize(GridPadCellSize.Weight(3f))
101 | .columnsSize(GridPadCellSize.Weight(2f))
102 | .build()
103 | )
104 | }
105 |
106 | @Test
107 | fun `Check extensions`() {
108 | assertEquals(
109 | listOf(GridPadCellSize.Fixed(1.dp), GridPadCellSize.Fixed(1.dp)),
110 | GridPadCellSize.fixed(2, 1.dp)
111 | )
112 | assertEquals(
113 | listOf(GridPadCellSize.Fixed(1.dp), GridPadCellSize.Fixed(2.dp)),
114 | GridPadCellSize.fixed(arrayOf(1.dp, 2.dp))
115 | )
116 | assertEquals(
117 | listOf(GridPadCellSize.Weight(0.5f), GridPadCellSize.Weight(0.5f)),
118 | GridPadCellSize.weight(2, 0.5f)
119 | )
120 | assertEquals(
121 | listOf(GridPadCellSize.Weight(0.5f), GridPadCellSize.Weight(1.5f)),
122 | GridPadCellSize.weight(0.5f, 1.5f)
123 | )
124 | }
125 |
126 | @Test
127 | fun `Check total size calculation`() {
128 | assertEquals(
129 | TotalSize(weight = 3f, fixed = 22.dp),
130 | listOf(
131 | GridPadCellSize.Fixed(12.dp),
132 | GridPadCellSize.Weight(2f),
133 | GridPadCellSize.Fixed(10.dp),
134 | GridPadCellSize.Weight(1f)
135 | ).calculateTotalSize()
136 | )
137 | }
138 |
139 | @Test
140 | fun `Check errors`() {
141 | assertThrows(IllegalStateException::class.java) {
142 | GridPadCellSize.Fixed(-1.dp)
143 | }
144 | assertThrows(IllegalStateException::class.java) {
145 | GridPadCellSize.Weight(0f)
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/gridpad/src/test/kotlin/com/touchlane/gridpad/GridPadDiagnosticLoggerUnitTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import org.junit.Assert.assertEquals
28 | import org.junit.Test
29 |
30 | class GridPadDiagnosticLoggerUnitTest : LoggerTest() {
31 |
32 | @Test
33 | fun `Test diagnostic logger message`() {
34 | var consumedMessage = ""
35 | val callback: (message: String) -> Unit = { message ->
36 | consumedMessage = message
37 | }
38 | GridPadDiagnosticLogger.onItemSkipped { "Message" }
39 | assertEquals("", consumedMessage)
40 | GridPadDiagnosticLogger.skippingItemListener = callback
41 | GridPadDiagnosticLogger.onItemSkipped { "Message" }
42 | assertEquals("Message", consumedMessage)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/gridpad/src/test/kotlin/com/touchlane/gridpad/GridPadPlacementPolicyUnitTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import com.touchlane.gridpad.GridPadPlacementPolicy.HorizontalDirection.END_START
28 | import com.touchlane.gridpad.GridPadPlacementPolicy.HorizontalDirection.START_END
29 | import com.touchlane.gridpad.GridPadPlacementPolicy.VerticalDirection.BOTTOM_TOP
30 | import com.touchlane.gridpad.GridPadPlacementPolicy.VerticalDirection.TOP_BOTTOM
31 | import com.touchlane.gridpad.GridPadSpanAnchor.Horizontal.END
32 | import com.touchlane.gridpad.GridPadSpanAnchor.Horizontal.START
33 | import com.touchlane.gridpad.GridPadSpanAnchor.Vertical.BOTTOM
34 | import com.touchlane.gridpad.GridPadSpanAnchor.Vertical.TOP
35 | import org.junit.Assert.assertEquals
36 | import org.junit.Test
37 |
38 | /**
39 | * Tests for GridPadPlacementPolicy
40 | */
41 | class GridPadPlacementPolicyUnitTest : LoggerTest() {
42 |
43 | @Test
44 | fun `Test anchor default initialization`() {
45 | val policy = GridPadPlacementPolicy()
46 | assertEquals(GridPadSpanAnchor(horizontal = START, vertical = TOP), policy.anchor)
47 | }
48 |
49 | @Test
50 | fun `Test anchor top start`() {
51 | val policy =
52 | GridPadPlacementPolicy(horizontalDirection = START_END, verticalDirection = TOP_BOTTOM)
53 | assertEquals(GridPadSpanAnchor(horizontal = START, vertical = TOP), policy.anchor)
54 | }
55 |
56 | @Test
57 | fun `Test anchor top end`() {
58 | val policy =
59 | GridPadPlacementPolicy(horizontalDirection = END_START, verticalDirection = TOP_BOTTOM)
60 | assertEquals(GridPadSpanAnchor(horizontal = END, vertical = TOP), policy.anchor)
61 | }
62 |
63 | @Test
64 | fun `Test anchor bottom end`() {
65 | val policy =
66 | GridPadPlacementPolicy(horizontalDirection = END_START, verticalDirection = BOTTOM_TOP)
67 | assertEquals(GridPadSpanAnchor(horizontal = END, vertical = BOTTOM), policy.anchor)
68 | }
69 |
70 | @Test
71 | fun `Test anchor bottom start`() {
72 | val policy =
73 | GridPadPlacementPolicy(horizontalDirection = START_END, verticalDirection = BOTTOM_TOP)
74 | assertEquals(GridPadSpanAnchor(horizontal = START, vertical = BOTTOM), policy.anchor)
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/gridpad/src/test/kotlin/com/touchlane/gridpad/LoggerTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.touchlane.gridpad
26 |
27 | import org.junit.Before
28 | import org.robolectric.shadows.ShadowLog
29 |
30 | open class LoggerTest {
31 |
32 | @Before
33 | @Throws(Exception::class)
34 | fun setUp() {
35 | ShadowLog.stream = System.out
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Touchlane LLC tech@touchlane.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | @file:Suppress("UnstableApiUsage")
26 |
27 | include(":gridpad")
28 |
29 |
30 | pluginManagement {
31 | includeBuild("build-logic")
32 | repositories {
33 | google()
34 | mavenCentral()
35 | gradlePluginPortal()
36 | }
37 | }
38 | dependencyResolutionManagement {
39 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
40 | repositories {
41 | google()
42 | mavenCentral()
43 | }
44 | }
45 | rootProject.name = "GridPad"
46 | include(":app")
--------------------------------------------------------------------------------