Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/src/main/java/app/gamenative/data/LibraryItem.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package app.gamenative.data

import app.gamenative.Constants
import app.gamenative.enums.ControllerSupport
import app.gamenative.utils.CustomGameScanner

enum class GameSource {
Expand All @@ -19,6 +20,7 @@ data class LibraryItem(
val iconHash: String = "",
val isShared: Boolean = false,
val gameSource: GameSource = GameSource.STEAM,
val controllerSupport: ControllerSupport = ControllerSupport.none,
) {
val clientIconUrl: String
get() = when (gameSource) {
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/app/gamenative/ui/data/GameDisplayInfo.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package app.gamenative.ui.data

import app.gamenative.enums.ControllerSupport

/**
* Common data structure for displaying game information in the UI.
* This allows both Steam and Custom Games to use the same UI layout.
Expand All @@ -20,5 +22,6 @@ data class GameDisplayInfo(
val logoUrl: String? = null, // Logo image URL (for SteamGridDB)
val capsuleUrl: String? = null, // Capsule/grid image URL (for SteamGridDB)
val headerUrl: String? = null, // Header image URL (for SteamGridDB, can use grid as header)
val controllerSupport: ControllerSupport = ControllerSupport.none,
)

6 changes: 6 additions & 0 deletions app/src/main/java/app/gamenative/ui/enums/AppFilter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.material.icons.filled.Build
import androidx.compose.material.icons.filled.Computer
import androidx.compose.material.icons.filled.Diversity3
import androidx.compose.material.icons.filled.InstallMobile
import androidx.compose.material.icons.filled.SportsEsports
import androidx.compose.material.icons.filled.VideogameAsset
import androidx.compose.ui.graphics.vector.ImageVector
import app.gamenative.enums.AppType
Expand Down Expand Up @@ -46,6 +47,11 @@ enum class AppFilter(
displayText = "Family",
icon = Icons.Default.Diversity3,
),
CONTROLLER_SUPPORT(
code = 0x40,
displayText = "Controller Support",
icon = Icons.Default.SportsEsports,
),
// ALPHABETIC(
// code = 0x20,
// displayText = "Alphabetic",
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/app/gamenative/ui/model/LibraryViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ class LibraryViewModel @Inject constructor(
true
}
}
.filter { item ->
if (currentState.appInfoSortType.contains(AppFilter.CONTROLLER_SUPPORT)) {
item.controllerSupport != app.gamenative.enums.ControllerSupport.none || !gameSource
} else {
true
}
}
.sortedWith(
compareByDescending<SteamApp> {
downloadDirectorySet.contains(SteamService.getAppDirName(it))
Expand All @@ -240,6 +247,7 @@ class LibraryViewModel @Inject constructor(
name = item.name,
iconHash = item.clientIconHash,
isShared = (PrefManager.steamUserAccountId != 0 && !item.ownerAccountId.contains(PrefManager.steamUserAccountId)),
controllerSupport = item.controllerSupport,
),
isInstalled = isInstalled,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.SportsEsports
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
Expand Down Expand Up @@ -297,6 +298,28 @@ internal fun AppScreenContent(
BackButton(onClick = onBack)
}

// Controller support icon (top right, next to settings)
if (displayInfo.controllerSupport != app.gamenative.enums.ControllerSupport.none) {
Box(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(top = 20.dp, end = 76.dp)
.size(28.dp)
.background(
color = Color.Black.copy(alpha = 0.6f),
shape = RoundedCornerShape(8.dp)
)
.padding(4.dp)
) {
Icon(
imageVector = Icons.Filled.SportsEsports,
contentDescription = "Controller Support",
tint = Color.White,
modifier = Modifier.fillMaxSize()
)
}
}

// Settings/options button (top right)
Box(
modifier = Modifier
Expand Down Expand Up @@ -854,6 +877,7 @@ private fun Preview_AppScreen() {
sizeFromStore = null,
lastPlayedText = null,
playtimeText = null,
controllerSupport = fakeApp.controllerSupport,
)
PluviaTheme {
Surface {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ class SteamAppScreen : BaseAppScreen() {
sizeFromStore = sizeFromStore,
lastPlayedText = lastPlayedText,
playtimeText = playtimeText,
controllerSupport = appInfo.controllerSupport,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
Expand All @@ -25,6 +26,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Face4
import androidx.compose.material.icons.filled.SportsEsports
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
Expand Down Expand Up @@ -83,7 +85,7 @@ internal fun AppItem(
hideText = true
alpha = 1f
}

// Reset alpha and hideText when image URL changes (e.g., when new images are fetched)
LaunchedEffect(imageRefreshCounter) {
if (paneType != PaneType.LIST) {
Expand Down Expand Up @@ -230,7 +232,7 @@ internal fun AppItem(
}
}
}

// Reset alpha and hideText when image URL changes (e.g., when new images are fetched)
LaunchedEffect(imageUrl) {
if (paneType != PaneType.LIST) {
Expand All @@ -249,6 +251,28 @@ internal fun AppItem(
}
)

// Controller support icon (top-right corner)
if (hideText && appInfo.controllerSupport != app.gamenative.enums.ControllerSupport.none) {
Box(
modifier = Modifier
.align(Alignment.TopEnd)
.padding(6.dp)
.size(20.dp)
.background(
color = Color.Black.copy(alpha = 0.7f),
shape = RoundedCornerShape(4.dp)
)
.padding(2.dp)
) {
Icon(
imageVector = Icons.Filled.SportsEsports,
contentDescription = "Controller Support",
tint = Color.White,
modifier = Modifier.fillMaxSize()
)
}
}

// Only display text if the image loading has failed
if (! hideText) {
GameInfoBlock(
Expand Down