Skip to content

Commit

Permalink
Adds moveable menu widget (#63)
Browse files Browse the repository at this point in the history
* Adds moveable reactive menu
  • Loading branch information
Jerboa-app authored Aug 19, 2024
1 parent a2a3443 commit cdb58ee
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 61 deletions.
66 changes: 34 additions & 32 deletions app/src/main/java/app/jerboa/spp/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,33 @@ import android.app.ActivityManager.RunningAppProcessInfo
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.graphics.Point
import android.graphics.Rect
import android.media.MediaPlayer
import android.net.Uri
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.graphics.Color
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import app.jerboa.spp.composable.NewsItem
import app.jerboa.spp.viewmodel.MUSIC
import app.jerboa.spp.viewmodel.REVIEW_RATE_LIMIT_MILLIS
import app.jerboa.spp.viewmodel.SPPViewModel
import app.jerboa.spp.viewmodel.SOCIAL
import app.jerboa.spp.composable.screen
import app.jerboa.spp.ui.theme.SPPTheme
import app.jerboa.spp.viewmodel.AboutViewModel
import app.jerboa.spp.viewmodel.ToyMenuViewModel
import app.jerboa.spp.viewmodel.MUSIC
import app.jerboa.spp.viewmodel.MenuPromptViewModel
import app.jerboa.spp.viewmodel.REVIEW_RATE_LIMIT_MILLIS
import app.jerboa.spp.viewmodel.SOCIAL
import app.jerboa.spp.viewmodel.SPPViewModel
import app.jerboa.spp.viewmodel.ToyMenuViewModel
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.gms.games.AuthenticationResult
Expand All @@ -40,7 +47,8 @@ import com.google.android.play.core.review.ReviewManager
import com.google.android.play.core.review.ReviewManagerFactory
import com.google.android.play.core.review.model.ReviewErrorCode
import java.lang.Integer.min
import java.util.*
import java.util.Date


val news = "news-21-07-24"

Expand All @@ -50,6 +58,7 @@ data class AppInfo(
val versionString: String,
val firstLaunch: Boolean,
val density: Float,
val textScaling: Float,
val heightDp: Float,
val widthDp: Float
)
Expand Down Expand Up @@ -573,12 +582,29 @@ class MainActivity : AppCompatActivity() {
}
)

val news: List<NewsItem> = listOf(
NewsItem(R.string.news1, R.drawable.__5_0),
NewsItem(R.string.news2, null),
NewsItem(R.string.news3, null),
NewsItem(R.string.news4, R.drawable.__5_3),
NewsItem(R.string.news5, null),
NewsItem(R.string.news6, R.drawable.__5_5),
NewsItem(R.string.news7, null),
NewsItem(R.string.news8, R.drawable.__6_0),
NewsItem(R.string.news9, null),
NewsItem(R.string.news10, R.drawable.news)
).reversed()

val height = resources.displayMetrics.heightPixels
val width = resources.displayMetrics.widthPixels

val displayInfo = resources.displayMetrics
val dpHeight = displayInfo.heightPixels / displayInfo.density
val dpWidth = displayInfo.widthPixels / displayInfo.density
val appInfo = AppInfo(
versionString,
firstLaunch,
displayInfo.density,
if (resources.getBoolean(R.bool.isTablet)) {
displayInfo.density
} else {
Expand All @@ -588,30 +614,6 @@ class MainActivity : AppCompatActivity() {
dpWidth
)

if (DEBUG) {
Log.d("density", appInfo.density.toString())
}

val news: List<NewsItem> = listOf(
NewsItem(R.string.news1, R.drawable.__5_0),
NewsItem(R.string.news2, null),
NewsItem(R.string.news3, null),
NewsItem(R.string.news4, R.drawable.__5_3),
NewsItem(R.string.news5, null),
NewsItem(R.string.news6, R.drawable.__5_5),
NewsItem(R.string.news7, null),
NewsItem(R.string.news8, R.drawable.__6_0),
NewsItem(R.string.news9, null),
NewsItem(R.string.news10, R.drawable.news)
).reversed()

window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
actionBar?.hide()

val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
val height = displayMetrics.heightPixels
val width = displayMetrics.widthPixels
setContent {
SPPTheme {
screen(
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/java/app/jerboa/spp/composable/about.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,28 +74,28 @@ fun about(
stringResource(id = R.string.tagline) + stringResource(id = R.string.description),
textAlign = TextAlign.Center,
maxLines = 4,
fontSize = MaterialTheme.typography.body1.fontSize * info.density,
fontSize = MaterialTheme.typography.body1.fontSize * info.textScaling,
colour = Color.Black
)
TextButton(onClick = { aboutViewModel.onRequestingLicenses() }) {
Text(
stringResource(id = R.string.OSSprompt),
textAlign = TextAlign.Center,
modifier = Modifier.weight(1f),
fontSize = MaterialTheme.typography.body1.fontSize * info.density,
fontSize = MaterialTheme.typography.body1.fontSize * info.textScaling,
color = MaterialTheme.colors.primary
)
}
adaptiveTextBox(
stringResource(R.string.attrib),
maxLines = 3,
fontSize = MaterialTheme.typography.overline.fontSize * info.density,
fontSize = MaterialTheme.typography.overline.fontSize * info.textScaling,
textAlign = TextAlign.Center,
colour = Color.Black
)
Text(
"version: " + info.versionString, modifier = Modifier.weight(1f),
fontSize = MaterialTheme.typography.overline.fontSize * info.density,
fontSize = MaterialTheme.typography.overline.fontSize * info.textScaling,
textAlign = TextAlign.Center,
color = Color.Black
)
Expand All @@ -104,7 +104,7 @@ fun about(
stringResource(id = R.string.resetTutorial),
textAlign = TextAlign.Center,
modifier = Modifier.weight(1f),
fontSize = MaterialTheme.typography.body1.fontSize * info.density,
fontSize = MaterialTheme.typography.body1.fontSize * info.textScaling,
color = MaterialTheme.colors.primary
)
}
Expand All @@ -113,7 +113,7 @@ fun about(
Spacer(modifier = Modifier.size(8.dp))
socials(images, info) { aboutViewModel.onRequestingSocial(it) }
Spacer(modifier = Modifier.size(2.dp))
newsLog(newsItems = newsItems, width = width75Percent*0.75, density = info.density)
newsLog(newsItems = newsItems, width = width75Percent*0.75)
}
}
}
77 changes: 70 additions & 7 deletions app/src/main/java/app/jerboa/spp/composable/menuPrompt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,46 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.*
import androidx.compose.material.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import app.jerboa.spp.AppInfo
import app.jerboa.spp.viewmodel.AboutViewModel
import app.jerboa.spp.viewmodel.MenuPromptViewModel
import app.jerboa.spp.viewmodel.SPPViewModel
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

@OptIn(ExperimentalAnimationApi::class)
@Composable
fun menuPrompt(
menuPromptViewModel: MenuPromptViewModel,
aboutViewModel: AboutViewModel,
sppViewModel: SPPViewModel,
images: Map<String,Int>,
menuItemHeight: Double
menuItemHeight: Double,
info: AppInfo
){

val displayingMenu: Boolean by menuPromptViewModel.displayingMenu.observeAsState(initial = false)
val displayingAbout: Boolean by aboutViewModel.displayingAbout.observeAsState(initial = false)
val displayingSliders: Boolean by menuPromptViewModel.displayingToyMenu.observeAsState(initial = false)

val displayingSound: Boolean by menuPromptViewModel.displayingSound.observeAsState(initial = false)
val paused: Boolean by menuPromptViewModel.paused.observeAsState(initial = false)
val playSuccess: Boolean by sppViewModel.playSuccess.observeAsState(initial = false)
Expand All @@ -47,6 +62,10 @@ fun menuPrompt(
), label = "alpha for fading the prompt"
)

val xmax = info.widthDp*info.density-1.7f*menuItemHeight.toFloat()*info.density
val ymax = info.heightDp*info.density-1.75f*menuItemHeight.toFloat()*info.density
var position by remember { mutableStateOf(Offset(0.0f,ymax)) }

Box(modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
Expand All @@ -55,14 +74,32 @@ fun menuPrompt(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.align(alignment = Alignment.BottomStart)
.graphicsLayer {
if (displayingAbout || displayingSliders) {
if (abs(position.x-xmax) < abs(position.x)) {
translationX = xmax
}
else {
translationX = 0.0f
}
translationY = ymax
} else {
translationX = position.x
translationY = position.y
}
}
) {
AnimatedVisibility(
visible = displayingMenu,
enter = fadeIn(tween(0)),
exit = fadeOut(tween(0))
) {
verticalMenu(modifier = Modifier, offset = Pair(0.dp, menuItemHeight.dp), contentPadding = 16.dp) {
verticalMenu(
modifier = Modifier,
offset = Pair(0.dp, 0.dp),
contentPadding = 16.dp,
headSpacePx = if (displayingAbout || displayingSliders) { ymax } else { position.y }
) {
Image(
painter = painterResource(id = images["toyMenu"]!!),
contentDescription = "Toy menu and sliders",
Expand All @@ -80,7 +117,8 @@ fun menuPrompt(
musicMenu(
menuPromptViewModel,
menuItemHeight,
images
images,
left = position.x > xmax/2.0f
)
}
else {
Expand Down Expand Up @@ -164,7 +202,30 @@ fun menuPrompt(
Box(
modifier = Modifier
.size(menuItemHeight.dp)
.align(alignment = Alignment.BottomStart)
.graphicsLayer {
if (displayingAbout || displayingSliders) {
if (abs(position.x-xmax) < abs(position.x)) {
translationX = xmax
}
else {
translationX = 0.0f
}
translationY = ymax
} else {
translationX = position.x
translationY = position.y
}
}
.conditional(!(displayingAbout || displayingSliders)){ Modifier.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consume()
var x = max(0.0f, position.x+dragAmount.x)
x = min(x, xmax)
var y = max(0.0f, position.y+dragAmount.y)
y = min(y, ymax)
position = Offset(x, y)
}
}}
) {
AnimatedVisibility(
visible = !displayingMenu,
Expand Down Expand Up @@ -194,7 +255,9 @@ fun menuPrompt(
.size(menuItemHeight.dp)
.clickable(
onClick = {
menuPromptViewModel.onDisplayingMenuChanged(false)
if (!(displayingAbout || displayingSliders)) {
menuPromptViewModel.onDisplayingMenuChanged(false)
}
aboutViewModel.onDisplayingAboutChanged(false)
menuPromptViewModel.onDisplayingToyMenuChanged(false)
menuPromptViewModel.onDisplayingMusicChanged(false)
Expand Down
17 changes: 16 additions & 1 deletion app/src/main/java/app/jerboa/spp/composable/musicMenu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
Expand All @@ -13,14 +14,18 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import app.jerboa.spp.viewmodel.AboutViewModel
import app.jerboa.spp.viewmodel.MUSIC
Expand All @@ -31,7 +36,16 @@ fun musicMenu(
menuPromptViewModel: MenuPromptViewModel,
menuItemHeight: Double,
images: Map<String,Int>,
left: Boolean = false
) {
val offsetX: Dp = if (left)
{
(-2*menuItemHeight).dp
}
else {
0.dp
}

AnimatedVisibility(
visible = true,
enter = fadeIn(),
Expand All @@ -40,7 +54,8 @@ fun musicMenu(
Row(
modifier = Modifier
.fillMaxWidth()
.height(menuItemHeight.dp),
.height(menuItemHeight.dp)
.offset(offsetX, 0.dp),
horizontalArrangement = Arrangement.spacedBy((0.01*menuItemHeight).dp),
verticalAlignment = Alignment.CenterVertically
) {
Expand Down
Loading

0 comments on commit cdb58ee

Please sign in to comment.