Skip to content

Commit

Permalink
Create LeaningSideHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
ldeso committed Mar 28, 2024
1 parent e419856 commit d81aaf8
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 60 deletions.
24 changes: 12 additions & 12 deletions app/src/main/kotlin/net/leodesouza/blitz/ui/ClockContent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import net.leodesouza.blitz.ui.components.BasicTime
import net.leodesouza.blitz.ui.components.LeaningSide

/**
* Chess clock screen content consisting of the time of each player in different colors.
Expand All @@ -52,7 +53,7 @@ import net.leodesouza.blitz.ui.components.BasicTime
* @param[isStartedProvider] Lambda for whether the clock has started ticking.
* @param[isTickingProvider] Lambda for whether the clock is currently ticking.
* @param[isPausedProvider] Lambda for whether the clock is on pause.
* @param[isLeaningRightProvider] Lambda for whether the device is leaning right.
* @param[leaningSideProvider] Lambda for which side the device is currently leaning towards.
* @param[backEventProgressProvider] Lambda for the progress of the back gesture.
* @param[backEventSwipeEdgeProvider] Lambda for the swipe edge where the back gesture starts.
*/
Expand All @@ -64,7 +65,7 @@ fun ClockContent(
isStartedProvider: () -> Boolean,
isTickingProvider: () -> Boolean,
isPausedProvider: () -> Boolean,
isLeaningRightProvider: () -> Boolean,
leaningSideProvider: () -> LeaningSide,
backEventProgressProvider: () -> Float,
backEventSwipeEdgeProvider: () -> Int,
) {
Expand Down Expand Up @@ -104,7 +105,7 @@ fun ClockContent(
isStarted = isStartedProvider(),
isTicking = isTickingProvider(),
isPaused = isPausedProvider(),
isLeaningRight = isLeaningRightProvider(),
leaningSide = leaningSideProvider(),
backEventProgress = backEventProgressProvider(),
backEventSwipeEdge = backEventSwipeEdgeProvider(),
isLandscape = isLandscape,
Expand All @@ -126,7 +127,7 @@ fun ClockContent(
isStarted = isStartedProvider(),
isTicking = isTickingProvider(),
isPaused = isPausedProvider(),
isLeaningRight = isLeaningRightProvider(),
leaningSide = leaningSideProvider(),
backEventProgress = backEventProgressProvider(),
backEventSwipeEdge = backEventSwipeEdgeProvider(),
isLandscape = isLandscape,
Expand All @@ -147,7 +148,7 @@ private fun ClockContentPreview() {
whiteTimeProvider = { 5L * 60_000L },
blackTimeProvider = { 3L * 1_000L },
isWhiteTurnProvider = { true },
isLeaningRightProvider = { true },
leaningSideProvider = { LeaningSide.RIGHT },
isStartedProvider = { false },
isTickingProvider = { false },
isPausedProvider = { true },
Expand All @@ -165,7 +166,7 @@ private fun ClockContentPreview() {
* @param[isStarted] Whether the clock has started ticking.
* @param[isTicking] Whether the clock is currently ticking.
* @param[isPaused] Whether the clock is on pause.
* @param[isLeaningRight] Whether the device is currently leaning right.
* @param[leaningSide] Which side the device is currently leaning towards.
* @param[backEventProgress] Progress of the back gesture.
* @param[backEventSwipeEdge] Swipe edge where the back gesture starts.
* @param[isLandscape] Whether the device is in landscape mode.
Expand All @@ -177,21 +178,20 @@ private fun GraphicsLayerScope.setBasicTimeGraphics(
isStarted: Boolean,
isTicking: Boolean,
isPaused: Boolean,
isLeaningRight: Boolean,
leaningSide: LeaningSide,
backEventProgress: Float,
backEventSwipeEdge: Int,
isLandscape: Boolean,
) {
rotationZ = if (isLandscape) {
0F
} else if (isLeaningRight) {
-90F
} else {
90F
} else when (leaningSide) {
LeaningSide.LEFT -> 90F
LeaningSide.RIGHT -> -90F
}

translationX = if (isTicking && !isPlayerTurn) {
0F // do not translate the time of the other player if the back gesture pauses the clock
0F // when pausing, do not translate time of non-current player
} else {
val sign = if (backEventSwipeEdge == BackEventCompat.EDGE_RIGHT) -1F else 1F
sign * backEventProgress * screenWidth.toPx()
Expand Down
39 changes: 21 additions & 18 deletions app/src/main/kotlin/net/leodesouza/blitz/ui/ClockInput.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import androidx.compose.ui.input.key.type
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.pointerInput
import kotlinx.coroutines.delay
import net.leodesouza.blitz.ui.components.LeaningSide

/**
* Effect making system back gestures pause or reset the clock.
Expand Down Expand Up @@ -72,6 +73,7 @@ fun ClockBackHandler(
updateProgress(backEventProgress)
updateSwipeEdge(backEvent.swipeEdge)
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
while (backEventProgress < 1F) {
delay(1L)
Expand All @@ -80,6 +82,7 @@ fun ClockBackHandler(
}
delay(100L)
}

if (isTicking) {
pause()
} else if (isStarted) {
Expand All @@ -101,7 +104,7 @@ fun ClockBackHandler(
* @param[isStartedProvider] Lambda for whether the clock has started ticking.
* @param[isTickingProvider] Lambda for whether the clock is currently ticking.
* @param[isPausedProvider] Lambda for whether the clock is on pause.
* @param[isLeaningRightProvider] Lambda for whether the device is leaning right.
* @param[leaningSideProvider] Lambda for which side the device is currently leaning towards.
* @param[isLandscape] Whether the device is in landscape mode.
* @param[isRtl] Whether the layout direction is configured from right to left.
* @param[start] Callback called to start the clock.
Expand All @@ -117,7 +120,7 @@ fun Modifier.clockInput(
isStartedProvider: () -> Boolean,
isTickingProvider: () -> Boolean,
isPausedProvider: () -> Boolean,
isLeaningRightProvider: () -> Boolean,
leaningSideProvider: () -> LeaningSide,
isLandscape: Boolean,
isRtl: Boolean,
start: () -> Unit,
Expand Down Expand Up @@ -166,7 +169,7 @@ fun Modifier.clockInput(
dragSensitivity = dragSensitivity,
isStarted = isStartedProvider(),
isPaused = isPausedProvider(),
isLeaningRight = isLeaningRightProvider(),
leaningSide = leaningSideProvider(),
isLandscape = isLandscape,
isRtl = isRtl,
restoreSavedTime = restoreSavedTime,
Expand Down Expand Up @@ -194,7 +197,7 @@ fun Modifier.clockInput(
dragSensitivity = dragSensitivity,
isStarted = isStartedProvider(),
isPaused = isPausedProvider(),
isLeaningRight = isLeaningRightProvider(),
leaningSide = leaningSideProvider(),
isLandscape = isLandscape,
isRtl = isRtl,
restoreSavedTime = restoreSavedTime,
Expand Down Expand Up @@ -281,11 +284,7 @@ private fun onClockDragStart(
isStarted: Boolean, isPaused: Boolean, saveTime: () -> Unit, saveConf: () -> Unit,
) {
if (isPaused) {
if (isStarted) {
saveTime()
} else {
saveConf()
}
if (isStarted) saveTime() else saveConf()
}
}

Expand All @@ -296,9 +295,7 @@ private fun onClockDragStart(
* @param[nextPlayer] Callback called to switch to the next player.
*/
private fun onClockDragEnd(isTicking: Boolean, nextPlayer: () -> Unit) {
if (isTicking) {
nextPlayer()
}
if (isTicking) nextPlayer()
}

/**
Expand All @@ -309,7 +306,7 @@ private fun onClockDragEnd(isTicking: Boolean, nextPlayer: () -> Unit) {
* @param[dragSensitivity] How many minutes or seconds to add per dragged pixel.
* @param[isStarted] Whether the clock has started ticking.
* @param[isPaused] Whether the clock is on pause.
* @param[isLeaningRight] Whether the device is leaning right.
* @param[leaningSide] Which side the device is currently leaning towards.
* @param[isLandscape] Whether the device is in landscape mode.
* @param[isRtl] Whether the layout direction is configured from right to left.
* @param[restoreSavedTime] Callback called to restore the saved time.
Expand All @@ -320,7 +317,7 @@ private fun onClockHorizontalDrag(
dragSensitivity: Float,
isStarted: Boolean,
isPaused: Boolean,
isLeaningRight: Boolean,
leaningSide: LeaningSide,
isLandscape: Boolean,
isRtl: Boolean,
restoreSavedTime: (Float, Float) -> Unit,
Expand All @@ -337,7 +334,10 @@ private fun onClockHorizontalDrag(
restoreSavedConf(addMinutes, addSeconds)
}
} else {
val sign = if (isLeaningRight) -1F else 1F
val sign = when (leaningSide) {
LeaningSide.LEFT -> 1F
LeaningSide.RIGHT -> -1F
}
val addMinutes = 0F
val addSeconds = sign * dragSensitivity * dragAmount
if (isStarted) {
Expand All @@ -357,7 +357,7 @@ private fun onClockHorizontalDrag(
* @param[dragSensitivity] How many minutes or seconds to add per dragged pixel.
* @param[isStarted] Whether the clock has started ticking.
* @param[isPaused] Whether the clock is on pause.
* @param[isLeaningRight] Whether the device is leaning right.
* @param[leaningSide] Which side the device is currently leaning towards.
* @param[isLandscape] Whether the device is in landscape mode.
* @param[isRtl] Whether the layout direction is configured from right to left.
* @param[restoreSavedTime] Callback called to restore the saved time.
Expand All @@ -368,7 +368,7 @@ private fun onClockVerticalDrag(
dragSensitivity: Float,
isStarted: Boolean,
isPaused: Boolean,
isLeaningRight: Boolean,
leaningSide: LeaningSide,
isLandscape: Boolean,
isRtl: Boolean,
restoreSavedTime: (Float, Float) -> Unit,
Expand All @@ -385,7 +385,10 @@ private fun onClockVerticalDrag(
restoreSavedConf(addMinutes, addSeconds)
}
} else {
val sign = if (isLeaningRight xor isRtl) -1F else 1F
val sign = when (leaningSide) {
LeaningSide.LEFT -> if (isRtl) -1F else 1F
LeaningSide.RIGHT -> if (isRtl) 1F else -1F
}
val addMinutes = sign * dragSensitivity * dragAmount
val addSeconds = 0F
if (isStarted) {
Expand Down
50 changes: 20 additions & 30 deletions app/src/main/kotlin/net/leodesouza/blitz/ui/ClockScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import net.leodesouza.blitz.ui.components.LeaningSide
import net.leodesouza.blitz.ui.components.LeaningSideHandler
import net.leodesouza.blitz.ui.components.OrientationHandler

/**
Expand Down Expand Up @@ -70,16 +72,27 @@ fun ClockScreen(
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl

var orientation by remember { mutableIntStateOf(0) }
var isLeaningRight by remember { mutableStateOf(true) }
var leaningSide by remember { mutableStateOf(LeaningSide.RIGHT) }
var backEventProgress by remember { mutableFloatStateOf(0F) }
var backEventSwipeEdge by remember { mutableIntStateOf(BackEventCompat.EDGE_LEFT) }
var backEventSwipeEdge by remember {
if (isRtl) {
mutableIntStateOf(BackEventCompat.EDGE_RIGHT)
} else {
mutableIntStateOf(BackEventCompat.EDGE_LEFT)
}
}

OrientationHandler(onOrientationChanged = { orientation = it })

IsLeaningRightHandler(
LeaningSideHandler(
orientationProvider = { orientation },
isLeaningRightProvider = { isLeaningRight },
onLeaningSideChanged = { isLeaningRight = !isLeaningRight },
leaningSideProvider = { leaningSide },
onLeaningSideChanged = {
leaningSide = when (leaningSide) {
LeaningSide.LEFT -> LeaningSide.RIGHT
LeaningSide.RIGHT -> LeaningSide.LEFT
}
},
)

ClockTickingEffect(
Expand Down Expand Up @@ -117,7 +130,7 @@ fun ClockScreen(
isStartedProvider = { uiState.isStarted },
isTickingProvider = { uiState.isTicking },
isPausedProvider = { uiState.isPaused },
isLeaningRightProvider = { isLeaningRight },
leaningSideProvider = { leaningSide },
isLandscape = isLandscape,
isRtl = isRtl,
start = {
Expand All @@ -138,36 +151,13 @@ fun ClockScreen(
isStartedProvider = { uiState.isStarted },
isTickingProvider = { uiState.isTicking },
isPausedProvider = { uiState.isPaused },
isLeaningRightProvider = { isLeaningRight },
leaningSideProvider = { leaningSide },
backEventProgressProvider = { backEventProgress },
backEventSwipeEdgeProvider = { backEventSwipeEdge },
)
}
}

/**
* Handle whether the device is currently leaning towards its right side.
*
* @param[orientationProvider] Lambda for the orientation of the device in degrees.
* @param[isLeaningRightProvider] Lambda for whether the device is currently leaning right.
* @param[onLeaningSideChanged] Callback called when the leaning side of the device changes.
*/
@Composable
private fun IsLeaningRightHandler(
orientationProvider: () -> Int,
isLeaningRightProvider: () -> Boolean,
onLeaningSideChanged: () -> Unit,
) {
val orientation = orientationProvider()
val isLeaningRight = isLeaningRightProvider()

val isChangingFromLeftToRight = !isLeaningRight && orientation in 10 until 170
val isChangingFromRightToLeft = isLeaningRight && orientation in 190 until 350
if (isChangingFromLeftToRight || isChangingFromRightToLeft) {
onLeaningSideChanged()
}
}

/**
* Effect taking care of repeatedly waiting until the next tick or pausing the clock when it has
* finished ticking.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2024 Léo de Souza
*
* 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
*
* http://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 net.leodesouza.blitz.ui.components

import androidx.compose.runtime.Composable

/** Which side the device is currently leaning towards. */
enum class LeaningSide { LEFT, RIGHT }

/**
* Call [onLeaningSideChanged] when the [LeaningSide] returned by the [leaningSideProvider] changes,
* based on the current leaning side calculated from orientation returned by the
* [orientationProvider] in degrees.
*/
@Composable
fun LeaningSideHandler(
orientationProvider: () -> Int,
leaningSideProvider: () -> LeaningSide,
onLeaningSideChanged: () -> Unit,
) {
val orientation = orientationProvider()
val leaningSide = leaningSideProvider()

val isChangingFromLeftToRight = leaningSide == LeaningSide.LEFT && orientation in 10 until 170
val isChangingFromRightToLeft = leaningSide == LeaningSide.RIGHT && orientation in 190 until 350
if (isChangingFromLeftToRight || isChangingFromRightToLeft) {
onLeaningSideChanged()
}
}

0 comments on commit d81aaf8

Please sign in to comment.