mirror of
https://github.com/AllanWang/Frost-for-Facebook.git
synced 2024-11-09 20:42:34 +01:00
Add shake effect
This commit is contained in:
parent
d0ed236ea6
commit
1dab81ee38
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Allan Wang
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.pitchedapps.frost.compose.effects
|
||||||
|
|
||||||
|
import androidx.compose.animation.core.animate
|
||||||
|
import androidx.compose.animation.core.spring
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.rotate
|
||||||
|
import androidx.compose.ui.platform.debugInspectorInfo
|
||||||
|
import androidx.compose.ui.platform.inspectable
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.cancelChildren
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State for tracking shaking animation
|
||||||
|
*
|
||||||
|
* Note: Used some other material states as reference. This however will recompose the function
|
||||||
|
* holding the state during shakes.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun rememberShakeState(): ShakeState {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val state = remember(scope) { ShakeState(scope) }
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShakeState
|
||||||
|
internal constructor(
|
||||||
|
private val animationScope: CoroutineScope,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val job = SupervisorJob()
|
||||||
|
|
||||||
|
private var _rotation by mutableFloatStateOf(0f)
|
||||||
|
|
||||||
|
internal val rotation
|
||||||
|
get() = _rotation
|
||||||
|
|
||||||
|
fun shake() {
|
||||||
|
job.cancelChildren()
|
||||||
|
animationScope.launch(job) {
|
||||||
|
animate(
|
||||||
|
_rotation,
|
||||||
|
0f,
|
||||||
|
initialVelocity = 200f,
|
||||||
|
animationSpec =
|
||||||
|
spring(
|
||||||
|
dampingRatio = 0.3f,
|
||||||
|
stiffness = 200f,
|
||||||
|
),
|
||||||
|
) { value, _ ->
|
||||||
|
_rotation = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Modifier.shake(state: ShakeState, enabled: Boolean = true) =
|
||||||
|
inspectable(
|
||||||
|
inspectorInfo =
|
||||||
|
debugInspectorInfo {
|
||||||
|
name = "shake"
|
||||||
|
properties["enabled"] = enabled
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Modifier.rotate(state.rotation)
|
||||||
|
}
|
@ -16,9 +16,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.pitchedapps.frost.tabselector
|
package com.pitchedapps.frost.tabselector
|
||||||
|
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
@ -37,6 +40,8 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.pitchedapps.frost.compose.effects.rememberShakeState
|
||||||
|
import com.pitchedapps.frost.compose.effects.shake
|
||||||
import com.pitchedapps.frost.facebook.FbItem
|
import com.pitchedapps.frost.facebook.FbItem
|
||||||
import com.pitchedapps.frost.facebook.tab
|
import com.pitchedapps.frost.facebook.tab
|
||||||
|
|
||||||
@ -63,6 +68,7 @@ fun TabSelectorScreen(modifier: Modifier = Modifier) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun TabSelector(
|
fun TabSelector(
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
@ -74,7 +80,17 @@ fun TabSelector(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
columns = GridCells.Fixed(4),
|
columns = GridCells.Fixed(4),
|
||||||
) {
|
) {
|
||||||
items(unselected, key = { it.key }) { TabItem(data = it) }
|
items(unselected, key = { it.key }) {
|
||||||
|
val shakeState = rememberShakeState()
|
||||||
|
TabItem(
|
||||||
|
modifier =
|
||||||
|
Modifier.animateItemPlacement().shake(shakeState).clickable {
|
||||||
|
shakeState.shake()
|
||||||
|
// onSelect(listOf(it))
|
||||||
|
},
|
||||||
|
data = it,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +104,7 @@ fun TabItem(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.padding(4.dp),
|
modifier = Modifier.padding(4.dp).size(24.dp),
|
||||||
imageVector = data.icon,
|
imageVector = data.icon,
|
||||||
contentDescription = data.title,
|
contentDescription = data.title,
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user