-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #750 from shunm-999/feature/holographic-effect-card
Make profile card glow based on device orientation
- Loading branch information
Showing
6 changed files
with
415 additions
and
4 deletions.
There are no files selected for viewing
98 changes: 98 additions & 0 deletions
98
core/ui/src/androidMain/kotlin/io/github/droidkaigi/confsched/ui/OrientationSensorManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package io.github.droidkaigi.confsched.ui | ||
|
||
import android.content.Context | ||
import android.hardware.Sensor | ||
import android.hardware.SensorEvent | ||
import android.hardware.SensorEventListener | ||
import android.hardware.SensorManager | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.ui.platform.LocalContext | ||
|
||
@Composable | ||
internal actual fun getOrientationSensorManager( | ||
onOrientationChanged: (Orientation) -> Unit, | ||
): OrientationSensorManager { | ||
val context = LocalContext.current | ||
return remember(context, onOrientationChanged) { | ||
AndroidOrientationSensorManager( | ||
context = context, | ||
onOrientationChanged = onOrientationChanged, | ||
) | ||
} | ||
} | ||
|
||
internal class AndroidOrientationSensorManager( | ||
context: Context, | ||
override val onOrientationChanged: (Orientation) -> Unit, | ||
) : OrientationSensorManager, SensorEventListener { | ||
private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager | ||
|
||
private val accelerometerReading = FloatArray(3) | ||
private val magnetometerReading = FloatArray(3) | ||
|
||
private val rotationMatrix = FloatArray(9) | ||
private val orientationAngles = FloatArray(3) | ||
|
||
override fun start() { | ||
sensorManager.registerListener( | ||
this, | ||
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), | ||
SENSOR_DELAY, | ||
) | ||
sensorManager.registerListener( | ||
this, | ||
sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), | ||
SENSOR_DELAY, | ||
) | ||
} | ||
|
||
override fun stop() { | ||
sensorManager.unregisterListener(this) | ||
} | ||
|
||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { | ||
// Do nothing | ||
} | ||
|
||
override fun onSensorChanged(event: SensorEvent) { | ||
when (event.sensor.type) { | ||
Sensor.TYPE_ACCELEROMETER -> { | ||
System.arraycopy( | ||
event.values, | ||
0, | ||
accelerometerReading, | ||
0, | ||
accelerometerReading.size, | ||
) | ||
} | ||
|
||
Sensor.TYPE_MAGNETIC_FIELD -> { | ||
System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size) | ||
} | ||
} | ||
updateOrientationAngles() | ||
|
||
onOrientationChanged( | ||
Orientation( | ||
azimuth = orientationAngles[0], | ||
pitch = orientationAngles[1], | ||
roll = orientationAngles[2], | ||
), | ||
) | ||
} | ||
|
||
private fun updateOrientationAngles() { | ||
SensorManager.getRotationMatrix( | ||
rotationMatrix, | ||
null, | ||
accelerometerReading, | ||
magnetometerReading, | ||
) | ||
SensorManager.getOrientation(rotationMatrix, orientationAngles) | ||
} | ||
|
||
companion object { | ||
private const val SENSOR_DELAY: Int = SensorManager.SENSOR_DELAY_UI | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
core/ui/src/commonMain/kotlin/io/github/droidkaigi/confsched/ui/OrientationSensorManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package io.github.droidkaigi.confsched.ui | ||
|
||
import androidx.compose.runtime.Composable | ||
|
||
data class Orientation( | ||
val azimuth: Float, | ||
val pitch: Float, | ||
val roll: Float, | ||
) { | ||
companion object { | ||
val Zero = Orientation(0f, 0f, 0f) | ||
} | ||
} | ||
|
||
internal interface OrientationSensorManager { | ||
val onOrientationChanged: (Orientation) -> Unit | ||
fun start() | ||
fun stop() | ||
} | ||
|
||
@Composable | ||
internal expect fun getOrientationSensorManager( | ||
onOrientationChanged: (Orientation) -> Unit, | ||
): OrientationSensorManager |
56 changes: 56 additions & 0 deletions
56
core/ui/src/commonMain/kotlin/io/github/droidkaigi/confsched/ui/WithDeviceOrientation.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package io.github.droidkaigi.confsched.ui | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.DisposableEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import androidx.lifecycle.Lifecycle | ||
import androidx.lifecycle.LifecycleEventObserver | ||
import androidx.lifecycle.LifecycleOwner | ||
import androidx.lifecycle.compose.LocalLifecycleOwner | ||
|
||
interface DeviceOrientationScope { | ||
val orientation: Orientation | ||
} | ||
|
||
private class DeviceOrientationScopeImpl : DeviceOrientationScope { | ||
override var orientation: Orientation by mutableStateOf(Orientation.Zero) | ||
private set | ||
|
||
fun updateOrientation(orientation: Orientation) { | ||
this.orientation = orientation | ||
} | ||
} | ||
|
||
@Composable | ||
fun WithDeviceOrientation( | ||
content: @Composable (DeviceOrientationScope.() -> Unit), | ||
) { | ||
val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current | ||
|
||
val scope = remember { | ||
DeviceOrientationScopeImpl() | ||
} | ||
val sensorManager = getOrientationSensorManager { | ||
scope.updateOrientation(it) | ||
} | ||
|
||
DisposableEffect(lifecycleOwner) { | ||
val observer = LifecycleEventObserver { _, event -> | ||
if (event == Lifecycle.Event.ON_RESUME) { | ||
sensorManager.start() | ||
} else if (event == Lifecycle.Event.ON_PAUSE) { | ||
sensorManager.stop() | ||
} | ||
} | ||
|
||
lifecycleOwner.lifecycle.addObserver(observer) | ||
onDispose { | ||
lifecycleOwner.lifecycle.removeObserver(observer) | ||
} | ||
} | ||
|
||
content(scope) | ||
} |
52 changes: 52 additions & 0 deletions
52
core/ui/src/iosMain/kotlin/io/github/droidkaigi/confsched/ui/OrientationSensorManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package io.github.droidkaigi.confsched.ui | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.remember | ||
import platform.CoreMotion.CMMotionManager | ||
import platform.Foundation.NSOperationQueue | ||
|
||
@Composable | ||
internal actual fun getOrientationSensorManager( | ||
onOrientationChanged: (Orientation) -> Unit, | ||
): OrientationSensorManager { | ||
return remember(onOrientationChanged) { | ||
IosOrientationSensorManager( | ||
onOrientationChanged = onOrientationChanged, | ||
) | ||
} | ||
} | ||
|
||
internal class IosOrientationSensorManager( | ||
override val onOrientationChanged: (Orientation) -> Unit, | ||
) : OrientationSensorManager { | ||
private val motionManager = CMMotionManager() | ||
|
||
override fun start() { | ||
if (!motionManager.deviceMotionActive) { | ||
return | ||
} | ||
NSOperationQueue.currentQueue()?.let { | ||
motionManager.startDeviceMotionUpdatesToQueue( | ||
it, | ||
) { motion, _ -> | ||
if (motion == null) { | ||
return@startDeviceMotionUpdatesToQueue | ||
} | ||
onOrientationChanged( | ||
Orientation( | ||
azimuth = motion.attitude.yaw.toFloat(), | ||
pitch = motion.attitude.pitch.toFloat(), | ||
roll = motion.attitude.roll.toFloat(), | ||
), | ||
) | ||
} | ||
} | ||
} | ||
|
||
override fun stop() { | ||
if (!motionManager.deviceMotionActive) { | ||
return | ||
} | ||
motionManager.stopDeviceMotionUpdates() | ||
} | ||
} |
Oops, something went wrong.