Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
af1573d
Themes working
Dec 10, 2025
b6b0b6d
Anchor and styling added
Dec 10, 2025
d25d306
List done - capsule needs tweaking
Dec 11, 2025
de65cca
Defaults working - ish
Dec 12, 2025
da4a3e8
Subtle tweaks
Dec 15, 2025
5ae648b
Theme variables utalized
Dec 15, 2025
72671c8
Themes working
Dec 15, 2025
b1b4e66
Added carousel theme
Dec 15, 2025
9b9d597
Added carousel theme
Dec 15, 2025
3d41457
Wokring
Dec 16, 2025
cb1e904
Navigation still not working as it should
Dec 16, 2025
9dd13f6
Navigation now working
Dec 17, 2025
51110da
Navigation working, and now with custom overwrites if needed
Dec 17, 2025
1ba9576
Working
Dec 17, 2025
2375c38
Working
Dec 18, 2025
df4ef53
XML Restructure done
Dec 18, 2025
72f5f60
Snowcase added
Dec 18, 2025
e2d413d
Working
Dec 18, 2025
09828d0
Updated zIndex calculations
Dec 19, 2025
9a1a68b
Good
Dec 19, 2025
660cc53
Fixed minor issues
Dec 22, 2025
df4b2a2
Last played support
Dec 22, 2025
275b48d
Working on SwitchinItUp
Dec 22, 2025
8de5caa
Almost done with SwitchinItUp
Dec 22, 2025
55b25d5
Working, but need small adjustments
Dec 22, 2025
42642ed
Performance optimized carousels, and fixed some bugs
Dec 30, 2025
4e51027
Added Add External Theme functionality
Dec 31, 2025
9c8f3cb
Added documentation
Jan 1, 2026
5b2393e
Updated documentation
Jan 2, 2026
428f486
Merged master into themes
Jan 5, 2026
69d797a
Added translations
Jan 5, 2026
2b7ce94
Moved code styling inline
Jan 5, 2026
d9bccd5
Fixed misspelling
Jan 5, 2026
505cc2e
Merged with Master, and added GOG support for themes
Jan 6, 2026
fe4610a
Pruning for PR
Jan 7, 2026
8cc1f86
Pruned for PR
Jan 7, 2026
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
7 changes: 7 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,15 @@ dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.bundles.compose)
implementation(libs.landscapist.coil)
implementation(libs.coil.svg)
debugImplementation(libs.androidx.ui.tooling)

// Media3 (ExoPlayer) for video playback
implementation(libs.bundles.media3)

// Baseline Profiles - enables precompilation of critical code paths
implementation(libs.profileinstaller)

// Support
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions app/src/main/assets/Themes/ListView/locales/da.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="open_button">Åbn</string>
</resources>

5 changes: 5 additions & 0 deletions app/src/main/assets/Themes/ListView/locales/default.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="open_button">Open</string>
</resources>

5 changes: 5 additions & 0 deletions app/src/main/assets/Themes/ListView/locales/pt-rBR.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="open_button">Abrir</string>
</resources>

5 changes: 5 additions & 0 deletions app/src/main/assets/Themes/ListView/locales/zh-rTW.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="open_button">開啟</string>
</resources>

14 changes: 14 additions & 0 deletions app/src/main/assets/Themes/ListView/manifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<manifest>
<id>list_view</id>
<title>List View</title>
<version>1.0.0</version>
<engineVersion>1.0.0</engineVersion>
<minAppVersion>0.0.0</minAppVersion>
<description>A traditional list layout with game details, install status, and quick actions.</description>
<author>
<name>Utkarsh Dalal</name>
<github>https://github.com/utkarshdalal</github>
</author>
<preview src="/assets/theme.png" />
<theme source="/theme.xml" variables="/variables.xml" locales="/locales" />
</manifest>
69 changes: 69 additions & 0 deletions app/src/main/assets/Themes/ListView/theme.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<theme>
<elements>
<card id="listItem" width="100%" height="@{vars.rowHeight}">
<rect id="rowBg" x="0" y="0" width="100%" height="@{vars.rowHeight}"
color="#AA1E1E1E" cornerRadius="@{vars.cornerRadius}"
borderWidth="1" borderColor="#22FFFFFF" />

<image id="cover" x="@{vars.paddingMedium}" y="@{vars.paddingMedium}"
width="@{vars.coverSize}" height="@{vars.coverSize}"
src="@{game.cover}" cornerRadius="@{vars.cornerRadius}" scaleType="cover" />

<text id="title" x="88" y="18" width="@{vars.titleWidth}" height="24"
text="@{game.title}" textSize="@{vars.textSizeTitle}"
color="@{vars.textColor}" maxLines="1" fontWeight="bold"
overflow="ellipsis" />

<text id="installIndicator" x="88" y="40" width="16" height="16"
text="●" textSize="@{vars.textSizeTitle}"
color="@{game.installStatus.color}" fontWeight="bold" />

<text id="installStatus" x="100" y="42" width="300" height="16"
text="@{game.installStatus}" textSize="12"
color="#FF888888" />

<text id="compatStatus" x="88" y="60" width="300" height="18"
text="@{game.compatibility.label}" textSize="13"
color="@{game.compatibility.color}" fontStyle="italic" />

<button id="openBtn" x="26" y="26" height="40" padding="0 20" anchor="topRight"
text="@string/open_button" backgroundColor="@color/primary" textColor="@color/onPrimary"
textSize="14" cornerRadius="@{vars.cornerRadius}" />
</card>
</elements>

<layout>
<grid columns="1" cellWidth="100%" cellSpacing="0"
padding="@{vars.gridPaddingTop} 20"
selectionMode="moving" itemCard="listItem">
<separator height="1" margin="12 0">
<rect x="0" y="0" width="100%" height="1" color="#22FFFFFF" />
</separator>
</grid>

<fixed id="topBar" backgroundColor="#CC000000" height="@{vars.topBarHeight}">
<header x="@{vars.paddingMedium}" y="8" anchor="topLeft"
textColor="@{vars.textColor}" showAppName="true" showGameCount="true" />
<searchBar x="@{vars.searchBarX}" y="@{vars.searchBarY}" width="@{vars.searchBarWidth}" height="56"
anchor="topLeft" backgroundColor="#FF1E1E1E" borderRadius="24"
highlightColor="@{vars.highlightColor}" highlightOpacity="@{vars.highlightOpacity}"
highlightBorderWidth="@{vars.highlightBorderWidth}" highlightTransitionSpeed="@{vars.highlightTransitionSpeed}" />
<profileButton x="@{vars.paddingMedium}" y="@{vars.profileButtonY}" anchor="topRight" size="56"
iconSize="36" padding="10"
backgroundColor="#66808080" cornerRadius="12"
highlightColor="@{vars.highlightColor}" highlightOpacity="@{vars.highlightOpacity}"
highlightBorderWidth="@{vars.highlightBorderWidth}" highlightTransitionSpeed="@{vars.highlightTransitionSpeed}" />
</fixed>

<fixed id="bottomBar">
<filterButton x="100" y="@{vars.bottomOffset}" anchor="bottomRight" expanded="true"
cornerRadius="16" size="56" iconSize="24"
highlightColor="@{vars.highlightColor}" highlightOpacity="@{vars.highlightOpacity}"
highlightBorderWidth="@{vars.highlightBorderWidth}" highlightTransitionSpeed="@{vars.highlightTransitionSpeed}" />
<addButton x="@{vars.paddingMedium}" y="@{vars.bottomOffset}" anchor="bottomRight"
cornerRadius="16" size="56" iconSize="24"
highlightColor="@{vars.highlightColor}" highlightOpacity="@{vars.highlightOpacity}"
highlightBorderWidth="@{vars.highlightBorderWidth}" highlightTransitionSpeed="@{vars.highlightTransitionSpeed}" />
</fixed>
</layout>
</theme>
40 changes: 40 additions & 0 deletions app/src/main/assets/Themes/ListView/variables.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<variables>
<!-- Colors (used multiple times) -->
<var name="textColor" value="#FFFFFFFF" />
<var name="highlightColor" value="#9575CD" />

<!-- Highlight styling (used by multiple elements) -->
<var name="highlightOpacity" value="0.9" />
<var name="highlightBorderWidth" value="2" />
<var name="highlightTransitionSpeed" value="200" />

<!-- Shared dimensions -->
<var name="cornerRadius" value="15" />
<var name="rowHeight" value="92" />
<var name="coverSize" value="60" />
<var name="textSizeTitle" value="16" />
<var name="titleWidth" value="65%" />

<!-- Shared spacing -->
<var name="paddingMedium" value="16" />
<var name="bottomOffset" value="24" />

<!-- Top bar (in breakpoint) -->
<var name="topBarHeight" value="72" />
<var name="searchBarWidth" value="600" />
<var name="searchBarX" value="200" />
<var name="searchBarY" value="12" />
<var name="profileButtonY" value="12" />
<var name="gridPaddingTop" value="80" />

<!-- Portrait overrides -->
<breakpoint orientation="portrait">
<var name="topBarHeight" value="130" />
<var name="gridPaddingTop" value="160" />
<var name="searchBarWidth" value="90%" />
<var name="searchBarX" value="5%" />
<var name="searchBarY" value="80" />
<var name="profileButtonY" value="10" />
<var name="titleWidth" value="45%" />
</breakpoint>
</variables>
136 changes: 136 additions & 0 deletions app/src/main/baseline-prof.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Baseline Profile Rules for GameNative
# These rules tell the Android Runtime (ART) which code paths should be
# precompiled at install time for better startup and runtime performance.
#
# Format: HSPLclass_name;method_name(parameters)return_type
# H = Hot (frequently called), S = Startup, P = Post-startup, L = Class
#
# Reference: https://developer.android.com/topic/performance/baselineprofiles

# =============================================================================
# Theme Runtime - Carousel Rendering (Critical for smooth scrolling)
# =============================================================================

# ThemedGameGrid - Main carousel/grid rendering
HSPLapp/gamenative/theme/runtime/ThemedGameGridKt;->**(**)**
HSPLapp/gamenative/theme/runtime/ThemedGameGrid_**;->**(**)**

# Theme utilities used during rendering
HSPLapp/gamenative/theme/runtime/ThemeUtils;->**(**)**
HSPLapp/gamenative/theme/runtime/ThemeUtilsKt;->**(**)**

# Layer renderers for card content
HSPLapp/gamenative/theme/runtime/layers/LayerRenderersKt;->**(**)**
HSPLapp/gamenative/theme/runtime/SharedElementRenderers;->**(**)**

# Fixed element rendering
HSPLapp/gamenative/theme/runtime/FixedElementRendererKt;->**(**)**

# Binding context for data resolution
HSPLapp/gamenative/theme/runtime/BindingContext;->**(**)**
HSPLapp/gamenative/theme/runtime/BindingContextKt;->**(**)**

# =============================================================================
# Theme Model Classes
# =============================================================================

# Layout models
HSPLapp/gamenative/theme/model/Layout**;->**(**)**
HSPLapp/gamenative/theme/model/Layers**;->**(**)**
HSPLapp/gamenative/theme/model/Fixed**;->**(**)**
HSPLapp/gamenative/theme/model/Card**;->**(**)**
HSPLapp/gamenative/theme/model/Dimension**;->**(**)**

# =============================================================================
# Library Screen Components
# =============================================================================

# Main library screen
HSPLapp/gamenative/ui/screen/library/LibraryScreenKt;->**(**)**
HSPLapp/gamenative/ui/screen/library/LibraryListPaneKt;->**(**)**

# Library components
HSPLapp/gamenative/ui/screen/library/components/**;->**(**)**

# =============================================================================
# Compose Foundation - Pager (HorizontalPager for carousels)
# =============================================================================

# Pager core
HSPLandroidx/compose/foundation/pager/**;->**(**)**

# Lazy layout infrastructure (used by pager)
HSPLandroidx/compose/foundation/lazy/layout/**;->**(**)**

# Gestures for scrolling
HSPLandroidx/compose/foundation/gestures/**;->**(**)**

# =============================================================================
# Compose Animation (Smooth transitions)
# =============================================================================

HSPLandroidx/compose/animation/core/**;->**(**)**
HSPLandroidx/compose/animation/**;->**(**)**

# =============================================================================
# Compose UI Graphics Layer (Scale, alpha, offset transforms)
# =============================================================================

HSPLandroidx/compose/ui/graphics/**;->**(**)**
HSPLandroidx/compose/ui/draw/**;->**(**)**

# Layout and measurement
HSPLandroidx/compose/ui/layout/**;->**(**)**

# Modifier chains
HSPLandroidx/compose/ui/Modifier**;->**(**)**

# =============================================================================
# Image Loading (Coil - for game covers)
# =============================================================================

HSPLcoil/**;->**(**)**
HSPLcom/skydoves/landscapist/**;->**(**)**

# =============================================================================
# Compose Material3 Components
# =============================================================================

HSPLandroidx/compose/material3/**;->**(**)**

# =============================================================================
# Kotlin Coroutines (Async operations during scrolling)
# =============================================================================

HSPLkotlinx/coroutines/**;->**(**)**

# =============================================================================
# Data Classes and ViewModels
# =============================================================================

HSPLapp/gamenative/data/LibraryItem;->**(**)**
HSPLapp/gamenative/data/LibraryItem**;->**(**)**
HSPLapp/gamenative/ui/data/LibraryState;->**(**)**
HSPLapp/gamenative/ui/model/LibraryViewModel;->**(**)**

# =============================================================================
# Theme Manager and Parser
# =============================================================================

HSPLapp/gamenative/theme/ThemeManager;->**(**)**
HSPLapp/gamenative/theme/io/ThemeXmlMapper;->**(**)**
HSPLapp/gamenative/theme/io/ThemeXmlMapperKt;->**(**)**

# =============================================================================
# Startup Classes
# =============================================================================

# Application class
HSPLapp/gamenative/PluviaApp;->**(**)**

# Main Activity
HSPLapp/gamenative/PluviaActivity;->**(**)**
HSPLapp/gamenative/MainActivity;->**(**)**

# Navigation
HSPLapp/gamenative/ui/PluviaMain**;->**(**)**
19 changes: 18 additions & 1 deletion app/src/main/java/app/gamenative/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ class MainActivity : ComponentActivity() {
private var currentOrientationChangeValue: Int = 0
private var availableOrientations: EnumSet<Orientation> = EnumSet.of(Orientation.UNSPECIFIED)

// Configuration state to trigger Compose recomposition
// This is needed because android:configChanges prevents automatic recreation
// and LocalConfiguration doesn't update automatically
val configurationChangeCounter = mutableStateOf(0)
val currentOrientation = mutableStateOf(Configuration.ORIENTATION_UNDEFINED)
val currentScreenWidthDp = mutableStateOf(0)

// Store pending launch request to be processed after UI is ready
@Volatile
private var pendingLaunchRequest: IntentLaunchManager.LaunchRequest? = null
Expand Down Expand Up @@ -129,6 +136,11 @@ class MainActivity : ComponentActivity() {
navigationBarStyle = SystemBarStyle.light(TRANSPARENT, TRANSPARENT),
)
super.onCreate(savedInstanceState)

// Initialize configuration state for Compose
val config = resources.configuration
currentOrientation.value = config.orientation
currentScreenWidthDp.value = config.screenWidthDp

// Initialize the controller management system
ControllerManager.getInstance().init(getApplicationContext());
Expand Down Expand Up @@ -182,6 +194,7 @@ class MainActivity : ComponentActivity() {
.components {
add(IconDecoder.Factory())
add(AnimatedPngDecoder.Factory())
add(coil.decode.SvgDecoder.Factory())
}
// .logger(logger)
.build()
Expand Down Expand Up @@ -352,7 +365,11 @@ class MainActivity : ComponentActivity() {

override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Log.d("MainActivity", "Requested orientation: $requestedOrientation => ${Orientation.fromActivityInfoValue(requestedOrientation)}")
// Update configuration state to trigger Compose recomposition
// This is needed because LocalConfiguration doesn't update with android:configChanges
currentOrientation.value = newConfig.orientation
currentScreenWidthDp.value = newConfig.screenWidthDp
configurationChangeCounter.value++
}

private fun startOrientator() {
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/app/gamenative/PluviaApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class PluviaApp : SplitCompatApplication() {
// Initialize GOGConstants
app.gamenative.service.gog.GOGConstants.init(this)

// Initialize ThemeManager (scan themes, migrate old layout to theme, and activate)
app.gamenative.theme.ThemeManager.init(this)

DownloadService.populateDownloadService(this)

appScope.launch {
Expand Down
Loading
Loading