Skip to content
Merged
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
80 changes: 80 additions & 0 deletions .github/workflows/native-themes-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Native Themes Sync

# After every push to master that touches the native-theme CSS sources,
# the CSS compiler, or the build script, regenerate the shipped
# `.res` files and commit them straight back to master (no PR). Every
# downstream pipeline (port builds, BuildDaemon, archetypes, website)
# just consumes the committed `.res` instead of rebuilding it, so this
# workflow is the single producer.
#
# Pushes made with GITHUB_TOKEN do not retrigger workflow runs, so the
# commit-back step cannot loop.

on:
workflow_dispatch:
push:
branches:
- master
paths:
- 'native-themes/**'
- 'maven/css-compiler/**'
- 'scripts/build-native-themes.sh'
- '.github/workflows/native-themes-sync.yml'

permissions:
contents: write

concurrency:
group: native-themes-sync
cancel-in-progress: false

jobs:
rebuild-and-commit:
runs-on: ubuntu-latest
container: ghcr.io/codenameone/codenameone/pr-ci-container:latest
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Use JDK 8
run: |
echo "JAVA_HOME=${JAVA_HOME_8}" >> $GITHUB_ENV
echo "${JAVA_HOME_8}/bin" >> $GITHUB_PATH

- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-m2

- name: Build css-compiler
run: |
cd maven
mvn -B -pl css-compiler -am install -DskipTests -Dmaven.javadoc.skip=true -Plocal-dev-javase

- name: Rebuild native themes
run: ./scripts/build-native-themes.sh

- name: Commit and push regenerated .res files
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Themes/ holds the single source of truth. Each downstream consumer
# (nativeios.jar, the Android port jar, the simulator fat-jar, the
# BuildDaemon's sibling cn1 checkout) copies from Themes/ at its own
# build time, so this workflow only commits these two files.
git add Themes/iOSModernTheme.res Themes/AndroidMaterialTheme.res
if git diff --staged --quiet; then
echo "No .res changes; nothing to commit."
exit 0
fi
git commit -m "ci: auto-regenerate native theme .res files"
git push
10 changes: 4 additions & 6 deletions Ports/Android/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,10 @@
<target name="-pre-compile">
<copy file="../../Themes/androidTheme.res" todir="src" />
<copy file="../../Themes/android_holo_light.res" todir="src" />
<!-- Android Material 3 theme generated by
scripts/build-native-themes.sh from
native-themes/android-material/theme.css.
failonerror=false so the port still builds if the generator
hasn't run yet; runtime falls back to holo light. -->
<copy file="../../Themes/AndroidMaterialTheme.res" todir="src" failonerror="false" />
<!-- Android Material 3 theme committed under Themes/ and kept in sync
by .github/workflows/native-themes-sync.yml from
native-themes/android-material/theme.css. -->
<copy file="../../Themes/AndroidMaterialTheme.res" todir="src" />
</target>

<target name="-pre-jar">
Expand Down
6 changes: 3 additions & 3 deletions Ports/JavaScriptPort/src/main/webapp/assets/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Generated by scripts/build-native-themes.sh. Mirrors of Themes/ so the
# JS port runtime picks up the modern native themes. The CSS sources in
# native-themes/ are authoritative.
# Mirrors of Themes/*.res written by scripts/build-native-themes.sh so a local
# JS port run can fetch them as webapp assets. The canonical .res lives in
# Themes/ and is committed; this mirror is a build artifact.
iOSModernTheme.res
AndroidMaterialTheme.res
9 changes: 4 additions & 5 deletions Ports/iOSPort/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,10 @@
<target name="-pre-compile">
<copy file="../../Themes/iPhoneTheme.res" todir="nativeSources" />
<copy file="../../Themes/iOS7Theme.res" todir="nativeSources" />
<!-- iOS Modern (liquid-glass) theme generated by
scripts/build-native-themes.sh from native-themes/ios-modern/theme.css.
failonerror=false so the port still builds if the generator
hasn't run yet; runtime falls back to iOS 7. -->
<copy file="../../Themes/iOSModernTheme.res" todir="nativeSources" failonerror="false" />
<!-- iOS Modern (liquid-glass) theme committed under Themes/ and kept
in sync by .github/workflows/native-themes-sync.yml from
native-themes/ios-modern/theme.css. -->
<copy file="../../Themes/iOSModernTheme.res" todir="nativeSources" />
</target>
<target name="-post-jar">
<delete file="${dist.jar}.old" />
Expand Down
4 changes: 0 additions & 4 deletions Themes/.gitignore

This file was deleted.

Binary file added Themes/AndroidMaterialTheme.res
Binary file not shown.
Binary file added Themes/iOSModernTheme.res
Binary file not shown.
25 changes: 25 additions & 0 deletions maven/android/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,22 @@
<configuration>
<target>
<mkdir dir="${project.build.outputDirectory}/com/codename1/android"/>
<!-- android_port_sources.jar is the
bundle AndroidGradleBuilder unzips
into the user app's APK assets/.
AndroidMaterialTheme.res must be in
here for the runtime to find it;
pull it directly from the canonical
Themes/ copy rather than staging
into Ports/Android/src/. The .res
is kept in sync by
.github/workflows/native-themes-sync.yml. -->
<zip destfile="${project.build.outputDirectory}/com/codename1/android/android_port_sources.jar">
<fileset dir="${real.src.dir}" />
<fileset dir="${codename1.src.dir}"/>
<fileset dir="${project.basedir}/../../Themes">
<include name="AndroidMaterialTheme.res"/>
</fileset>
</zip>
</target>
</configuration>
Expand Down Expand Up @@ -280,6 +293,18 @@
<resource>
<directory>${src.dir}</directory>
</resource>
<!-- Themes/AndroidMaterialTheme.res is the single
source of truth; pull it into the Android port
jar here instead of pre-staging a copy under
Ports/Android/src/. The .res is committed and
kept in sync by
.github/workflows/native-themes-sync.yml. -->
<resource>
<directory>${project.basedir}/../../Themes</directory>
<includes>
<include>AndroidMaterialTheme.res</include>
</includes>
</resource>
</resources>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.codename1.ui.plaf.StyleParser.PaddingInfo;
import com.codename1.ui.plaf.StyleParser.ScalarValue;
import com.codename1.ui.plaf.StyleParser.StyleInfo;
import java.lang.reflect.Field;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;

Expand Down Expand Up @@ -215,27 +216,25 @@ void testStyleParserImageAndBorderParsing() {
}

@FormTest
void testRoundBorderShadowSpreadAndPaintingCaches() {
void testRoundBorderShadowSpreadAndPaintingCaches() throws Exception {
RoundBorder border = RoundBorder.create().shadowSpread(3).shadowBlur(4f).shadowOpacity(128).uiid(false);
com.codename1.ui.Label label = new com.codename1.ui.Label();
label.setWidth(20);
label.setHeight(20);
label.setX(0);
label.setY(0);
border.paintBorderBackground(graphics, label);
RoundBorder.CacheValue cacheValue = null;
Object baseCache = label.getClientProperty("cn1$$-rbcache");
if (baseCache instanceof RoundBorder.CacheValue) {
cacheValue = (RoundBorder.CacheValue) baseCache;
}
for (int i = 0; cacheValue == null && i < 50; i++) {
Object cached = label.getClientProperty("cn1$$-rbcache" + (i + 1));
if (cached instanceof RoundBorder.CacheValue) {
cacheValue = (RoundBorder.CacheValue) cached;
break;
}
}
assertNotNull(cacheValue);
// RoundBorder stores its cache under "cn1$$-rbcache" + instanceVal where
// instanceVal is a per-instance id off a static counter. Read the actual
// instanceVal off this border so the lookup doesn't depend on how many
// RoundBorder instances earlier tests in the same JVM happened to mint.
Field instanceValField = RoundBorder.class.getDeclaredField("instanceVal");
instanceValField.setAccessible(true);
int instanceVal = instanceValField.getInt(border);
Object cached = label.getClientProperty("cn1$$-rbcache" + instanceVal);
assertNotNull(cached, "RoundBorder.paintBorderBackground should populate the cache under cn1$$-rbcache" + instanceVal);
assertTrue(cached instanceof RoundBorder.CacheValue);
RoundBorder.CacheValue cacheValue = (RoundBorder.CacheValue) cached;
assertEquals(label.getWidth(), cacheValue.img.getWidth());
assertTrue(border.getMinimumHeight() > 0);
assertTrue(border.getMinimumWidth() > 0);
Expand Down
15 changes: 14 additions & 1 deletion maven/ios/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,21 @@
<target>
<mkdir dir="${project.build.outputDirectory}/codenameone/iosport-bundle"/>

<!-- Themes/iOSModernTheme.res is the single
source of truth; pull it into nativeios.jar
here instead of pre-staging a copy under
${codename1.nativeios.dir}. The exclude on
the nativeSources fileset guarantees a
stale local copy can't shadow the canonical
one. The .res is committed and kept in sync
by .github/workflows/native-themes-sync.yml. -->
<zip destfile="${project.build.directory}/codenameone/iosport-bundle/nativeios.jar">
<fileset dir="${codename1.nativeios.dir}" />
<fileset dir="${codename1.nativeios.dir}">
<exclude name="iOSModernTheme.res"/>
</fileset>
<fileset dir="${project.basedir}/../../Themes">
<include name="iOSModernTheme.res"/>
</fileset>
</zip>
<copy file="${project.build.directory}/${project.build.finalName}-jar-with-dependencies.jar" tofile="${project.build.directory}/codenameone/iosport-bundle/iOSPort.jar" overwrite="true"/>
<zip destfile="${project.build.directory}/${project.build.finalName}-bundle.jar">
Expand Down
9 changes: 4 additions & 5 deletions maven/javase/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,10 @@
simulator fat jar so JavaSEPort.loadSkinFile can
load the right .res based on the current skin's
platformName (or the Simulator "Native Theme"
menu override). failonerror=false lets the
simulator still build if
scripts/build-native-themes.sh hasn't produced
the modern .res files yet. -->
<copy todir="${project.build.outputDirectory}" failonerror="false">
menu override). All .res files are committed
under Themes/; the modern pair is regenerated
by .github/workflows/native-themes-sync.yml. -->
<copy todir="${project.build.outputDirectory}">
<fileset dir="${project.basedir}/../../Themes">
<include name="iOSModernTheme.res"/>
<include name="AndroidMaterialTheme.res"/>
Expand Down
12 changes: 5 additions & 7 deletions scripts/build-android-port.sh
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,11 @@ if [ ! -f "$BUILD_CLIENT" ]; then
fi
fi

# Compile native CSS themes (AndroidMaterialTheme.res) and stage them in the
# Android port's src/ so the Maven build packages them into the port jar. The
# runtime falls back to android_holo_light.res if AndroidMaterialTheme.res is
# missing, which loses the Material 3 palette + all $DarkUIID entries.
./scripts/build-native-themes.sh
mkdir -p Ports/Android/src
cp Themes/AndroidMaterialTheme.res Ports/Android/src/AndroidMaterialTheme.res
# maven/android/pom.xml pulls Themes/AndroidMaterialTheme.res directly into
# the Android port jar (resource entry on Themes/), so no pre-staging copy
# under Ports/Android/src/ is needed. The .res is committed under Themes/ and
# kept in sync by .github/workflows/native-themes-sync.yml. For local iteration
# on native-themes/android-material/theme.css, run scripts/build-native-themes.sh.

# Rebuild the `designer` module first so changes under maven/css-compiler/
# are picked up by the maven plugin's CSS compile step. The designer module's
Expand Down
13 changes: 5 additions & 8 deletions scripts/build-ios-port.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,11 @@ if [ ! -f "$BUILD_CLIENT" ]; then
fi
fi

# Compile native CSS themes (iOSModernTheme.res) and copy into the iOS port's
# native sources so the Maven iOS build packages them into nativeios.jar. The
# iOS runtime falls back to iOS7Theme.res when iOSModernTheme.res is missing,
# which loses all $DarkUIID entries (dark mode appears broken) and the liquid-
# glass styling — so make sure this runs before the port is built.
./scripts/build-native-themes.sh
mkdir -p Ports/iOSPort/nativeSources
cp Themes/iOSModernTheme.res Ports/iOSPort/nativeSources/iOSModernTheme.res
# maven/ios/pom.xml pulls Themes/iOSModernTheme.res directly into nativeios.jar,
# so no pre-staging copy under Ports/iOSPort/nativeSources/ is needed. The .res
# is committed under Themes/ and kept in sync by
# .github/workflows/native-themes-sync.yml. For local iteration on
# native-themes/ios-modern/theme.css, run scripts/build-native-themes.sh.

# Rebuild the `designer` module first so changes under maven/css-compiler/
# are picked up by the maven plugin's CSS compile step. The designer module's
Expand Down
4 changes: 3 additions & 1 deletion scripts/build-native-themes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ CSS_COMPILER_MODULE="$REPO_ROOT/maven/css-compiler"
CSS_SRC_ROOT="$REPO_ROOT/native-themes"
OUT_DIR="$REPO_ROOT/Themes"
# JavaScriptPort's runtime serves themes out of its webapp assets folder;
# mirror the generated .res files there too so the JS port picks them up.
# mirror the generated .res files there too so a local JS port run picks them
# up. The mirror is gitignored - Themes/ is the single source of truth, and
# the port poms (maven/ios, maven/android) consume it directly at build time.
JS_ASSETS_DIR="$REPO_ROOT/Ports/JavaScriptPort/src/main/webapp/assets"

# Resolve the compiler jar. Prefer a freshly-built target/ jar (so CSS compiler
Expand Down
13 changes: 6 additions & 7 deletions scripts/cn1playground/common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -417,12 +417,11 @@
</plugin>

<!--
Bundle the generated iOS Modern + Android Material native theme .res
files into the playground's classpath so the deployed JS bundle can
Bundle the iOS Modern + Android Material native theme .res files
into the playground's classpath so the deployed JS bundle can
`Resources.openLayered("/iOSModernTheme")` from inside the live
preview. The files are gitignored build artifacts produced by
scripts/build-native-themes.sh; failonerror=false keeps standalone
builds working when they haven't been generated yet.
preview. The .res files are committed under Themes/ and kept in
sync by .github/workflows/native-themes-sync.yml.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand All @@ -436,8 +435,8 @@
</goals>
<configuration>
<target>
<copy todir="${project.build.outputDirectory}" failonerror="false" verbose="true">
<fileset dir="${project.basedir}/../../../Themes" erroronmissingdir="false">
<copy todir="${project.build.outputDirectory}" verbose="true">
<fileset dir="${project.basedir}/../../../Themes">
<include name="iOSModernTheme.res"/>
<include name="AndroidMaterialTheme.res"/>
</fileset>
Expand Down
13 changes: 6 additions & 7 deletions scripts/initializr/common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -390,12 +390,11 @@
</plugin>

<!--
Bundle the generated iOS Modern native theme .res file into the
initializr's classpath so the deployed JS bundle can
Bundle the iOS Modern native theme .res file into the initializr's
classpath so the deployed JS bundle can
`Resources.openLayered("/iOSModernTheme")` for the live preview.
The file is a gitignored build artifact produced by
scripts/build-native-themes.sh; failonerror=false keeps standalone
builds working when it hasn't been generated yet.
The .res files are committed under Themes/ and kept in sync by
.github/workflows/native-themes-sync.yml.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand All @@ -409,8 +408,8 @@
</goals>
<configuration>
<target>
<copy todir="${project.build.outputDirectory}" failonerror="false" verbose="true">
<fileset dir="${project.basedir}/../../../Themes" erroronmissingdir="false">
<copy todir="${project.build.outputDirectory}" verbose="true">
<fileset dir="${project.basedir}/../../../Themes">
<include name="iOSModernTheme.res"/>
<include name="AndroidMaterialTheme.res"/>
</fileset>
Expand Down
Loading
Loading