diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..7101007
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,17 @@
+# noinspection EditorConfigKeyCorrectness
+[{*.kt,*.kts}]
+ktlint_standard_annotation = disabled
+ktlint_standard_filename = disabled
+ktlint_standard_wrapping = disabled
+ktlint_standard_import-ordering = enabled
+ktlint_standard_max-line-length = disabled
+ktlint_standard_multiline-if-else = disabled
+ktlint_standard_argument-list-wrapping = disabled
+ktlint_standard_parameter-list-wrapping = disabled
+ktlint_standard_trailing-comma-on-declaration-site = disabled
+ktlint_function_signature_body_expression_wrapping = multiline
+ij_continuation_indent_size = 2
+indent_size = 4
+indent_style = space
+insert_final_newline = false
+max_line_length = 150
\ No newline at end of file
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
deleted file mode 100644
index 386c86b..0000000
--- a/.github/workflows/publish.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-# This is a basic workflow to help you get started with Actions
-
-name: Publish To Maven Central
-
-# Controls when the workflow will run
-on:
- # Triggers the workflow when tag is pushed
- push:
- tags:
- - 'v*'
-
- # Allows you to run this workflow manually from the Actions tab
- workflow_dispatch:
-
-# A workflow run is made up of one or more jobs that can run sequentially or in parallel
-jobs:
- # This workflow contains a single job called "publish"
- publish:
- # The type of runner that the job will run on
- runs-on: macos-latest
-
- # Steps represent a sequence of tasks that will be executed as part of the job
- steps:
- # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- - uses: actions/checkout@v3
- - name: Set up JDK 17
- uses: actions/setup-java@v3
- with:
- java-version: '17'
- distribution: 'temurin'
-
- # Runs a single command using the runners shell
- - name: publish
- run: ./gradlew publish --no-daemon --no-parallel
- env:
- ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
- ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
- ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }}
- ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }}
- ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_KEY_PASSWORD }}
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
deleted file mode 100644
index 370c0c3..0000000
--- a/.github/workflows/static-analysis.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-# This is a workflow to verify PRs with static code analysis tools
-name: Static Analysis
-
-# Controls when the workflow will run
-on:
- pull_request:
- branches: [main]
-
- # Allows you to run this workflow manually from the Actions tab
- workflow_dispatch:
-
-jobs:
- detekt:
- name: Detekt
- runs-on: macos-latest
-
- # Steps represent a sequence of tasks that will be executed as part of the job
- steps:
- # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- - uses: actions/checkout@v3
- - name: Set up JDK 17
- uses: actions/setup-java@v3
- with:
- java-version: '17'
- distribution: 'temurin'
-
- # Runs a single command using the runners shell
- - name: detekt
- run: ./gradlew detekt
-
- spotless:
- name: Spotless
- runs-on: macos-latest
-
- # Steps represent a sequence of tasks that will be executed as part of the job
- steps:
- # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- - uses: actions/checkout@v3
- - name: Set up JDK 17
- uses: actions/setup-java@v3
- with:
- java-version: '17'
- distribution: 'temurin'
-
- # Runs a single command using the runners shell
- - name: spotless
- run: ./gradlew spotlessCheck
diff --git a/.gitignore b/.gitignore
index e44d96a..aa724b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,15 @@
*.iml
.gradle
/local.properties
-/.idea
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
.DS_Store
-build/
+/build
/captures
.externalNativeBuild
.cxx
+local.properties
diff --git a/.idea/.gitignore b/.idea/.gitignore
index 26d3352..3ad4a12 100644
--- a/.idea/.gitignore
+++ b/.idea/.gitignore
@@ -1,3 +1,5 @@
# Default ignored files
/shelf/
-/workspace.xml
+/gradle.xml
+/misc.xml
+/workspace.xml
\ No newline at end of file
diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml
new file mode 100644
index 0000000..371f2e2
--- /dev/null
+++ b/.idea/appInsightsSettings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index 1b4dd5a..0000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,205 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- xmlns:android
-
- ^$
-
-
-
-
-
-
-
-
- xmlns:.*
-
- ^$
-
-
- BY_NAME
-
-
-
-
-
-
- .*:id
-
- http://schemas.android.com/apk/res/android
-
-
-
-
-
-
-
-
- .*:name
-
- http://schemas.android.com/apk/res/android
-
-
-
-
-
-
-
-
- name
-
- ^$
-
-
-
-
-
-
-
-
- style
-
- ^$
-
-
-
-
-
-
-
-
- .*
-
- ^$
-
-
- BY_NAME
-
-
-
-
-
-
- .*
-
- http://schemas.android.com/apk/res/android
-
-
- ANDROID_ATTRIBUTE_ORDER
-
-
-
-
-
-
- .*
-
- .*
-
-
- BY_NAME
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index 79ee123..0000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 0000000..b1d56a7
--- /dev/null
+++ b/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 10965d5..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png b/.idea/icon.png
similarity index 100%
rename from demo/src/main/res/mipmap-xxhdpi/ic_launcher.png
rename to .idea/icon.png
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..146ab09
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..f8467b4
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/ktlint.xml b/.idea/ktlint.xml
new file mode 100644
index 0000000..92c4441
--- /dev/null
+++ b/.idea/ktlint.xml
@@ -0,0 +1,6 @@
+
+
+
+ false
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index c9a2cd7..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7..35eb1dd 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 2e90b9c..da2d3fa 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,18 @@
[](https://mvnrepository.com/artifact/io.github.oleksandrbalan/pagecurl)
-
+
-# Page Curl
+# Page Curl (Multiplatform)
-Page Curl library for Jetpack Compose.
+Page Curl library for Jetpack Compose Multiplatform.
+
+Support for Android, iOS, Desktop (JVM):
+
+
+
+> Note
+
+This is just an attempt at multiplatform porting, and there may still be some problems.
## Motivation
@@ -12,122 +20,19 @@ This library allows to create an effect of turning pages, which can be used in b
## Usage
-### Get a dependency
+> Note
-**Step 1.** Add the MavenCentral repository to your build file.
-Add it in your root `build.gradle.kts` at the end of repositories:
-```kotlin
-allprojects {
- repositories {
- ...
- mavenCentral()
- }
-}
-```
+This multiplatform library's artifact is not upload to any repositories,
+you can clone this repository or use git submodule to use it.
-Or in `settings.gradle.kts`:
-```kotlin
-pluginManagement {
- repositories {
- ...
- mavenCentral()
- }
-}
-```
+For an Android version and a sample usage, please visit: https://github.com/oleksandrbalan/pagecurl.
-**Step 2.** Add the dependency.
-Check latest version on the [releases page](https://github.com/oleksandrbalan/pagecurl/releases).
-```kotlin
-dependencies {
- implementation("io.github.oleksandrbalan:pagecurl:$version")
-}
-```
+See Demo application
+and [examples](https://github.com/fankes/pagecurl/blob/multiplatform/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens) for more usage
+examples.
-### Use in Composable
+## Thanks
-The `PageCurl` has 2 mandatory arguments:
-* **count** - The count of pages.
-* **content** - The content lambda to provide the page composable. Receives the page number.
+[The compose multiplatform shadows way](https://github.com/oleksandrbalan/pagecurl/issues/23#issuecomment-1767145310)
-```
-val pages = listOf("One", "Two", "Three")
-PageCurl(count = pages.size) { index ->
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier
- .background(MaterialTheme.colors.background)
- .fillMaxSize()
- ) {
- Text(
- text = pages[index],
- style = MaterialTheme.typography.h1,
- )
- }
-}
-```
-
-Optionally `state` could be provided to observe and manage PageCurl state.
-* **state** - The state of the PageCurl. Use it to programmatically change the current page or observe changes, and to configure shadow, back-page and interactions.
-```
-Column {
- val scope = rememberCoroutineScope()
- val state = rememberPageCurlState()
- Button(onClick = { scope.launch { state.next() } }) {
- Text(text = "Next")
- }
-
- val pages = listOf("One", "Two", "Three")
- PageCurl(
- count = pages.size,
- state = state,
- ) { index ->
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier
- .background(MaterialTheme.colors.background)
- .fillMaxSize()
- ) {
- Text(
- text = pages[index],
- style = MaterialTheme.typography.h1,
- )
- }
- }
-}
-```
-
-Optionally `key` lambda could be provided with stable key for each item. PageCurl with keys for each page will correctly preserve a current position when items are added or removed.
-* **key** - The lambda to provide stable key for each item. Useful when adding and removing items before current page.
-```
-Column {
- var pages by remember { mutableStateOf(listOf("Four", "Five", "Six")) }
- Button(onClick = { pages = listOf("One", "Two", "Three") + pages }) {
- Text(text = "Prepend new pages")
- }
-
- PageCurl(
- count = pages.size,
- key = { pages[it].hashCode() },
- ) { index ->
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier
- .background(MaterialTheme.colors.background)
- .fillMaxSize()
- ) {
- Text(
- text = pages[index],
- style = MaterialTheme.typography.h1,
- )
- }
- }
-}
-```
-
-See Demo application and [examples](demo/src/main/kotlin/eu/wewox/pagecurl/screens) for more usage examples.
-
-https://user-images.githubusercontent.com/20944869/185782671-2861c2ed-c033-4318-bf12-1d8db74fc8b5.mp4
-
-https://user-images.githubusercontent.com/20944869/185782668-b52da2b9-be8d-49db-8729-88b6f9a8ee48.mp4
-
-https://user-images.githubusercontent.com/20944869/185782663-4bd97a57-1a46-408d-a07b-34c193f01aba.mp4
+[Multiplatform Paging](https://github.com/cashapp/multiplatform-paging)
\ No newline at end of file
diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
deleted file mode 100644
index a21a774..0000000
--- a/build-logic/convention/build.gradle.kts
+++ /dev/null
@@ -1,19 +0,0 @@
-plugins {
- `kotlin-dsl`
-}
-
-java {
- toolchain {
- val version = libs.versions.java.toolchain.get()
- languageVersion.set(JavaLanguageVersion.of(version))
- }
-}
-
-gradlePlugin {
- plugins {
- register("conventionJvmToolchain") {
- id = "convention.jvm.toolchain"
- implementationClass = "JvmToolchainConventionPlugin"
- }
- }
-}
diff --git a/build-logic/convention/src/main/kotlin/JvmToolchainConventionPlugin.kt b/build-logic/convention/src/main/kotlin/JvmToolchainConventionPlugin.kt
deleted file mode 100644
index 8ee9599..0000000
--- a/build-logic/convention/src/main/kotlin/JvmToolchainConventionPlugin.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.plugins.JavaPluginExtension
-import org.gradle.jvm.toolchain.JavaLanguageVersion
-import org.gradle.kotlin.dsl.configure
-import utils.libs
-
-class JvmToolchainConventionPlugin : Plugin {
- override fun apply(target: Project) =
- with(target) {
- extensions.configure {
- toolchain {
- val version = libs.findVersion("java-toolchain").get().displayName
- languageVersion.set(JavaLanguageVersion.of(version))
- }
- }
- }
-}
diff --git a/build-logic/convention/src/main/kotlin/utils/ProjectExtensions.kt b/build-logic/convention/src/main/kotlin/utils/ProjectExtensions.kt
deleted file mode 100644
index 3b0a623..0000000
--- a/build-logic/convention/src/main/kotlin/utils/ProjectExtensions.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package utils
-
-import org.gradle.api.Project
-import org.gradle.api.artifacts.VersionCatalog
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.kotlin.dsl.getByType
-
-val Project.libs: VersionCatalog
- get() = extensions.getByType().named("libs")
diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts
deleted file mode 100644
index c97f8ca..0000000
--- a/build-logic/settings.gradle.kts
+++ /dev/null
@@ -1,18 +0,0 @@
-dependencyResolutionManagement {
- repositories {
- google()
- mavenCentral()
- }
- versionCatalogs {
- create("libs") {
- from(files("../gradle/libs.versions.toml"))
- }
- }
-}
-
-plugins {
- id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0")
-}
-
-rootProject.name = "build-logic"
-include(":convention")
diff --git a/build.gradle.kts b/build.gradle.kts
index 78f7c3a..19264c6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,23 +1,6 @@
-import com.diffplug.gradle.spotless.SpotlessPlugin
-import io.gitlab.arturbosch.detekt.DetektPlugin
-
plugins {
- alias(libs.plugins.android.application) apply false
- alias(libs.plugins.android.library) apply false
- alias(libs.plugins.kotlin) apply false
- alias(libs.plugins.detekt)
- alias(libs.plugins.spotless)
- alias(libs.plugins.mavenpublish)
-}
-
-configure(subprojects) {
- apply()
- apply()
-
- spotless {
- kotlin {
- target("**/*.kt")
- ktlint("0.43.2")
- }
- }
-}
+ autowire(libs.plugins.kotlin.multiplatform) apply false
+ autowire(libs.plugins.android.application) apply false
+ autowire(libs.plugins.android.library) apply false
+ autowire(libs.plugins.jetbrains.compose) apply false
+}
\ No newline at end of file
diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml
deleted file mode 100644
index 4dbb501..0000000
--- a/config/detekt/detekt.yml
+++ /dev/null
@@ -1,684 +0,0 @@
-build:
- maxIssues: 0
- excludeCorrectable: false
- weights:
- # complexity: 2
- # LongParameterList: 1
- # style: 1
- # comments: 1
-
-config:
- validation: true
- warningsAsErrors: false
- # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]'
- excludes: ''
-
-processors:
- active: true
- exclude:
- - 'DetektProgressListener'
- # - 'KtFileCountProcessor'
- # - 'PackageCountProcessor'
- # - 'ClassCountProcessor'
- # - 'FunctionCountProcessor'
- # - 'PropertyCountProcessor'
- # - 'ProjectComplexityProcessor'
- # - 'ProjectCognitiveComplexityProcessor'
- # - 'ProjectLLOCProcessor'
- # - 'ProjectCLOCProcessor'
- # - 'ProjectLOCProcessor'
- # - 'ProjectSLOCProcessor'
- # - 'LicenseHeaderLoaderExtension'
-
-console-reports:
- active: true
- exclude:
- - 'ProjectStatisticsReport'
- - 'ComplexityReport'
- - 'NotificationReport'
- - 'FindingsReport'
- - 'FileBasedFindingsReport'
- # - 'LiteFindingsReport'
-
-output-reports:
- active: true
- exclude:
- # - 'TxtOutputReport'
- # - 'XmlOutputReport'
- # - 'HtmlOutputReport'
-
-comments:
- active: true
- AbsentOrWrongFileLicense:
- active: false
- licenseTemplateFile: 'license.template'
- licenseTemplateIsRegex: false
- CommentOverPrivateFunction:
- active: false
- CommentOverPrivateProperty:
- active: false
- DeprecatedBlockTag:
- active: false
- EndOfSentenceFormat:
- active: false
- endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)'
- OutdatedDocumentation:
- active: false
- matchTypeParameters: true
- matchDeclarationsOrder: true
- allowParamOnConstructorProperties: false
- UndocumentedPublicClass:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- searchInNestedClass: true
- searchInInnerClass: true
- searchInInnerObject: true
- searchInInnerInterface: true
- UndocumentedPublicFunction:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- UndocumentedPublicProperty:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
-
-complexity:
- active: true
- ComplexCondition:
- active: true
- threshold: 4
- ComplexInterface:
- active: false
- threshold: 10
- includeStaticDeclarations: false
- includePrivateDeclarations: false
- ComplexMethod:
- active: true
- threshold: 15
- ignoreSingleWhenExpression: false
- ignoreSimpleWhenEntries: false
- ignoreNestingFunctions: false
- nestingFunctions:
- - 'also'
- - 'apply'
- - 'forEach'
- - 'isNotNull'
- - 'ifNull'
- - 'let'
- - 'run'
- - 'use'
- - 'with'
- LabeledExpression:
- active: false
- ignoredLabels: []
- LargeClass:
- active: true
- threshold: 600
- LongMethod:
- active: true
- threshold: 60
- LongParameterList:
- active: true
- functionThreshold: 10
- constructorThreshold: 7
- ignoreDefaultParameters: false
- ignoreDataClasses: true
- ignoreAnnotated: [ 'Composable' ]
- ignoreAnnotatedParameter: []
- MethodOverloading:
- active: false
- threshold: 6
- NamedArguments:
- active: false
- threshold: 3
- ignoreArgumentsMatchingNames: false
- NestedBlockDepth:
- active: true
- threshold: 4
- ReplaceSafeCallChainWithRun:
- active: false
- StringLiteralDuplication:
- active: false
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- threshold: 3
- ignoreAnnotation: true
- excludeStringsWithLessThan5Characters: true
- ignoreStringsRegex: '$^'
- TooManyFunctions:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- thresholdInFiles: 11
- thresholdInClasses: 11
- thresholdInInterfaces: 11
- thresholdInObjects: 11
- thresholdInEnums: 11
- ignoreDeprecated: false
- ignorePrivate: false
- ignoreOverridden: false
-
-coroutines:
- active: true
- GlobalCoroutineUsage:
- active: false
- InjectDispatcher:
- active: false
- dispatcherNames:
- - 'IO'
- - 'Default'
- - 'Unconfined'
- RedundantSuspendModifier:
- active: false
- SleepInsteadOfDelay:
- active: false
- SuspendFunWithCoroutineScopeReceiver:
- active: false
- SuspendFunWithFlowReturnType:
- active: false
-
-empty-blocks:
- active: true
- EmptyCatchBlock:
- active: true
- allowedExceptionNameRegex: '_|(ignore|expected).*'
- EmptyClassBlock:
- active: true
- EmptyDefaultConstructor:
- active: true
- EmptyDoWhileBlock:
- active: true
- EmptyElseBlock:
- active: true
- EmptyFinallyBlock:
- active: true
- EmptyForBlock:
- active: true
- EmptyFunctionBlock:
- active: true
- ignoreOverridden: false
- EmptyIfBlock:
- active: true
- EmptyInitBlock:
- active: true
- EmptyKtFile:
- active: true
- EmptySecondaryConstructor:
- active: true
- EmptyTryBlock:
- active: true
- EmptyWhenBlock:
- active: true
- EmptyWhileBlock:
- active: true
-
-exceptions:
- active: true
- ExceptionRaisedInUnexpectedLocation:
- active: true
- methodNames:
- - 'equals'
- - 'finalize'
- - 'hashCode'
- - 'toString'
- InstanceOfCheckForException:
- active: false
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- NotImplementedDeclaration:
- active: false
- ObjectExtendsThrowable:
- active: false
- PrintStackTrace:
- active: true
- RethrowCaughtException:
- active: true
- ReturnFromFinally:
- active: true
- ignoreLabeled: false
- SwallowedException:
- active: true
- ignoredExceptionTypes:
- - 'InterruptedException'
- - 'MalformedURLException'
- - 'NumberFormatException'
- - 'ParseException'
- allowedExceptionNameRegex: '_|(ignore|expected).*'
- ThrowingExceptionFromFinally:
- active: true
- ThrowingExceptionInMain:
- active: false
- ThrowingExceptionsWithoutMessageOrCause:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- exceptions:
- - 'ArrayIndexOutOfBoundsException'
- - 'Exception'
- - 'IllegalArgumentException'
- - 'IllegalMonitorStateException'
- - 'IllegalStateException'
- - 'IndexOutOfBoundsException'
- - 'NullPointerException'
- - 'RuntimeException'
- - 'Throwable'
- ThrowingNewInstanceOfSameException:
- active: true
- TooGenericExceptionCaught:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- exceptionNames:
- - 'ArrayIndexOutOfBoundsException'
- - 'Error'
- - 'Exception'
- - 'IllegalMonitorStateException'
- - 'IndexOutOfBoundsException'
- - 'NullPointerException'
- - 'RuntimeException'
- - 'Throwable'
- allowedExceptionNameRegex: '_|(ignore|expected).*'
- TooGenericExceptionThrown:
- active: true
- exceptionNames:
- - 'Error'
- - 'Exception'
- - 'RuntimeException'
- - 'Throwable'
-
-naming:
- active: true
- BooleanPropertyNaming:
- active: false
- allowedPattern: '^(is|has|are)'
- ignoreOverridden: true
- ClassNaming:
- active: true
- classPattern: '[A-Z][a-zA-Z0-9]*'
- ConstructorParameterNaming:
- active: true
- parameterPattern: '[a-z][A-Za-z0-9]*'
- privateParameterPattern: '[a-z][A-Za-z0-9]*'
- excludeClassPattern: '$^'
- ignoreOverridden: true
- EnumNaming:
- active: true
- enumEntryPattern: '[A-Z][_a-zA-Z0-9]*'
- ForbiddenClassName:
- active: false
- forbiddenName: []
- FunctionMaxLength:
- active: false
- maximumFunctionNameLength: 30
- FunctionMinLength:
- active: false
- minimumFunctionNameLength: 3
- FunctionNaming:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- functionPattern: '[a-z][a-zA-Z0-9]*'
- excludeClassPattern: '$^'
- ignoreOverridden: true
- ignoreAnnotated: [ 'Composable' ]
- FunctionParameterNaming:
- active: true
- parameterPattern: '[a-z][A-Za-z0-9]*'
- excludeClassPattern: '$^'
- ignoreOverridden: true
- InvalidPackageDeclaration:
- active: false
- rootPackage: ''
- requireRootInDeclaration: false
- LambdaParameterNaming:
- active: false
- parameterPattern: '[a-z][A-Za-z0-9]*|_'
- MatchingDeclarationName:
- active: true
- mustBeFirst: true
- MemberNameEqualsClassName:
- active: true
- ignoreOverridden: true
- NoNameShadowing:
- active: false
- NonBooleanPropertyPrefixedWithIs:
- active: false
- ObjectPropertyNaming:
- active: true
- constantPattern: '[A-Za-z][_A-Za-z0-9]*'
- propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
- privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'
- PackageNaming:
- active: true
- packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*'
- TopLevelPropertyNaming:
- active: true
- constantPattern: '[A-Z][A-Za-z0-9]*'
- propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
- privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*'
- VariableMaxLength:
- active: false
- maximumVariableNameLength: 64
- VariableMinLength:
- active: false
- minimumVariableNameLength: 1
- VariableNaming:
- active: true
- variablePattern: '[a-z][A-Za-z0-9]*'
- privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'
- excludeClassPattern: '$^'
- ignoreOverridden: true
-
-performance:
- active: true
- ArrayPrimitive:
- active: true
- ForEachOnRange:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- SpreadOperator:
- active: false
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- UnnecessaryTemporaryInstantiation:
- active: true
-
-potential-bugs:
- active: true
- AvoidReferentialEquality:
- active: false
- forbiddenTypePatterns:
- - 'kotlin.String'
- CastToNullableType:
- active: false
- Deprecation:
- active: false
- DontDowncastCollectionTypes:
- active: false
- DoubleMutabilityForCollection:
- active: false
- mutableTypes:
- - 'kotlin.collections.MutableList'
- - 'kotlin.collections.MutableMap'
- - 'kotlin.collections.MutableSet'
- - 'java.util.ArrayList'
- - 'java.util.LinkedHashSet'
- - 'java.util.HashSet'
- - 'java.util.LinkedHashMap'
- - 'java.util.HashMap'
- DuplicateCaseInWhenExpression:
- active: true
- ElseCaseInsteadOfExhaustiveWhen:
- active: false
- EqualsAlwaysReturnsTrueOrFalse:
- active: true
- EqualsWithHashCodeExist:
- active: true
- ExitOutsideMain:
- active: false
- ExplicitGarbageCollectionCall:
- active: true
- HasPlatformType:
- active: false
- IgnoredReturnValue:
- active: false
- restrictToAnnotatedMethods: true
- returnValueAnnotations:
- - '*.CheckResult'
- - '*.CheckReturnValue'
- ignoreReturnValueAnnotations:
- - '*.CanIgnoreReturnValue'
- ignoreFunctionCall: []
- ImplicitDefaultLocale:
- active: true
- ImplicitUnitReturnType:
- active: false
- allowExplicitReturnType: true
- InvalidRange:
- active: true
- IteratorHasNextCallsNextMethod:
- active: true
- IteratorNotThrowingNoSuchElementException:
- active: true
- LateinitUsage:
- active: false
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- ignoreOnClassesPattern: ''
- MapGetWithNotNullAssertionOperator:
- active: false
- MissingPackageDeclaration:
- active: false
- excludes: ['**/*.kts']
- MissingWhenCase:
- active: true
- allowElseExpression: true
- NullCheckOnMutableProperty:
- active: false
- NullableToStringCall:
- active: false
- RedundantElseInWhen:
- active: true
- UnconditionalJumpStatementInLoop:
- active: false
- UnnecessaryNotNullOperator:
- active: true
- UnnecessarySafeCall:
- active: true
- UnreachableCatchBlock:
- active: false
- UnreachableCode:
- active: true
- UnsafeCallOnNullableType:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- UnsafeCast:
- active: true
- UnusedUnaryOperator:
- active: false
- UselessPostfixExpression:
- active: false
- WrongEqualsTypeParameter:
- active: true
-
-style:
- active: true
- CanBeNonNullable:
- active: false
- ClassOrdering:
- active: false
- CollapsibleIfStatements:
- active: false
- DataClassContainsFunctions:
- active: false
- conversionFunctionPrefix: 'to'
- DataClassShouldBeImmutable:
- active: false
- DestructuringDeclarationWithTooManyEntries:
- active: false
- maxDestructuringEntries: 3
- EqualsNullCall:
- active: true
- EqualsOnSignatureLine:
- active: false
- ExplicitCollectionElementAccessMethod:
- active: false
- ExplicitItLambdaParameter:
- active: false
- ExpressionBodySyntax:
- active: false
- includeLineWrapping: false
- ForbiddenComment:
- active: true
- values:
- - 'FIXME:'
- - 'STOPSHIP:'
- - 'TODO:'
- allowedPatterns: ''
- customMessage: ''
- ForbiddenImport:
- active: false
- imports: []
- forbiddenPatterns: ''
- ForbiddenMethodCall:
- active: false
- methods:
- - 'kotlin.io.print'
- - 'kotlin.io.println'
- ForbiddenPublicDataClass:
- active: true
- excludes: ['**']
- ignorePackages:
- - '*.internal'
- - '*.internal.*'
- ForbiddenVoid:
- active: false
- ignoreOverridden: false
- ignoreUsageInGenerics: false
- FunctionOnlyReturningConstant:
- active: true
- ignoreOverridableFunction: true
- ignoreActualFunction: true
- excludedFunctions: ''
- LibraryCodeMustSpecifyReturnType:
- active: true
- excludes: ['**']
- LibraryEntitiesShouldNotBePublic:
- active: true
- excludes: ['**']
- LoopWithTooManyJumpStatements:
- active: true
- maxJumpCount: 1
- MagicNumber:
- active: false
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- ignoreNumbers:
- - '-1'
- - '0'
- - '1'
- - '2'
- ignoreHashCodeFunction: true
- ignorePropertyDeclaration: false
- ignoreLocalVariableDeclaration: false
- ignoreConstantDeclaration: true
- ignoreCompanionObjectPropertyDeclaration: true
- ignoreAnnotation: false
- ignoreNamedArgument: true
- ignoreEnums: false
- ignoreRanges: false
- ignoreExtensionFunctions: true
- MandatoryBracesIfStatements:
- active: false
- MandatoryBracesLoops:
- active: false
- MaxLineLength:
- active: true
- maxLineLength: 120
- excludePackageStatements: true
- excludeImportStatements: true
- excludeCommentStatements: false
- MayBeConst:
- active: true
- ModifierOrder:
- active: true
- MultilineLambdaItParameter:
- active: false
- NestedClassesVisibility:
- active: true
- NewLineAtEndOfFile:
- active: true
- NoTabs:
- active: false
- ObjectLiteralToLambda:
- active: false
- OptionalAbstractKeyword:
- active: true
- OptionalUnit:
- active: false
- OptionalWhenBraces:
- active: false
- PreferToOverPairSyntax:
- active: false
- ProtectedMemberInFinalClass:
- active: true
- RedundantExplicitType:
- active: false
- RedundantHigherOrderMapUsage:
- active: false
- RedundantVisibilityModifierRule:
- active: false
- ReturnCount:
- active: true
- max: 2
- excludedFunctions: 'equals'
- excludeLabeled: false
- excludeReturnFromLambda: true
- excludeGuardClauses: false
- SafeCast:
- active: true
- SerialVersionUIDInSerializableClass:
- active: true
- SpacingBetweenPackageAndImports:
- active: false
- ThrowsCount:
- active: true
- max: 2
- excludeGuardClauses: false
- TrailingWhitespace:
- active: false
- UnderscoresInNumericLiterals:
- active: false
- acceptableLength: 4
- allowNonStandardGrouping: false
- UnnecessaryAbstractClass:
- active: true
- UnnecessaryAnnotationUseSiteTarget:
- active: false
- UnnecessaryApply:
- active: true
- UnnecessaryFilter:
- active: false
- UnnecessaryInheritance:
- active: true
- UnnecessaryInnerClass:
- active: false
- UnnecessaryLet:
- active: false
- UnnecessaryParentheses:
- active: false
- UntilInsteadOfRangeTo:
- active: false
- UnusedImports:
- active: false
- UnusedPrivateClass:
- active: true
- UnusedPrivateMember:
- active: true
- allowedNames: '(_|ignored|expected|serialVersionUID)'
- UseAnyOrNoneInsteadOfFind:
- active: false
- UseArrayLiteralsInAnnotations:
- active: false
- UseCheckNotNull:
- active: false
- UseCheckOrError:
- active: false
- UseDataClass:
- active: false
- allowVars: false
- UseEmptyCounterpart:
- active: false
- UseIfEmptyOrIfBlank:
- active: false
- UseIfInsteadOfWhen:
- active: false
- UseIsNullOrEmpty:
- active: false
- UseOrEmpty:
- active: false
- UseRequire:
- active: false
- UseRequireNotNull:
- active: false
- UselessCallOnNotNull:
- active: true
- UtilityClassWithPublicConstructor:
- active: true
- VarCouldBeVal:
- active: true
- WildcardImport:
- active: true
- excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
- excludeImports:
- - 'java.util.*'
diff --git a/demo/build.gradle.kts b/demo/build.gradle.kts
deleted file mode 100644
index 0fee587..0000000
--- a/demo/build.gradle.kts
+++ /dev/null
@@ -1,61 +0,0 @@
-plugins {
- alias(libs.plugins.android.application)
- alias(libs.plugins.kotlin)
- id("convention.jvm.toolchain")
-}
-
-android {
- namespace = "eu.wewox.pagecurl"
-
- compileSdk = libs.versions.sdk.compile.get().toInt()
-
- defaultConfig {
- applicationId = "eu.wewox.pagecurl"
-
- minSdk = libs.versions.sdk.min.get().toInt()
- targetSdk = libs.versions.sdk.target.get().toInt()
-
- versionCode = 1
- versionName = "1.0"
-
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- buildFeatures {
- compose = true
- }
- composeOptions {
- kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
- }
- kotlinOptions {
- freeCompilerArgs = freeCompilerArgs +
- "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api"
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
-}
-
-dependencies {
- implementation(project(":pagecurl"))
-
- implementation(platform(libs.compose.bom))
- implementation(libs.compose.material3)
- implementation(libs.compose.ui)
- implementation(libs.androidx.activitycompose)
- implementation(libs.androidx.pagingruntime)
- implementation(libs.androidx.pagingcompose)
-}
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/MainActivity.kt b/demo/src/main/kotlin/eu/wewox/pagecurl/MainActivity.kt
deleted file mode 100644
index db56fb0..0000000
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/MainActivity.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-package eu.wewox.pagecurl
-
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.BackHandler
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.compose.animation.Crossfade
-import androidx.compose.foundation.layout.safeDrawingPadding
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.core.view.WindowCompat
-import eu.wewox.pagecurl.screens.BackPagePageCurlScreen
-import eu.wewox.pagecurl.screens.InteractionConfigInPageCurlScreen
-import eu.wewox.pagecurl.screens.PagingPageCurlScreen
-import eu.wewox.pagecurl.screens.SettingsPageCurlScreen
-import eu.wewox.pagecurl.screens.ShadowInPageCurlScreen
-import eu.wewox.pagecurl.screens.SimplePageCurlScreen
-import eu.wewox.pagecurl.screens.StateInPageCurlScreen
-import eu.wewox.pagecurl.ui.theme.PageCurlTheme
-
-/**
- * Main activity for demo application.
- * Contains simple "Crossfade" based navigation to various examples.
- */
-class MainActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
-
- WindowCompat.setDecorFitsSystemWindows(window, false)
-
- setContent {
- PageCurlTheme {
- var example by rememberSaveable { mutableStateOf(null) }
-
- BackHandler(enabled = example != null) {
- example = null
- }
-
- Surface(color = MaterialTheme.colorScheme.background) {
- Crossfade(targetState = example, Modifier.safeDrawingPadding(), label = "Crossfade") { selected ->
- when (selected) {
- null -> RootScreen(onExampleClick = { example = it })
- Example.SimplePageCurl -> SimplePageCurlScreen()
- Example.PagingPageCurl -> PagingPageCurlScreen()
- Example.SettingsPageCurl -> SettingsPageCurlScreen()
- Example.StateInPageCurl -> StateInPageCurlScreen()
- Example.InteractionConfigInPageCurl -> InteractionConfigInPageCurlScreen()
- Example.ShadowPageCurl -> ShadowInPageCurlScreen()
- Example.BackPagePageCurl -> BackPagePageCurlScreen()
- }
- }
- }
- }
- }
- }
-}
diff --git a/gradle.properties b/gradle.properties
index 754d361..7b94f5d 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,48 +1,21 @@
-# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
+# Compiler Configuration
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-# AndroidX package structure to make it clearer which packages are bundled with the
-# Android operating system, and which are packaged with your app"s APK
-# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
-# Kotlin code style for this project: "official" or "obsolete":
-kotlin.code.style=official
-# Enables namespacing of each library's R class so that its R class includes only the
-# resources declared in the library itself and none from the library's dependencies,
-# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
-
-# Maven setup with https://github.com/vanniktech/gradle-maven-publish-plugin
-SONATYPE_HOST=S01
-RELEASE_SIGNING_ENABLED=true
-
-GROUP=io.github.oleksandrbalan
-POM_ARTIFACT_ID=pagecurl
-VERSION_NAME=1.4.1
-
-POM_NAME=Page Curl
-POM_DESCRIPTION=This library allows to create an effect of turning pages, which can be used in book reader applications, custom on-boarding screens or elsewhere.
-POM_INCEPTION_YEAR=2022
-POM_URL=https://github.com/oleksandrbalan/pagecurl
-
-POM_LICENSE_NAME=The Apache Software License, Version 2.0
-POM_LICENSE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
-POM_LICENSE_DIST=repo
-
-POM_SCM_URL=https://github.com/oleksandrbalan/pagecurl
-POM_SCM_CONNECTION=scm:git:git://github.com/oleksandrbalan/pagecurl.git
-POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/oleksandrbalan/pagecurl.git
-
-POM_DEVELOPER_ID=oleksandrbalan
-POM_DEVELOPER_NAME=Oleksandr Balan
-POM_DEVELOPER_URL=https://github.com/oleksandrbalan
+kotlin.code.style=official
+kotlin.incremental.useClasspathSnapshot=true
+org.jetbrains.compose.experimental.uikit.enabled=true
+# Project Configuration
+project.name=pagecurl-multiplatform
+project.description=Page Curl library for Jetpack Compose Multiplatform.
+project.url=https://github.com/fankes/pagecurl-multiplatform
+project.groupName=eu.wewox.pagecurl
+project.moduleName=pagecurl-multiplatform
+project.version="1.4.1"
+project.licence.name=Apache License 2.0
+project.licence.url=https://github.com/fankes/pagecurl-multiplatform/blob/master/LICENSE
+project.android.compileSdk=34
+project.android.minSdk=21
+project.android.targetSdk=34
+project.samples.androidApp.versionName=universal
+project.samples.androidApp.versionCode=1
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
deleted file mode 100644
index 579ffb2..0000000
--- a/gradle/libs.versions.toml
+++ /dev/null
@@ -1,34 +0,0 @@
-[versions]
-sdk-compile = "34"
-sdk-min = "21"
-sdk-target = "33"
-
-compose-bom = "2023.09.00"
-compose-compiler = "1.5.3"
-activity-compose = "1.8.0-beta01"
-paging = "3.2.1"
-
-plugin-android-gradle = "8.1.1"
-plugin-kotlin = "1.9.10"
-plugin-detekt = "1.21.0"
-plugin-spotless = "6.5.1"
-plugin-mavenpublish = "0.25.3"
-
-java-toolchain = "17"
-
-[libraries]
-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose-bom" }
-compose-foundation = { module = "androidx.compose.foundation:foundation" }
-compose-material3 = { module = "androidx.compose.material3:material3" }
-compose-ui = { module = "androidx.compose.ui:ui" }
-androidx-activitycompose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" }
-androidx-pagingruntime = { module = "androidx.paging:paging-runtime", version.ref = "paging" }
-androidx-pagingcompose = { module = "androidx.paging:paging-compose", version.ref = "paging" }
-
-[plugins]
-android-application = { id = "com.android.application", version.ref = "plugin-android-gradle" }
-android-library = { id = "com.android.library", version.ref = "plugin-android-gradle" }
-kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "plugin-kotlin" }
-detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "plugin-detekt" }
-spotless = { id = "com.diffplug.spotless", version.ref = "plugin-spotless" }
-mavenpublish = { id = "com.vanniktech.maven.publish", version.ref = "plugin-mavenpublish" }
diff --git a/gradle/sweet-dependency/sweet-dependency-config.yaml b/gradle/sweet-dependency/sweet-dependency-config.yaml
new file mode 100644
index 0000000..b020053
--- /dev/null
+++ b/gradle/sweet-dependency/sweet-dependency-config.yaml
@@ -0,0 +1,65 @@
+preferences:
+ autowire-on-sync-mode: UPDATE_OPTIONAL_DEPENDENCIES
+ repositories-mode: FAIL_ON_PROJECT_REPOS
+
+repositories:
+ gradle-plugin-portal:
+ scope: PLUGINS
+ google:
+ maven-central:
+
+plugins:
+ org.jetbrains.kotlin.multiplatform:
+ alias: kotlin-multiplatform
+ version: 1.9.10
+ org.jetbrains.compose:
+ alias: jetbrains-compose
+ version: 1.5.1
+ com.android.application:
+ alias: android-application
+ version: 8.1.2
+ com.android.library:
+ alias: android-library
+ version-ref: android-application
+
+libraries:
+ app.cash.paging:
+ paging-common:
+ version: 3.3.0-alpha02-0.4.0
+ paging-compose-common:
+ version-ref: ::paging-common
+ androidx.compose:
+ compose-bom:
+ version: 2023.09.02
+ androidx.compose.foundation:
+ foundation:
+ version:
+ androidx.compose.ui:
+ ui:
+ version:
+ androidx.compose.material3:
+ material3:
+ version:
+ androidx.activity:
+ activity:
+ version: 1.8.0
+ activity-compose:
+ version: 1.7.2
+ androidx.core:
+ core-ktx:
+ version: 1.10.0
+ androidx.appcompat:
+ appcompat:
+ version: 1.6.1
+ com.google.android.material:
+ material:
+ version: 1.8.0
+ androidx.test.ext:
+ junit:
+ version: 1.1.5
+ androidx.test.espresso:
+ espresso-core:
+ version: 3.5.1
+ junit:
+ junit:
+ version: 4.13.2
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 3e49027..692fc5c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Wed Sep 06 22:11:14 CEST 2023
distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
-zipStoreBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
\ No newline at end of file
diff --git a/gradlew.bat b/gradlew.bat
index ac1b06f..107acd3 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,89 +1,89 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/pagecurl/build.gradle.kts b/pagecurl/build.gradle.kts
index 1a22fd1..d842e04 100644
--- a/pagecurl/build.gradle.kts
+++ b/pagecurl/build.gradle.kts
@@ -1,32 +1,65 @@
plugins {
- alias(libs.plugins.android.library)
- alias(libs.plugins.kotlin)
- alias(libs.plugins.mavenpublish)
- id("convention.jvm.toolchain")
+ autowire(libs.plugins.kotlin.multiplatform)
+ autowire(libs.plugins.android.library)
+ autowire(libs.plugins.jetbrains.compose)
+}
+
+group = property.project.groupName
+
+kotlin {
+ androidTarget()
+ jvm("desktop")
+ iosX64()
+ iosArm64()
+ iosSimulatorArm64()
+ jvmToolchain(17)
+ sourceSets {
+ all {
+ languageSettings {
+ optIn("kotlinx.cinterop.ExperimentalForeignApi")
+ }
+ }
+ val commonMain by getting {
+ dependencies {
+ implementation(compose.runtime)
+ implementation(compose.foundation)
+ implementation(compose.material3)
+ }
+ }
+ val androidMain by getting
+ val desktopMain by getting {
+ dependencies {
+ implementation(compose.desktop.currentOs)
+ }
+ }
+ val iosX64Main by getting
+ val iosArm64Main by getting
+ val iosSimulatorArm64Main by getting
+ val iosMain by creating {
+ dependsOn(commonMain)
+ iosX64Main.dependsOn(this)
+ iosArm64Main.dependsOn(this)
+ iosSimulatorArm64Main.dependsOn(this)
+ }
+ }
}
android {
- namespace = "eu.wewox.pagecurl"
+ namespace = property.project.groupName
+ compileSdk = property.project.android.compileSdk
- compileSdk = libs.versions.sdk.compile.get().toInt()
+ sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
- minSdk = libs.versions.sdk.min.get().toInt()
+ minSdk = property.project.android.minSdk
}
- buildFeatures {
- compose = true
- }
- composeOptions {
- kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
- }
- kotlinOptions {
- freeCompilerArgs = freeCompilerArgs +
- "-Xexplicit-api=strict"
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
}
-dependencies {
- implementation(platform(libs.compose.bom))
- implementation(libs.compose.foundation)
- implementation(libs.compose.ui)
-}
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+}
\ No newline at end of file
diff --git a/pagecurl/src/androidMain/AndroidManifest.xml b/pagecurl/src/androidMain/AndroidManifest.xml
new file mode 100644
index 0000000..568741e
--- /dev/null
+++ b/pagecurl/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/pagecurl/src/androidMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.android.kt b/pagecurl/src/androidMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.android.kt
new file mode 100644
index 0000000..9ccc680
--- /dev/null
+++ b/pagecurl/src/androidMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.android.kt
@@ -0,0 +1,9 @@
+package eu.wewox.pagecurl.page
+
+import android.graphics.BlurMaskFilter
+import androidx.compose.ui.graphics.Paint
+
+actual fun Paint.setBlurred(value: Float) {
+ if (value == 0f) return
+ asFrameworkPaint().maskFilter = BlurMaskFilter(value, BlurMaskFilter.Blur.NORMAL)
+}
\ No newline at end of file
diff --git a/pagecurl/src/androidMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.android.kt b/pagecurl/src/androidMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.android.kt
new file mode 100644
index 0000000..332cc68
--- /dev/null
+++ b/pagecurl/src/androidMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.android.kt
@@ -0,0 +1,3 @@
+package eu.wewox.pagecurl.page
+
+internal actual fun systemCurrentTimeMillis() = System.currentTimeMillis()
\ No newline at end of file
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/ExperimentalPageCurlApi.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/ExperimentalPageCurlApi.kt
similarity index 100%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/ExperimentalPageCurlApi.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/ExperimentalPageCurlApi.kt
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/config/PageCurlConfig.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/config/PageCurlConfig.kt
similarity index 99%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/config/PageCurlConfig.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/config/PageCurlConfig.kt
index b4c0d69..875c72d 100644
--- a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/config/PageCurlConfig.kt
+++ b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/config/PageCurlConfig.kt
@@ -48,7 +48,7 @@ public fun rememberPageCurlConfig(
backPageColor: Color = Color.White,
backPageContentAlpha: Float = 0.1f,
shadowColor: Color = Color.Black,
- shadowAlpha: Float = 0.2f,
+ shadowAlpha: Float = 0.5f,
shadowRadius: Dp = 15.dp,
shadowOffset: DpOffset = DpOffset((-5).dp, 0.dp),
dragForwardEnabled: Boolean = true,
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/CurlDraw.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.kt
similarity index 85%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/CurlDraw.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.kt
index 1d8d040..574ec16 100644
--- a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/CurlDraw.kt
+++ b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.kt
@@ -1,23 +1,22 @@
package eu.wewox.pagecurl.page
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.os.Build
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.CacheDrawScope
import androidx.compose.ui.draw.DrawResult
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.toRect
+import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.ImageBitmapConfig
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.Path
-import androidx.compose.ui.graphics.asAndroidPath
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.rotateRad
import androidx.compose.ui.graphics.drawscope.withTransform
-import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.dp
import eu.wewox.pagecurl.ExperimentalPageCurlApi
@@ -25,8 +24,9 @@ import eu.wewox.pagecurl.config.PageCurlConfig
import eu.wewox.pagecurl.utils.Polygon
import eu.wewox.pagecurl.utils.lineLineIntersection
import eu.wewox.pagecurl.utils.rotate
-import java.lang.Float.max
+import kotlin.math.PI
import kotlin.math.atan2
+import kotlin.math.max
@ExperimentalPageCurlApi
internal fun Modifier.drawCurl(
@@ -157,7 +157,7 @@ private fun CacheDrawScope.prepareCurl(
// Calculate the angle in radians between X axis and the curl line, this is used to rotate mirrored content to the
// right position of the curled back-page
val lineVector = topCurlOffset - bottomCurlOffset
- val angle = Math.PI.toFloat() - atan2(lineVector.y, lineVector.x) * 2
+ val angle = PI.toFloat() - atan2(lineVector.y, lineVector.x) * 2
// Prepare a lambda to draw the shadow of the back-page
val drawShadow = prepareShadow(config, polygon, angle)
@@ -197,29 +197,27 @@ private fun CacheDrawScope.prepareShadow(
// Prepare shadow parameters
val radius = config.shadowRadius.toPx()
val shadowColor = config.shadowColor.copy(alpha = config.shadowAlpha).toArgb()
- val transparent = config.shadowColor.copy(alpha = 0f).toArgb()
+ // TODO shadowOffset to be set here
val shadowOffset = Offset(-config.shadowOffset.x.toPx(), config.shadowOffset.y.toPx())
- .rotate(2 * Math.PI.toFloat() - angle)
+ .rotate(2 * PI.toFloat() - angle)
// Prepare shadow paint with a shadow layer
val paint = Paint().apply {
- val frameworkPaint = asFrameworkPaint()
- frameworkPaint.color = transparent
- frameworkPaint.setShadowLayer(
- config.shadowRadius.toPx(),
- shadowOffset.x,
- shadowOffset.y,
- shadowColor
- )
+ color = Color(shadowColor)
+ setBlurred(radius)
+
+// val frameworkPaint = asFrameworkPaint()
+// frameworkPaint.color = transparent
+// frameworkPaint.setShadowLayer(
+// config.shadowRadius.toPx(),
+// shadowOffset.x,
+// shadowOffset.y,
+// shadowColor
+// )
}
- // Hardware acceleration supports setShadowLayer() only on API 28 and above, thus to support previous API versions
// draw a shadow to the bitmap instead
- return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- prepareShadowApi28(radius, paint, polygon)
- } else {
- prepareShadowImage(radius, paint, polygon)
- }
+ return prepareShadowImage(radius, paint, polygon)
}
private fun prepareShadowApi28(
@@ -228,12 +226,7 @@ private fun prepareShadowApi28(
polygon: Polygon,
): ContentDrawScope.() -> Unit = {
drawIntoCanvas {
- it.nativeCanvas.drawPath(
- polygon
- .offset(radius).toPath()
- .asAndroidPath(),
- paint.asFrameworkPaint()
- )
+ it.drawPath(polygon.offset(radius).toPath(), paint)
}
}
@@ -243,26 +236,26 @@ private fun CacheDrawScope.prepareShadowImage(
polygon: Polygon,
): ContentDrawScope.() -> Unit {
// Increase the size a little bit so that shadow is not clipped
- val bitmap = Bitmap.createBitmap(
+ val bitmap = ImageBitmap(
(size.width + radius * 4).toInt(),
(size.height + radius * 4).toInt(),
- Bitmap.Config.ARGB_8888
+ ImageBitmapConfig.Argb8888
)
Canvas(bitmap).apply {
drawPath(
polygon
// As bitmap size is increased we should translate the polygon so that shadow remains in center
.translate(Offset(2 * radius, 2 * radius))
- .offset(radius).toPath()
- .asAndroidPath(),
- paint.asFrameworkPaint()
+ .offset(radius).toPath(), paint
)
}
return {
drawIntoCanvas {
// As bitmap size is increased we should shift the drawing so that shadow remains in center
- it.nativeCanvas.drawBitmap(bitmap, -2 * radius, -2 * radius, null)
+ it.drawImage(bitmap, Offset(-2 * radius, -2 * radius), paint)
}
}
}
+
+internal expect fun Paint.setBlurred(value: Float)
\ No newline at end of file
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/CurlGesture.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.kt
similarity index 60%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/CurlGesture.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.kt
index 3fbdeda..fbafa4f 100644
--- a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/CurlGesture.kt
+++ b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.kt
@@ -5,9 +5,9 @@ import androidx.compose.animation.core.AnimationVector4D
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.calculateTargetValue
import androidx.compose.animation.splineBasedDecay
+import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.drag
-import androidx.compose.foundation.gestures.forEachGesture
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
@@ -84,50 +84,50 @@ internal fun Modifier.curlGesture(
val velocityTracker = VelocityTracker()
val startRect by lazy { targetStart.multiply(size) }
val endRect by lazy { targetEnd.multiply(size) }
- forEachGesture {
- awaitPointerEventScope {
- val down = awaitFirstDown(requireUnconsumed = false)
- if (!startRect.contains(down.position)) {
- return@awaitPointerEventScope
- }
+ awaitEachGesture {
+ val down = awaitFirstDown(requireUnconsumed = false)
+ if (!startRect.contains(down.position)) {
+ return@awaitEachGesture
+ }
- // Change X position to be always on the right side for more convenient gesture tracking
- val dragStart = down.position.copy(x = size.width.toFloat())
+ // Change X position to be always on the right side for more convenient gesture tracking
+ val dragStart = down.position.copy(x = size.width.toFloat())
- onStart()
+ onStart()
- var dragCurrent = dragStart
- drag(down.id) { change ->
- dragCurrent = change.position
- velocityTracker.addPosition(System.currentTimeMillis(), dragCurrent)
- change.consume()
- val vector = (dragStart - dragCurrent).rotate(PI.toFloat() / 2)
- onCurl(dragCurrent - vector, dragCurrent + vector)
- }
+ var dragCurrent = dragStart
+ drag(down.id) { change ->
+ dragCurrent = change.position
+ velocityTracker.addPosition(systemCurrentTimeMillis(), dragCurrent)
+ change.consume()
+ val vector = (dragStart - dragCurrent).rotate(PI.toFloat() / 2)
+ onCurl(dragCurrent - vector, dragCurrent + vector)
+ }
- if (dragCurrent == dragStart) {
- onCancel()
- return@awaitPointerEventScope
- }
+ if (dragCurrent == dragStart) {
+ onCancel()
+ return@awaitEachGesture
+ }
- val velocity = velocityTracker.calculateVelocity()
- val decay = splineBasedDecay(this)
- val target = decay.calculateTargetValue(
- Offset.VectorConverter,
- dragCurrent,
- Offset(velocity.x, velocity.y)
- ).let {
- Offset(
- it.x.coerceIn(0f, size.width.toFloat() - 1),
- it.y.coerceIn(0f, size.height.toFloat() - 1)
- )
- }
+ val velocity = velocityTracker.calculateVelocity()
+ val decay = splineBasedDecay(this)
+ val target = decay.calculateTargetValue(
+ Offset.VectorConverter,
+ dragCurrent,
+ Offset(velocity.x, velocity.y)
+ ).let {
+ Offset(
+ it.x.coerceIn(0f, size.width.toFloat() - 1),
+ it.y.coerceIn(0f, size.height.toFloat() - 1)
+ )
+ }
- if (endRect.contains(target)) {
- onEnd()
- } else {
- onCancel()
- }
+ if (endRect.contains(target)) {
+ onEnd()
+ } else {
+ onCancel()
}
}
}
+
+internal expect fun systemCurrentTimeMillis(): Long
\ No newline at end of file
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/PageCurl.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/PageCurl.kt
similarity index 100%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/PageCurl.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/PageCurl.kt
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/PageCurlState.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/PageCurlState.kt
similarity index 100%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/PageCurlState.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/PageCurlState.kt
diff --git a/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/TapGesture.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/TapGesture.kt
new file mode 100644
index 0000000..4ac537d
--- /dev/null
+++ b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/page/TapGesture.kt
@@ -0,0 +1,51 @@
+package eu.wewox.pagecurl.page
+
+import androidx.compose.foundation.gestures.awaitEachGesture
+import androidx.compose.foundation.gestures.awaitFirstDown
+import androidx.compose.foundation.gestures.waitForUpOrCancellation
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.pointerInput
+import eu.wewox.pagecurl.ExperimentalPageCurlApi
+import eu.wewox.pagecurl.config.PageCurlConfig
+import eu.wewox.pagecurl.utils.multiply
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+@ExperimentalPageCurlApi
+internal fun Modifier.tapGesture(
+ config: PageCurlConfig,
+ scope: CoroutineScope,
+ onTapForward: suspend () -> Unit,
+ onTapBackward: suspend () -> Unit,
+): Modifier = pointerInput(config) {
+ awaitEachGesture {
+ val down = awaitFirstDown().also { it.consume() }
+ val up = waitForUpOrCancellation() ?: return@awaitEachGesture
+
+ if ((down.position - up.position).getDistance() > viewConfiguration.touchSlop) {
+ return@awaitEachGesture
+ }
+
+ if (config.tapCustomEnabled && config.onCustomTap(this, size, up.position)) {
+ return@awaitEachGesture
+ }
+
+ if (config.tapForwardEnabled && config.tapForwardInteraction.target.multiply(size).contains(up.position)) {
+ scope.launch {
+ onTapForward()
+ }
+ return@awaitEachGesture
+ }
+
+ if (config.tapBackwardEnabled &&
+ config.tapBackwardInteraction.target
+ .multiply(size)
+ .contains(up.position)
+ ) {
+ scope.launch {
+ onTapBackward()
+ }
+ return@awaitEachGesture
+ }
+ }
+}
\ No newline at end of file
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/utils/MathUtils.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/utils/MathUtils.kt
similarity index 100%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/utils/MathUtils.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/utils/MathUtils.kt
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/utils/Polygon.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/utils/Polygon.kt
similarity index 100%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/utils/Polygon.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/utils/Polygon.kt
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/utils/RectUtils.kt b/pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/utils/RectUtils.kt
similarity index 100%
rename from pagecurl/src/main/kotlin/eu/wewox/pagecurl/utils/RectUtils.kt
rename to pagecurl/src/commonMain/kotlin/eu/wewox/pagecurl/utils/RectUtils.kt
diff --git a/pagecurl/src/desktopMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.desktop.kt b/pagecurl/src/desktopMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.desktop.kt
new file mode 100644
index 0000000..0f6604a
--- /dev/null
+++ b/pagecurl/src/desktopMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.desktop.kt
@@ -0,0 +1,10 @@
+package eu.wewox.pagecurl.page
+
+import androidx.compose.ui.graphics.Paint
+import org.jetbrains.skia.FilterBlurMode
+import org.jetbrains.skia.MaskFilter
+
+actual fun Paint.setBlurred(value: Float) {
+ if (value == 0f) return
+ asFrameworkPaint().maskFilter = MaskFilter.makeBlur(FilterBlurMode.NORMAL, value / 2f)
+}
\ No newline at end of file
diff --git a/pagecurl/src/desktopMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.desktop.kt b/pagecurl/src/desktopMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.desktop.kt
new file mode 100644
index 0000000..332cc68
--- /dev/null
+++ b/pagecurl/src/desktopMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.desktop.kt
@@ -0,0 +1,3 @@
+package eu.wewox.pagecurl.page
+
+internal actual fun systemCurrentTimeMillis() = System.currentTimeMillis()
\ No newline at end of file
diff --git a/pagecurl/src/iosMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.ios.kt b/pagecurl/src/iosMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.ios.kt
new file mode 100644
index 0000000..0f6604a
--- /dev/null
+++ b/pagecurl/src/iosMain/kotlin/eu/wewox/pagecurl/page/CurlDraw.ios.kt
@@ -0,0 +1,10 @@
+package eu.wewox.pagecurl.page
+
+import androidx.compose.ui.graphics.Paint
+import org.jetbrains.skia.FilterBlurMode
+import org.jetbrains.skia.MaskFilter
+
+actual fun Paint.setBlurred(value: Float) {
+ if (value == 0f) return
+ asFrameworkPaint().maskFilter = MaskFilter.makeBlur(FilterBlurMode.NORMAL, value / 2f)
+}
\ No newline at end of file
diff --git a/pagecurl/src/iosMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.ios.kt b/pagecurl/src/iosMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.ios.kt
new file mode 100644
index 0000000..ae1c9a6
--- /dev/null
+++ b/pagecurl/src/iosMain/kotlin/eu/wewox/pagecurl/page/CurlGesture.ios.kt
@@ -0,0 +1,13 @@
+package eu.wewox.pagecurl.page
+
+import kotlinx.cinterop.alloc
+import kotlinx.cinterop.memScoped
+import kotlinx.cinterop.ptr
+import platform.posix.gettimeofday
+import platform.posix.timeval
+
+internal actual fun systemCurrentTimeMillis() = memScoped {
+ val timeVal = alloc()
+ gettimeofday(timeVal.ptr, null)
+ (timeVal.tv_sec * 1000) + (timeVal.tv_usec / 1000)
+}
\ No newline at end of file
diff --git a/pagecurl/src/main/AndroidManifest.xml b/pagecurl/src/main/AndroidManifest.xml
deleted file mode 100644
index c191e0f..0000000
--- a/pagecurl/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/TapGesture.kt b/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/TapGesture.kt
deleted file mode 100644
index 20dd2ef..0000000
--- a/pagecurl/src/main/kotlin/eu/wewox/pagecurl/page/TapGesture.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package eu.wewox.pagecurl.page
-
-import androidx.compose.foundation.gestures.awaitFirstDown
-import androidx.compose.foundation.gestures.forEachGesture
-import androidx.compose.foundation.gestures.waitForUpOrCancellation
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.input.pointer.pointerInput
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
-import eu.wewox.pagecurl.config.PageCurlConfig
-import eu.wewox.pagecurl.utils.multiply
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-
-@ExperimentalPageCurlApi
-internal fun Modifier.tapGesture(
- config: PageCurlConfig,
- scope: CoroutineScope,
- onTapForward: suspend () -> Unit,
- onTapBackward: suspend () -> Unit,
-): Modifier = pointerInput(config) {
- forEachGesture {
- awaitPointerEventScope {
- val down = awaitFirstDown().also { it.consume() }
- val up = waitForUpOrCancellation() ?: return@awaitPointerEventScope
-
- if ((down.position - up.position).getDistance() > viewConfiguration.touchSlop) {
- return@awaitPointerEventScope
- }
-
- if (config.tapCustomEnabled && config.onCustomTap(this, size, up.position)) {
- return@awaitPointerEventScope
- }
-
- if (config.tapForwardEnabled && config.tapForwardInteraction.target.multiply(size).contains(up.position)) {
- scope.launch {
- onTapForward()
- }
- return@awaitPointerEventScope
- }
-
- if (config.tapBackwardEnabled &&
- config.tapBackwardInteraction.target
- .multiply(size)
- .contains(up.position)
- ) {
- scope.launch {
- onTapBackward()
- }
- return@awaitPointerEventScope
- }
- }
- }
-}
diff --git a/build-logic/.gitignore b/samples/.gitignore
similarity index 100%
rename from build-logic/.gitignore
rename to samples/.gitignore
diff --git a/build-logic/convention/.gitignore b/samples/androidApp/.gitignore
similarity index 100%
rename from build-logic/convention/.gitignore
rename to samples/androidApp/.gitignore
diff --git a/samples/androidApp/build.gradle.kts b/samples/androidApp/build.gradle.kts
new file mode 100644
index 0000000..a04d949
--- /dev/null
+++ b/samples/androidApp/build.gradle.kts
@@ -0,0 +1,45 @@
+plugins {
+ autowire(libs.plugins.kotlin.multiplatform)
+ autowire(libs.plugins.android.application)
+ autowire(libs.plugins.jetbrains.compose)
+}
+
+group = property.project.groupName
+
+kotlin {
+ androidTarget()
+ jvmToolchain(17)
+ sourceSets {
+ val androidMain by getting {
+ dependencies {
+ implementation(projects.samples.shared)
+ }
+ }
+ }
+}
+
+android {
+ namespace = property.project.groupName
+ compileSdk = property.project.android.compileSdk
+
+ sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
+
+ defaultConfig {
+ applicationId = property.project.groupName
+ minSdk = property.project.android.minSdk
+ targetSdk = property.project.android.targetSdk
+ versionName = property.project.samples.androidApp.versionName
+ versionCode = property.project.samples.androidApp.versionCode
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+}
\ No newline at end of file
diff --git a/demo/proguard-rules.pro b/samples/androidApp/proguard-rules.pro
similarity index 88%
rename from demo/proguard-rules.pro
rename to samples/androidApp/proguard-rules.pro
index 481bb43..ff59496 100644
--- a/demo/proguard-rules.pro
+++ b/samples/androidApp/proguard-rules.pro
@@ -1,6 +1,6 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
+# proguardFiles setting in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
diff --git a/demo/src/main/AndroidManifest.xml b/samples/androidApp/src/androidMain/AndroidManifest.xml
similarity index 95%
rename from demo/src/main/AndroidManifest.xml
rename to samples/androidApp/src/androidMain/AndroidManifest.xml
index b32aa5c..ddd8703 100644
--- a/demo/src/main/AndroidManifest.xml
+++ b/samples/androidApp/src/androidMain/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/samples/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json b/samples/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 0000000..ee7e3ca
--- /dev/null
+++ b/samples/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
\ No newline at end of file
diff --git a/samples/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..083f644
--- /dev/null
+++ b/samples/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,14 @@
+{
+ "images" : [
+ {
+ "filename" : "app-icon-512.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "512x512"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/samples/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-512.png b/samples/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-512.png
new file mode 100644
index 0000000..5365c18
Binary files /dev/null and b/samples/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-512.png differ
diff --git a/samples/iosApp/iosApp/Assets.xcassets/Contents.json b/samples/iosApp/iosApp/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/samples/iosApp/iosApp/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/samples/iosApp/iosApp/ContentView.swift b/samples/iosApp/iosApp/ContentView.swift
new file mode 100644
index 0000000..473b05a
--- /dev/null
+++ b/samples/iosApp/iosApp/ContentView.swift
@@ -0,0 +1,19 @@
+import UIKit
+import SwiftUI
+import shared
+
+struct ComposeView: UIViewControllerRepresentable {
+ func makeUIViewController(context: Context) -> UIViewController {
+ let viewController = Main_iosKt.createUIViewController()
+ return viewController
+ }
+
+ func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
+}
+
+struct ContentView: View {
+ var body: some View {
+ ComposeView()
+ .ignoresSafeArea(.all, edges: .bottom) // Compose has own keyboard handler
+ }
+}
diff --git a/samples/iosApp/iosApp/Info.plist b/samples/iosApp/iosApp/Info.plist
new file mode 100644
index 0000000..412e378
--- /dev/null
+++ b/samples/iosApp/iosApp/Info.plist
@@ -0,0 +1,50 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+
+ UILaunchScreen
+
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/samples/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json b/samples/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 0000000..4aa7c53
--- /dev/null
+++ b/samples/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
\ No newline at end of file
diff --git a/samples/iosApp/iosApp/iOSApp.swift b/samples/iosApp/iosApp/iOSApp.swift
new file mode 100644
index 0000000..b7bf2f4
--- /dev/null
+++ b/samples/iosApp/iosApp/iOSApp.swift
@@ -0,0 +1,10 @@
+import SwiftUI
+
+@main
+struct iOSApp: App {
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
diff --git a/samples/shared/.gitignore b/samples/shared/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/samples/shared/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/samples/shared/build.gradle.kts b/samples/shared/build.gradle.kts
new file mode 100644
index 0000000..f1ff602
--- /dev/null
+++ b/samples/shared/build.gradle.kts
@@ -0,0 +1,87 @@
+plugins {
+ autowire(libs.plugins.kotlin.multiplatform)
+ autowire(libs.plugins.android.library)
+ autowire(libs.plugins.jetbrains.compose)
+}
+
+group = property.project.groupName
+
+kotlin {
+ androidTarget()
+ jvm("desktop")
+ listOf(
+ iosX64(),
+ iosArm64(),
+ iosSimulatorArm64()
+ ).forEach { iosTarget ->
+ iosTarget.binaries.framework {
+ baseName = "shared"
+ isStatic = true
+ }
+ }
+ jvmToolchain(17)
+ sourceSets {
+ all {
+ languageSettings {
+ optIn("androidx.compose.material3.ExperimentalMaterial3Api")
+ optIn("eu.wewox.pagecurl.ExperimentalPageCurlApi")
+ }
+ }
+ val commonMain by getting {
+ dependencies {
+ implementation(compose.runtime)
+ implementation(compose.foundation)
+ implementation(compose.material3)
+ implementation(app.cash.paging.paging.common)
+ implementation(app.cash.paging.paging.compose.common)
+ implementation(projects.pagecurl)
+ }
+ }
+ val androidMain by getting {
+ dependencies {
+ api(compose.foundation)
+ api(androidx.core.core.ktx)
+ api(androidx.appcompat.appcompat)
+ api(androidx.activity.activity)
+ api(androidx.activity.activity.compose)
+ }
+ }
+ val desktopMain by getting {
+ dependencies {
+ api(compose.desktop.currentOs)
+ api(compose.runtime)
+ api(compose.foundation)
+ api(compose.material3)
+ }
+ }
+ val iosX64Main by getting
+ val iosArm64Main by getting
+ val iosSimulatorArm64Main by getting
+ val iosMain by creating {
+ dependsOn(commonMain)
+ iosX64Main.dependsOn(this)
+ iosArm64Main.dependsOn(this)
+ iosSimulatorArm64Main.dependsOn(this)
+ }
+ }
+}
+
+android {
+ namespace = property.project.groupName
+ compileSdk = property.project.android.compileSdk
+
+ sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
+
+ defaultConfig {
+ minSdk = property.project.android.minSdk
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+}
\ No newline at end of file
diff --git a/samples/shared/src/androidMain/kotlin/eu/wewox/pagecurl/App.android.kt b/samples/shared/src/androidMain/kotlin/eu/wewox/pagecurl/App.android.kt
new file mode 100644
index 0000000..1145196
--- /dev/null
+++ b/samples/shared/src/androidMain/kotlin/eu/wewox/pagecurl/App.android.kt
@@ -0,0 +1,8 @@
+package eu.wewox.pagecurl
+
+import androidx.compose.runtime.Composable
+
+@Composable
+internal actual fun BackablePageScreen(content: @Composable () -> Unit) {
+ content()
+}
\ No newline at end of file
diff --git a/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/App.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/App.kt
new file mode 100644
index 0000000..ff9f88e
--- /dev/null
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/App.kt
@@ -0,0 +1,62 @@
+package eu.wewox.pagecurl
+
+import androidx.compose.animation.Crossfade
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import eu.wewox.pagecurl.screens.BackPagePageCurlScreen
+import eu.wewox.pagecurl.screens.InteractionConfigInPageCurlScreen
+import eu.wewox.pagecurl.screens.PagingPageCurlScreen
+import eu.wewox.pagecurl.screens.SettingsPageCurlScreen
+import eu.wewox.pagecurl.screens.ShadowInPageCurlScreen
+import eu.wewox.pagecurl.screens.SimplePageCurlScreen
+import eu.wewox.pagecurl.screens.StateInPageCurlScreen
+import eu.wewox.pagecurl.ui.theme.PageCurlTheme
+
+/**
+ * Main view for demo application.
+ * Contains simple "Crossfade" based navigation to various examples.
+ */
+@Composable
+fun App(modifier: Modifier = Modifier) {
+ PageCurlTheme {
+ var example by rememberSaveable { mutableStateOf(null) }
+ PageStateHandler.callNavToMain = { example = null }
+ Surface(color = MaterialTheme.colorScheme.background) {
+ Crossfade(targetState = example, modifier, label = "Crossfade") { selected ->
+ when (selected) {
+ null -> RootScreen(onExampleClick = { PageStateHandler.onLeftMain?.invoke(); example = it })
+ Example.SimplePageCurl -> BackablePageScreen { SimplePageCurlScreen() }
+ Example.PagingPageCurl -> BackablePageScreen { PagingPageCurlScreen() }
+ Example.SettingsPageCurl -> BackablePageScreen { SettingsPageCurlScreen() }
+ Example.StateInPageCurl -> BackablePageScreen { StateInPageCurlScreen() }
+ Example.InteractionConfigInPageCurl -> BackablePageScreen { InteractionConfigInPageCurlScreen() }
+ Example.ShadowPageCurl -> BackablePageScreen { ShadowInPageCurlScreen() }
+ Example.BackPagePageCurl -> BackablePageScreen { BackPagePageCurlScreen() }
+ }
+ }
+ }
+ }
+}
+
+object PageStateHandler {
+
+ internal var onLeftMain: (() -> Unit)? = null
+ internal var callNavToMain: (() -> Unit)? = null
+
+ fun onLeftMain(onLeftMain: () -> Unit) {
+ this.onLeftMain = onLeftMain
+ }
+
+ fun navToMain() {
+ callNavToMain?.invoke()
+ }
+}
+
+@Composable
+internal expect fun BackablePageScreen(content: @Composable () -> Unit)
\ No newline at end of file
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/Example.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/Example.kt
similarity index 100%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/Example.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/Example.kt
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/HowToPageData.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/HowToPageData.kt
similarity index 100%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/HowToPageData.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/HowToPageData.kt
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/RootScreen.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/RootScreen.kt
similarity index 100%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/RootScreen.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/RootScreen.kt
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/components/HowToPage.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/HowToPage.kt
similarity index 100%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/components/HowToPage.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/HowToPage.kt
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/components/SettingsPopup.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/SettingsPopup.kt
similarity index 97%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/components/SettingsPopup.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/SettingsPopup.kt
index ccba5fe..94fcefb 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/components/SettingsPopup.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/SettingsPopup.kt
@@ -1,5 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
-
package eu.wewox.pagecurl.components
import androidx.compose.foundation.layout.Arrangement
@@ -20,7 +18,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
import eu.wewox.pagecurl.config.PageCurlConfig
@Composable
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/components/TopBar.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/TopBar.kt
similarity index 100%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/components/TopBar.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/TopBar.kt
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/components/ZoomOutLayout.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/ZoomOutLayout.kt
similarity index 97%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/components/ZoomOutLayout.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/ZoomOutLayout.kt
index 58f40a0..2d3b404 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/components/ZoomOutLayout.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/components/ZoomOutLayout.kt
@@ -1,5 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
-
package eu.wewox.pagecurl.components
import androidx.compose.animation.AnimatedVisibility
@@ -18,7 +16,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
import eu.wewox.pagecurl.config.PageCurlConfig
/**
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/BackPagePageCurlScreen.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/BackPagePageCurlScreen.kt
similarity index 98%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/screens/BackPagePageCurlScreen.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/BackPagePageCurlScreen.kt
index d951277..0b7cb84 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/BackPagePageCurlScreen.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/BackPagePageCurlScreen.kt
@@ -1,4 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
@file:Suppress("MagicNumber")
package eu.wewox.pagecurl.screens
@@ -31,7 +30,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.center
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toOffset
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
import eu.wewox.pagecurl.HowToPageData
import eu.wewox.pagecurl.components.HowToPage
import eu.wewox.pagecurl.components.ZoomOutLayout
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/InteractionConfigInPageCurl.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/InteractionConfigInPageCurl.kt
similarity index 98%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/screens/InteractionConfigInPageCurl.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/InteractionConfigInPageCurl.kt
index 791250b..c2b2186 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/InteractionConfigInPageCurl.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/InteractionConfigInPageCurl.kt
@@ -1,5 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
-
package eu.wewox.pagecurl.screens
import androidx.compose.foundation.layout.Arrangement
@@ -26,7 +24,6 @@ import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.center
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toOffset
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
import eu.wewox.pagecurl.HowToPageData
import eu.wewox.pagecurl.components.HowToPage
import eu.wewox.pagecurl.components.ZoomOutLayout
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/PagingPageCurlScreen.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/PagingPageCurlScreen.kt
similarity index 96%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/screens/PagingPageCurlScreen.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/PagingPageCurlScreen.kt
index 0c44745..10b6815 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/PagingPageCurlScreen.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/PagingPageCurlScreen.kt
@@ -1,5 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
-
package eu.wewox.pagecurl.screens
import androidx.compose.foundation.background
@@ -20,8 +18,7 @@ import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.PagingState
-import androidx.paging.compose.collectAsLazyPagingItems
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
+import app.cash.paging.compose.collectAsLazyPagingItems
import eu.wewox.pagecurl.page.PageCurl
import eu.wewox.pagecurl.page.rememberPageCurlState
import kotlinx.coroutines.delay
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/SettingsPageCurlScreen.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/SettingsPageCurlScreen.kt
similarity index 95%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/screens/SettingsPageCurlScreen.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/SettingsPageCurlScreen.kt
index fa1d6a3..c402f82 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/SettingsPageCurlScreen.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/SettingsPageCurlScreen.kt
@@ -1,5 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
-
package eu.wewox.pagecurl.screens
import androidx.compose.foundation.layout.Box
@@ -14,7 +12,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.center
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toOffset
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
import eu.wewox.pagecurl.HowToPageData
import eu.wewox.pagecurl.components.HowToPage
import eu.wewox.pagecurl.components.SettingsPopup
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/ShadowInPageCurlScreen.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/ShadowInPageCurlScreen.kt
similarity index 97%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/screens/ShadowInPageCurlScreen.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/ShadowInPageCurlScreen.kt
index cfe7736..e17e8ed 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/ShadowInPageCurlScreen.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/ShadowInPageCurlScreen.kt
@@ -1,4 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
@file:Suppress("MagicNumber")
package eu.wewox.pagecurl.screens
@@ -20,7 +19,6 @@ import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.center
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toOffset
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
import eu.wewox.pagecurl.HowToPageData
import eu.wewox.pagecurl.components.HowToPage
import eu.wewox.pagecurl.components.ZoomOutLayout
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/SimplePageCurlScreen.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/SimplePageCurlScreen.kt
similarity index 87%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/screens/SimplePageCurlScreen.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/SimplePageCurlScreen.kt
index 824fc5b..0932db0 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/SimplePageCurlScreen.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/SimplePageCurlScreen.kt
@@ -1,5 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
-
package eu.wewox.pagecurl.screens
import androidx.compose.foundation.layout.Box
@@ -7,7 +5,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
import eu.wewox.pagecurl.HowToPageData
import eu.wewox.pagecurl.components.HowToPage
import eu.wewox.pagecurl.page.PageCurl
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/StateInPageCurlScreen.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/StateInPageCurlScreen.kt
similarity index 97%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/screens/StateInPageCurlScreen.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/StateInPageCurlScreen.kt
index 375827b..143d575 100644
--- a/demo/src/main/kotlin/eu/wewox/pagecurl/screens/StateInPageCurlScreen.kt
+++ b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/screens/StateInPageCurlScreen.kt
@@ -1,5 +1,3 @@
-@file:OptIn(ExperimentalPageCurlApi::class)
-
package eu.wewox.pagecurl.screens
import androidx.compose.foundation.horizontalScroll
@@ -23,7 +21,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.center
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toOffset
-import eu.wewox.pagecurl.ExperimentalPageCurlApi
import eu.wewox.pagecurl.HowToPageData
import eu.wewox.pagecurl.components.HowToPage
import eu.wewox.pagecurl.components.ZoomOutLayout
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/ui/Spacing.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/ui/Spacing.kt
similarity index 100%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/ui/Spacing.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/ui/Spacing.kt
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/ui/theme/Color.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/ui/theme/Color.kt
similarity index 100%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/ui/theme/Color.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/ui/theme/Color.kt
diff --git a/demo/src/main/kotlin/eu/wewox/pagecurl/ui/theme/Theme.kt b/samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/ui/theme/Theme.kt
similarity index 100%
rename from demo/src/main/kotlin/eu/wewox/pagecurl/ui/theme/Theme.kt
rename to samples/shared/src/commonMain/kotlin/eu/wewox/pagecurl/ui/theme/Theme.kt
diff --git a/samples/shared/src/desktopMain/kotlin/eu/wewox/pagecurl/App.desktop.kt b/samples/shared/src/desktopMain/kotlin/eu/wewox/pagecurl/App.desktop.kt
new file mode 100644
index 0000000..d0231aa
--- /dev/null
+++ b/samples/shared/src/desktopMain/kotlin/eu/wewox/pagecurl/App.desktop.kt
@@ -0,0 +1,13 @@
+package eu.wewox.pagecurl
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import eu.wewox.pagecurl.components.TopBar
+
+@Composable
+internal actual fun BackablePageScreen(content: @Composable () -> Unit) {
+ Box {
+ content()
+ TopBar(title = "", onBackClick = { PageStateHandler.navToMain() })
+ }
+}
\ No newline at end of file
diff --git a/samples/shared/src/iosMain/kotlin/Main.ios.kt b/samples/shared/src/iosMain/kotlin/Main.ios.kt
new file mode 100644
index 0000000..9aaf6a8
--- /dev/null
+++ b/samples/shared/src/iosMain/kotlin/Main.ios.kt
@@ -0,0 +1,6 @@
+@file:Suppress("unused")
+
+import androidx.compose.ui.window.ComposeUIViewController
+import eu.wewox.pagecurl.App
+
+fun createUIViewController() = ComposeUIViewController { App() }
\ No newline at end of file
diff --git a/samples/shared/src/iosMain/kotlin/eu/wewox/pagecurl/App.ios.kt b/samples/shared/src/iosMain/kotlin/eu/wewox/pagecurl/App.ios.kt
new file mode 100644
index 0000000..d0231aa
--- /dev/null
+++ b/samples/shared/src/iosMain/kotlin/eu/wewox/pagecurl/App.ios.kt
@@ -0,0 +1,13 @@
+package eu.wewox.pagecurl
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import eu.wewox.pagecurl.components.TopBar
+
+@Composable
+internal actual fun BackablePageScreen(content: @Composable () -> Unit) {
+ Box {
+ content()
+ TopBar(title = "", onBackClick = { PageStateHandler.navToMain() })
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index dc66895..753a76c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,23 +1,19 @@
+enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
pluginManagement {
- includeBuild("build-logic")
repositories {
- google()
- mavenCentral()
gradlePluginPortal()
- }
-}
-
-plugins {
- id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0")
-}
-
-dependencyResolutionManagement {
- repositories {
google()
mavenCentral()
}
}
-
-rootProject.name = "PageCurl"
-include(":demo")
-include(":pagecurl")
+plugins {
+ id("com.highcapable.sweetdependency") version "1.0.2"
+ id("com.highcapable.sweetproperty") version "1.0.3"
+}
+sweetProperty {
+ global { sourcesCode { isEnable = false } }
+ rootProject { all { isEnable = false } }
+}
+rootProject.name = "pagecurl-multiplatform"
+include(":samples:androidApp", ":samples:desktopApp", ":samples:shared")
+include(":pagecurl")
\ No newline at end of file