Skip to content

Instantly share code, notes, and snippets.

@GibsonRuitiari
Created June 17, 2022 11:30
Show Gist options
  • Save GibsonRuitiari/0c25bbf2d781d2e34f98a9b712df1ddb to your computer and use it in GitHub Desktop.
Save GibsonRuitiari/0c25bbf2d781d2e34f98a9b712df1ddb to your computer and use it in GitHub Desktop.
package com.gibsonruitiari.eatoutui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.view.WindowCompat
import com.gibsonruitiari.eatoutui.ui.theme.EatOutUiTheme
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import java.util.*
import kotlin.concurrent.schedule
import kotlin.random.Random
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// turns of decor fitting system windows
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
setContent {
val systemUiController = rememberSystemUiController()
val useDarkIcons = MaterialTheme.colors.isLight
SideEffect {
systemUiController.setStatusBarColor(Color.Transparent, darkIcons = useDarkIcons)
}
EatOutUiTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
MainScreenHeaderComponent()
}
}
}
}
enum class Face(val angle:Float){
Front(0f){
override val next: Face
get() = Back
},
Back(180f){
override val next: Face
get() = Front
};
abstract val next:Face
}
enum class RotationAxis{AxisX, AxisY}
@Composable
private fun MainScreenHeaderComponent() {
BoxWithConstraints(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
var face by remember { mutableStateOf(Face.Front) }
val angle_ = remember { Animatable(0f) }
val scope = rememberCoroutineScope()
val firstPair = Container("Steak".toCharArray(), "Indian".toCharArray())
val secondPair = Container("Ethiopian".toCharArray(), "Barbeque".toCharArray())
val fourthPair = Container("African".toCharArray(), "Italian".toCharArray())
val fifthPair = Container("Eritrean".toCharArray(), "Lebanese".toCharArray())
val sixthPair = Container("Spanish".toCharArray(), "Mexican".toCharArray())
var front by remember {
mutableStateOf(firstPair.front)
}
var back by remember {
mutableStateOf(firstPair.back)
}
val seventhPair = Container("Mediterranean".toCharArray(), "Italian".toCharArray())
val list = listOf(firstPair,secondPair,fourthPair,sixthPair, fifthPair, seventhPair)
var isTransitioned by remember {
mutableStateOf(false)
}
LaunchedEffect(key1 = Unit) {
scope.timer {
face = face.next
angle_.animateTo(face.angle, tween(2500))
if (!isTransitioned){
val randomIndex= list.random()
front=randomIndex.front
back= randomIndex.back
delay(3000)
isTransitioned=false
}else {
isTransitioned=true
}
}
}
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier
.wrapContentSize()
.padding(10.dp)) {
Container(front,back).iterator().forEach {
val axis = if (it.first.code%2==0) RotationAxis.AxisY else RotationAxis.AxisX
FlipComposable(angle = angle_.value, front =it.first.toString(), back =it.second.toString(), axis = axis)
}
}
}
}
fun Container.iterator(): Iterator<Pair<Char, Char>> {
val (leading,other) = if(front.size>back.size) front to back else back to front
val pair=leading.zip(other).toMutableList() + leading.drop(other.size).map { it to ' ' }
return pair.iterator()
}
data class Container(val front: CharArray,val back: CharArray) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Container
if (!front.contentEquals(other.front)) return false
if (!back.contentEquals(other.back)) return false
return true
}
override fun hashCode(): Int {
var result = front.contentHashCode()
result = 31 * result + back.contentHashCode()
return result
}
}
@Composable
private fun FlipComposable(axis:RotationAxis=RotationAxis.AxisY,angle: Float,front: String,back: String){
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.wrapContentSize()
.graphicsLayer {
if (axis == RotationAxis.AxisX) rotationX = angle
else rotationY = angle
cameraDistance = 12 * density
}) {
if (angle <= 90) {
Text(text = front, fontSize = 24.sp, modifier = Modifier.wrapContentSize())
} else{
Text(text =back, fontSize = 24.sp, modifier = Modifier
.graphicsLayer {
if (axis == RotationAxis.AxisX) rotationX = 180f
else rotationY = 180f
}
.wrapContentSize())
}
}
}
private fun CoroutineScope.timer(delay:Long=500,action:suspend ()->Unit):Job=launch {
// if the job is not active anymore i.e has completed/cancelled due to cancellation of scope associated with this job
// the while loop will be broken automatically
while (isActive){
try {
action()
delay(delay)
}catch (ex:Exception){
println("error $ex")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment