Skip to content

Commit

Permalink
Add new tag groups
Browse files Browse the repository at this point in the history
  • Loading branch information
DRSchlaubi committed Nov 21, 2023
1 parent a5b0e14 commit 8e129be
Show file tree
Hide file tree
Showing 18 changed files with 231 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/android/wear/src/main/java/ui/WearTonbrettApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fun WearTonbrettApp(token: String) {

if (state is State.Awaiting) {
LaunchedEffect(api) {
sounds = api.getSounds()
sounds = api.getSoundList()

val me = api.getMe()

Expand Down
2 changes: 1 addition & 1 deletion app/desktop/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ kotlin {
}

named("jvmMain") {
if (OSUtils.IS_WINDOWS) {
if (OSUtils.IS_WINDOWS && false) {
dependsOn(windowsMain)
} else {
dependsOn(nonWindowsMain)
Expand Down
3 changes: 2 additions & 1 deletion app/shared/src/commonMain/kotlin/components/SearchBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ import dev.schlaubi.tonbrett.app.ColorScheme
import dev.schlaubi.tonbrett.app.api.IO
import dev.schlaubi.tonbrett.app.api.LocalContext
import dev.schlaubi.tonbrett.common.Sound
import dev.schlaubi.tonbrett.common.SoundGroup
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.time.Duration.Companion.milliseconds

typealias SoundUpdater = (List<Sound>) -> Unit
typealias SoundUpdater = (List<SoundGroup>) -> Unit

private val protectedKeys = listOf(Key.Enter, Key.DirectionUp, Key.DirectionDown)

Expand Down
87 changes: 72 additions & 15 deletions app/shared/src/commonMain/kotlin/components/SoundContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,52 @@
package dev.schlaubi.tonbrett.app.components

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Stop
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import cafe.adriel.lyricist.LocalStrings
import dev.schlaubi.tonbrett.app.ColorScheme
import dev.schlaubi.tonbrett.app.ErrorReporter
import dev.schlaubi.tonbrett.app.OptionalWebImage
import dev.schlaubi.tonbrett.app.api.IO
import dev.schlaubi.tonbrett.app.api.LocalContext
import dev.schlaubi.tonbrett.app.util.SoundToolTip
import dev.schlaubi.tonbrett.app.util.canClearFocus
import dev.schlaubi.tonbrett.app.util.conditional
import dev.schlaubi.tonbrett.app.util.isMobile
import dev.schlaubi.tonbrett.app.util.*
import dev.schlaubi.tonbrett.common.Id
import dev.schlaubi.tonbrett.common.Sound
import dev.schlaubi.tonbrett.common.SoundGroup
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun SoundContainer(
sounds: List<Sound>,
sounds: List<SoundGroup>,
errorReporter: ErrorReporter,
playingSound: Id<Sound>?,
unavailableFor: String?,
Expand Down Expand Up @@ -74,19 +81,64 @@ fun SoundContainer(
}

SearchBar(soundUpdater)
LazyVerticalGrid(
GridCells.Adaptive(160.dp),
verticalArrangement = Arrangement.spacedBy(5.dp),
horizontalArrangement = Arrangement.spacedBy(5.dp),
modifier = Modifier.canClearFocus().fillMaxHeight().padding(5.dp)
LazyColumn(
modifier = Modifier.fillMaxSize().scrollable(rememberScrollState(), Orientation.Vertical)
) {
items(sounds) { (id, name, _, description, emoji) ->
SoundCard(id, name, emoji, description, id == playingSound, errorReporter, unavailableFor != null)
items(sounds) { group ->
SoundGroup(group, playingSound, errorReporter, unavailableFor)
}
}
}
}

@Composable
private fun SoundGroup(
group: SoundGroup,
playingSound: Id<Sound>?,
errorReporter: ErrorReporter,
unavailableFor: String?
) = Column(Modifier.padding(5.dp)) {
var collapsed by remember { mutableStateOf(false) }
val strings = LocalStrings.current
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
Text(group.tag ?: strings.otherSounds, color = Color.White)
CollapseIcon(collapsed, Modifier.clickable { collapsed = !collapsed })
Divider(Modifier.fillMaxWidth().padding(5.dp))
}

AnimatedVisibility(!collapsed) {
FlowGrid(
GridCells.Adaptive(160.dp),
group.sounds,
horizontalArrangement = Arrangement.spacedBy(5.dp),
verticalArrangement = Arrangement.spacedBy(5.dp),
modifier = Modifier.canClearFocus()
) { (id, name, _, description, emoji) ->
SoundCard(
id,
name,
emoji,
description,
id == playingSound,
errorReporter,
unavailableFor != null
)
}
}
}

@Composable
private fun CollapseIcon(collapsed: Boolean, modifier: Modifier = Modifier) {
val transition = updateTransition(targetState = collapsed)
val iconRotation by transition.animateFloat { searching ->
if (searching) -90f else 0f
}
Icon(
Icons.Default.ExpandMore,
null,
tint = ColorScheme.current.textColor,
modifier = modifier.rotate(iconRotation)
)
}

@Composable
Expand Down Expand Up @@ -169,7 +221,12 @@ fun SoundCard(
) {
require(emoji is Sound.Emoji.HasUrl?) { "This emoji is invalid: $emoji" }
OptionalWebImage(emoji?.url, modifier = Modifier.size(32.dp).padding(end = 5.dp))
Text(name, color = ColorScheme.current.textColor, fontSize = 16.sp, textAlign = TextAlign.Center)
Text(
name,
color = ColorScheme.current.textColor,
fontSize = 16.sp,
textAlign = TextAlign.Center
)
}
if (playing && hovered && !disabled && !waiting) {
Box(Modifier.zIndex(1f).background(ColorScheme.current.secondaryContainer)) {
Expand Down
23 changes: 18 additions & 5 deletions app/shared/src/commonMain/kotlin/components/SoundList.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private val LOG = KotlinLogging.logger {}
@Composable
fun SoundList(errorReporter: ErrorReporter, voiceState: User.VoiceState?) {
var playingSound by remember { mutableStateOf<Id<Sound>?>(null) }
var sounds by remember { mutableStateOf<List<Sound>>(emptyList()) }
var sounds by remember { mutableStateOf<List<SoundGroup>>(emptyList()) }
var loading by remember { mutableStateOf(true) }
var available by remember { mutableStateOf(voiceState?.playerAvailable ?: false) }
var channelMismatch by remember { mutableStateOf(voiceState?.channelMismatch ?: false) }
Expand Down Expand Up @@ -74,17 +74,30 @@ fun SoundList(errorReporter: ErrorReporter, voiceState: User.VoiceState?) {
}

is SoundDeletedEvent -> {
sounds = sounds.filter { it.id != event.id }
sounds = sounds.map {
it.copy(sounds = it.sounds.filter { sound -> sound.id != event.id })
}
}

is SoundCreatedEvent -> {
sounds += event.sound
val existingGroup = sounds.firstOrNull { it.tag == event.sound.tag }
if (existingGroup == null) {
sounds += SoundGroup(event.sound.tag, listOf(event.sound))
} else {
val id = sounds.indexOf(existingGroup)
val copy = sounds.toMutableList()
copy[id] = existingGroup.copy(sounds = existingGroup.sounds + event.sound)
sounds = copy
}
}

is SoundUpdatedEvent -> {
val copy = sounds.toMutableList()
val groupsCopy = sounds.toMutableList()
val group = groupsCopy.first { it.tag == event.sound.tag }
val copy = group.sounds.toMutableList()
copy[copy.indexOfFirst { it.id == event.sound.id }] = event.sound
sounds = copy
groupsCopy[groupsCopy.indexOf(group)] = group.copy(sounds = copy)
sounds = groupsCopy
}

else -> LOG.warn { "Unknown event type: $event" }
Expand Down
3 changes: 2 additions & 1 deletion app/shared/src/commonMain/kotlin/strings/DeStrings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ val DeStrings = Strings(
playerBusy = "Jemand anders spielt gerade einen Ton ab",
pleaseSignIn = "Bitte melde dich an um die APp zu benutzen",
signInWithDiscord = "Mit Discord anmelden",
typeForMoreSuggestions = "Suche für mehr Vorschläge"
typeForMoreSuggestions = "Suche für mehr Vorschläge",
otherSounds = "Andere Sounds"
)
3 changes: 2 additions & 1 deletion app/shared/src/commonMain/kotlin/strings/EnStrings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ val EnStrings = Strings(
playerBusy = "Someone else is currently playing a sound",
pleaseSignIn = "Please sign in to use the app",
signInWithDiscord = "Sign in with Discord",
typeForMoreSuggestions = "Type for more suggestions"
typeForMoreSuggestions = "Type for more suggestions",
otherSounds = "Other sounds"
)
3 changes: 2 additions & 1 deletion app/shared/src/commonMain/kotlin/strings/Strings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ data class Strings(
val playerBusy: String,
val pleaseSignIn: String,
val signInWithDiscord: String,
val typeForMoreSuggestions: String
val typeForMoreSuggestions: String,
val otherSounds: String
)
53 changes: 53 additions & 0 deletions app/shared/src/commonMain/kotlin/util/FlowGrid.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dev.schlaubi.tonbrett.app.util

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

/**
* Grid-like layout based on [FlowRow].
*
* @param gridCells descriptor of [GridCells]
* @param items the items inside the grid
* @param horizontalArrangement The horizontal arrangement of the layout's children.
* @param verticalArrangement The vertical arrangement of the layout's virtual rows.
* @param modifier the [Modifier]
* @param itemContent Content for the items
*/
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun <T> FlowGrid(
gridCells: GridCells,
items: Iterable<T>,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
modifier: Modifier = Modifier,
itemContent: @Composable (T) -> Unit
) = BoxWithConstraints(modifier) {
val density = LocalDensity.current
val spacingPx = remember(density) { with(density) { horizontalArrangement.spacing.roundToPx() } }
val widths =
remember(density, constraints) { with(gridCells) { density.calculateCrossAxisCellSizes(constraints.maxWidth, spacingPx) } }

fun getWidth(index: Int) = with(density) { widths[index % widths.size].toDp() }

FlowRow(
horizontalArrangement = horizontalArrangement,
verticalArrangement = verticalArrangement,
) {
items.forEachIndexed { index, item ->
val width = getWidth(index)

BoxWithConstraints(Modifier.width(width)) {
itemContent(item)
}
}
}
}
2 changes: 1 addition & 1 deletion bot/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ mikbotPlugin {
tasks {
assembleBot {
bundledPlugins = listOf(
"ktor@${libs.versions.mikbot.get()}",
"ktor@1.25.0",
"music-player@${libs.mikbot.music.get().version}"
)
}
Expand Down
Loading

0 comments on commit 8e129be

Please sign in to comment.