Skip to content

Commit

Permalink
Merge pull request #4 from teogor/feature/configuration-state-monitor
Browse files Browse the repository at this point in the history
Implement Configuration State Monitoring for Compose
  • Loading branch information
teogor authored Sep 2, 2024
2 parents c86502b + 2cc8689 commit 117b721
Show file tree
Hide file tree
Showing 13 changed files with 622 additions and 0 deletions.
1 change: 1 addition & 0 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ kotlin {
implementation(libs.androidx.lifecycle.viewmodel)
implementation(libs.androidx.lifecycle.runtime.compose)

implementation(projects.crosslensCompose)
implementation(projects.crosslensCore)
implementation(projects.crosslensUi)
}
Expand Down
3 changes: 3 additions & 0 deletions composeApp/src/commonMain/kotlin/dev/teogor/crosslens/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import dev.teogor.crosslens.compose.lifecycle.getConfigurationStateMonitor
import dev.teogor.crosslens.core.buildHashCode
import dev.teogor.crosslens.ui.rememberVisibilityState
import org.jetbrains.compose.ui.tooling.preview.Preview
Expand All @@ -49,6 +50,8 @@ public fun App() {
visibility.show()
visibility.toggle()
}
val configurationStateMonitor = getConfigurationStateMonitor()
configurationStateMonitor.isChanging()
remember {
buildHashCode {
append(visibility.isVisible)
Expand Down
17 changes: 17 additions & 0 deletions crosslens-compose/api/android/crosslens-compose.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
public final class dev/teogor/crosslens/compose/lifecycle/ConfigurationStateMonitor {
public static final field $stable I
public fun <init> (Landroid/app/Activity;)V
public final fun isChanging ()Z
}

public final class dev/teogor/crosslens/compose/lifecycle/ConfigurationStateMonitor_androidKt {
public static final fun getConfigurationStateMonitor (Landroidx/compose/runtime/Composer;I)Ldev/teogor/crosslens/compose/lifecycle/ConfigurationStateMonitor;
}

public final class dev/teogor/crosslens/compose/lifecycle/EffectsKt {
public static final fun DisposableEffectIgnoringConfiguration (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
public static final fun DisposableEffectIgnoringConfiguration (Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
public static final fun DisposableEffectIgnoringConfiguration (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
public static final fun DisposableEffectIgnoringConfiguration ([Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
}

17 changes: 17 additions & 0 deletions crosslens-compose/api/jvm/crosslens-compose.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
public final class dev/teogor/crosslens/compose/lifecycle/ConfigurationStateMonitor {
public static final field $stable I
public fun <init> ()V
public final fun isChanging ()Z
}

public final class dev/teogor/crosslens/compose/lifecycle/ConfigurationStateMonitor_jvmKt {
public static final fun getConfigurationStateMonitor (Landroidx/compose/runtime/Composer;I)Ldev/teogor/crosslens/compose/lifecycle/ConfigurationStateMonitor;
}

public final class dev/teogor/crosslens/compose/lifecycle/EffectsKt {
public static final fun DisposableEffectIgnoringConfiguration (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
public static final fun DisposableEffectIgnoringConfiguration (Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
public static final fun DisposableEffectIgnoringConfiguration (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
public static final fun DisposableEffectIgnoringConfiguration ([Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V
}

115 changes: 115 additions & 0 deletions crosslens-compose/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright 2024 Teogor (Teodor Grigor)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerToolOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile

plugins {
alias(libs.plugins.jetbrains.kotlin.multiplatform)
alias(libs.plugins.android.library)
alias(libs.plugins.jetbrains.compose)
alias(libs.plugins.jetbrains.compose.compiler)
alias(libs.plugins.teogor.winds)
}

winds {
moduleMetadata {
artifactDescriptor {
name = "Compose"
}
}
}

kotlin {
explicitApi()

applyDefaultHierarchyTemplate()

jvm {
kotlin {
jvmToolchain(11)
}
}

js(IR) {
browser()
nodejs()
}

@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
nodejs()
binaries.executable()
}

androidTarget {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}

listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { target ->
target.binaries.framework {
baseName = "crosslens-compose"
}
}

macosX64()
macosArm64()

sourceSets {
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.ui)

implementation(libs.kotlinx.coroutines.core)
}
}
}

android {
namespace = "dev.teogor.crosslens.compose"
compileSdk = libs.versions.android.compileSdk.get().toInt()

defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

kotlin {
jvmToolchain(11)
}
}

tasks.withType<KotlinJvmCompile>().configureEach {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2024 Teogor (Teodor Grigor)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.teogor.crosslens.compose.lifecycle

import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import androidx.compose.runtime.Composable
import androidx.compose.runtime.NonRestartableComposable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext

private tailrec fun Context.getActivity(): Activity? = when (this) {
is Activity -> this
is ContextWrapper -> baseContext.getActivity()
else -> null
}

/**
* Retrieves the [ConfigurationStateMonitor] instance for checking configuration changes.
*
* @return An instance of [ConfigurationStateMonitor].
*/
@Composable
@NonRestartableComposable
public actual fun getConfigurationStateMonitor(): ConfigurationStateMonitor {
val context = LocalContext.current
return remember(context) { ConfigurationStateMonitor(context.getActivity()) }
}

/**
* Monitors the state of configuration changes.
*
* This class provides functionality to determine if the application is currently
* undergoing a configuration change, such as screen rotations or other system-level
* changes that affect the application's state.
*/
@Stable
public actual class ConfigurationStateMonitor(
private val activity: Activity?
) {
/**
* Checks if a configuration change is currently ongoing.
*
* @return `true` if a configuration change is in progress; `false` otherwise.
*/
public actual fun isChanging(): Boolean {
return activity?.isChangingConfigurations ?: false
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2024 Teogor (Teodor Grigor)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.teogor.crosslens.compose.lifecycle

import androidx.compose.runtime.Composable
import androidx.compose.runtime.NonRestartableComposable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember

private val configurationStateMonitor = ConfigurationStateMonitor()

/**
* Retrieves the [ConfigurationStateMonitor] instance for checking configuration changes.
*
* @return An instance of [ConfigurationStateMonitor].
*/
@Composable
@NonRestartableComposable
public actual fun getConfigurationStateMonitor(): ConfigurationStateMonitor {
return remember { configurationStateMonitor }
}

/**
* Monitors the state of configuration changes.
*
* This class provides functionality to determine if the application is currently
* undergoing a configuration change, such as screen rotations or other system-level
* changes that affect the application's state.
*/
@Stable
public actual class ConfigurationStateMonitor {
/**
* Checks if a configuration change is currently ongoing.
*
* @return `true` if a configuration change is in progress; `false` otherwise.
*/
public actual fun isChanging(): Boolean = false

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2024 Teogor (Teodor Grigor)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.teogor.crosslens.compose.lifecycle

import androidx.compose.runtime.Composable
import androidx.compose.runtime.NonRestartableComposable
import androidx.compose.runtime.Stable

/**
* Retrieves the [ConfigurationStateMonitor] instance for checking configuration changes.
*
* @return An instance of [ConfigurationStateMonitor].
*/
@Composable
@NonRestartableComposable
public expect fun getConfigurationStateMonitor(): ConfigurationStateMonitor

/**
* Monitors the state of configuration changes.
*
* This class provides functionality to determine if the application is currently
* undergoing a configuration change, such as screen rotations or other system-level
* changes that affect the application's state.
*/
@Stable
public expect class ConfigurationStateMonitor {

/**
* Checks if a configuration change is currently ongoing.
*
* @return `true` if a configuration change is in progress; `false` otherwise.
*/
public fun isChanging(): Boolean
}
Loading

0 comments on commit 117b721

Please sign in to comment.