Skip to content

Commit bbb428c

Browse files
authored
* Run demo build under xvfb
Scope demo build step to demo changes
1 parent 5a19d68 commit bbb428c

File tree

12 files changed

+460
-43
lines changed

12 files changed

+460
-43
lines changed

.github/workflows/developer-guide-docs.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
types: [opened, synchronize, reopened, ready_for_review]
66
paths:
77
- 'docs/developer-guide/**'
8+
- 'docs/demos/**'
89
- '.github/workflows/developer-guide-docs.yml'
910
release:
1011
types: [published]
@@ -22,6 +23,32 @@ jobs:
2223
- name: Check out repository
2324
uses: actions/checkout@v4
2425

26+
- name: Determine changed components
27+
id: changes
28+
if: github.event_name == 'pull_request'
29+
uses: dorny/paths-filter@v3
30+
with:
31+
filters: |
32+
demos:
33+
- 'docs/demos/**'
34+
docs:
35+
- 'docs/developer-guide/**'
36+
37+
- name: Set up Java
38+
uses: actions/setup-java@v4
39+
with:
40+
distribution: 'temurin'
41+
java-version: '11'
42+
43+
- name: Build Codename One demos
44+
if: github.event_name != 'pull_request' || steps.changes.outputs.demos == 'true'
45+
run: |
46+
set -euo pipefail
47+
mkdir -p "$HOME/.codenameone"
48+
touch "$HOME/.codenameone/guibuilder.jar"
49+
cp maven/CodeNameOneBuildClient.jar "$HOME/.codenameone/CodeNameOneBuildClient.jar"
50+
xvfb-run -a mvn -B -ntp -Dgenerate-gui-sources-done=true -pl common -am -f docs/demos/pom.xml test
51+
2552
- name: Determine publication metadata
2653
run: |
2754
set -euo pipefail
@@ -110,6 +137,7 @@ jobs:
110137
fi
111138
112139
- name: Build Developer Guide HTML and PDF
140+
if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true'
113141
run: |
114142
set -euo pipefail
115143
OUTPUT_ROOT="build/developer-guide"
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.codenameone.developerguide;
2+
3+
import com.codename1.components.SpanLabel;
4+
import com.codename1.ui.Button;
5+
import com.codename1.ui.Form;
6+
import com.codename1.ui.Slider;
7+
import com.codename1.ui.layouts.BoxLayout;
8+
9+
/**
10+
* Simple interactive demo that lets the user update a counter using buttons and a slider.
11+
*/
12+
public class CounterDemo implements Demo {
13+
@Override
14+
public String getTitle() {
15+
return "Counter";
16+
}
17+
18+
@Override
19+
public String getDescription() {
20+
return "Interactive counter with increment/decrement controls and a slider.";
21+
}
22+
23+
@Override
24+
public void show(Form parent) {
25+
Form form = new Form("Counter", BoxLayout.y());
26+
form.setName("counterForm");
27+
form.getToolbar().setBackCommand("Back", e -> parent.showBack());
28+
29+
SpanLabel valueLabel = new SpanLabel("Current value: 0");
30+
valueLabel.setName("counterValueLabel");
31+
32+
Slider slider = new Slider();
33+
slider.setName("counterSlider");
34+
slider.setEditable(true);
35+
slider.setMinValue(0);
36+
slider.setMaxValue(20);
37+
slider.setProgress(0);
38+
39+
Button increment = new Button("Increment");
40+
increment.setName("incrementButton");
41+
Button decrement = new Button("Decrement");
42+
decrement.setName("decrementButton");
43+
44+
increment.addActionListener(e -> adjustValue(slider, valueLabel, Math.min(slider.getProgress() + 1, slider.getMaxValue())));
45+
decrement.addActionListener(e -> adjustValue(slider, valueLabel, Math.max(slider.getProgress() - 1, slider.getMinValue())));
46+
slider.addDataChangedListener((type, index) -> updateLabel(valueLabel, slider.getProgress()));
47+
48+
form.addAll(valueLabel, slider, increment, decrement);
49+
form.show();
50+
}
51+
52+
private void adjustValue(Slider slider, SpanLabel valueLabel, int newValue) {
53+
slider.setProgress(newValue);
54+
updateLabel(valueLabel, newValue);
55+
}
56+
57+
private void updateLabel(SpanLabel valueLabel, int value) {
58+
valueLabel.setText("Current value: " + value);
59+
valueLabel.repaint();
60+
}
61+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.codenameone.developerguide;
2+
3+
import com.codename1.ui.Form;
4+
5+
/**
6+
* Represents a standalone demo that can be launched from the demo browser.
7+
*/
8+
public interface Demo {
9+
/**
10+
* @return The title used to identify this demo to the user.
11+
*/
12+
String getTitle();
13+
14+
/**
15+
* @return A short description that is displayed in the demo browser.
16+
*/
17+
String getDescription();
18+
19+
/**
20+
* Launches the demo, optionally using the supplied parent form to return
21+
* to when the demo is closed.
22+
*
23+
* @param parent The form that launched this demo.
24+
*/
25+
void show(Form parent);
26+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.codenameone.developerguide;
2+
3+
import com.codename1.components.MultiButton;
4+
import com.codename1.ui.Container;
5+
import com.codename1.ui.Form;
6+
import com.codename1.ui.layouts.BorderLayout;
7+
import com.codename1.ui.layouts.BoxLayout;
8+
9+
/**
10+
* Parent form that lists all demos and allows launching them.
11+
*/
12+
public class DemoBrowserForm extends Form {
13+
14+
public DemoBrowserForm() {
15+
super("Developer Guide Demos", new BorderLayout());
16+
getToolbar().setTitleCentered(false);
17+
Container listContainer = new Container(BoxLayout.y());
18+
listContainer.setName("demoList");
19+
listContainer.setScrollableY(true);
20+
21+
int index = 0;
22+
for (Demo demo : DemoRegistry.getDemos()) {
23+
MultiButton demoButton = new MultiButton(demo.getTitle());
24+
demoButton.setTextLine2(demo.getDescription());
25+
demoButton.setName("demoButton-" + index++);
26+
demoButton.addActionListener(e -> demo.show(DemoBrowserForm.this));
27+
listContainer.add(demoButton);
28+
}
29+
30+
add(BorderLayout.CENTER, listContainer);
31+
}
32+
}
Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,13 @@
11
package com.codenameone.developerguide;
22

3-
import static com.codename1.ui.CN.*;
43
import com.codename1.system.Lifecycle;
5-
import com.codename1.ui.*;
6-
import com.codename1.ui.layouts.*;
7-
import com.codename1.io.*;
8-
import com.codename1.ui.plaf.*;
9-
import com.codename1.ui.util.Resources;
104

115
/**
12-
* This file was generated by <a href="https://www.codenameone.com/">Codename One</a> for the purpose
13-
* of building native mobile applications using Java.
6+
* Application entry point that launches the demo browser.
147
*/
158
public class DemoCode extends Lifecycle {
169
@Override
1710
public void runApp() {
18-
Form hi = new Form("Hi World", BoxLayout.y());
19-
Button helloButton = new Button("Hello World");
20-
hi.add(helloButton);
21-
helloButton.addActionListener(e -> hello());
22-
hi.getToolbar().addMaterialCommandToSideMenu("Hello Command",
23-
FontImage.MATERIAL_CHECK, 4, e -> hello());
24-
hi.show();
11+
new DemoBrowserForm().show();
2512
}
26-
27-
private void hello() {
28-
Dialog.show("Hello Codename One", "Welcome to Codename One", "OK", null);
29-
}
30-
3113
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.codenameone.developerguide;
2+
3+
import java.util.Arrays;
4+
import java.util.Collections;
5+
import java.util.List;
6+
7+
/**
8+
* Registry of available demos so that the browser can enumerate them.
9+
*/
10+
public final class DemoRegistry {
11+
private static final List<Demo> DEMOS = Collections.unmodifiableList(
12+
Arrays.asList(
13+
new HelloWorldDemo(),
14+
new CounterDemo()
15+
)
16+
);
17+
18+
private DemoRegistry() {
19+
// utility class
20+
}
21+
22+
public static List<Demo> getDemos() {
23+
return DEMOS;
24+
}
25+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.codenameone.developerguide;
2+
3+
import com.codename1.ui.Button;
4+
import com.codename1.ui.Dialog;
5+
import com.codename1.ui.Form;
6+
import com.codename1.ui.layouts.BoxLayout;
7+
8+
/**
9+
* Simple hello world demo showing a dialog.
10+
*/
11+
public class HelloWorldDemo implements Demo {
12+
13+
@Override
14+
public String getTitle() {
15+
return "Hello World";
16+
}
17+
18+
@Override
19+
public String getDescription() {
20+
return "Shows a button that pops up a welcome dialog.";
21+
}
22+
23+
@Override
24+
public void show(Form parent) {
25+
Form form = new Form("Hello World", BoxLayout.y());
26+
form.setName("helloWorldForm");
27+
form.getToolbar().setBackCommand("Back", e -> parent.showBack());
28+
Button helloButton = new Button("Say Hello");
29+
helloButton.setName("helloButton");
30+
helloButton.addActionListener(e -> Dialog.show("Hello Codename One", "Welcome to Codename One", "OK", null));
31+
form.add(helloButton);
32+
form.show();
33+
}
34+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.codenameone.developerguide;
2+
3+
import com.codename1.components.SpanLabel;
4+
import com.codename1.testing.AbstractTest;
5+
import com.codename1.testing.TestUtils;
6+
import com.codename1.ui.Button;
7+
import com.codename1.ui.Command;
8+
import com.codename1.ui.Display;
9+
import com.codename1.ui.Form;
10+
import com.codename1.ui.Slider;
11+
import com.codename1.ui.events.ActionEvent;
12+
13+
/**
14+
* Validates the Counter demo's interactions update the UI consistently.
15+
*/
16+
public class CounterDemoTest extends AbstractTest {
17+
18+
@Override
19+
public boolean runTest() throws Exception {
20+
Form parent = new Form("Parent");
21+
parent.show();
22+
TestUtils.waitForFormTitle("Parent", 5000);
23+
24+
Demo demo = new CounterDemo();
25+
demo.show(parent);
26+
TestUtils.waitForFormTitle("Counter", 5000);
27+
28+
Form current = Display.getInstance().getCurrent();
29+
assertEqual("Counter", current.getTitle());
30+
assertEqual("counterForm", current.getName());
31+
32+
SpanLabel valueLabel = (SpanLabel) TestUtils.findByName("counterValueLabel");
33+
assertNotNull(valueLabel, "Counter value label should exist.");
34+
assertEqual("Current value: 0", valueLabel.getText());
35+
36+
Slider slider = (Slider) TestUtils.findByName("counterSlider");
37+
assertNotNull(slider, "Counter slider should exist.");
38+
assertEqual(0, slider.getProgress());
39+
40+
Button increment = (Button) TestUtils.findByName("incrementButton");
41+
Button decrement = (Button) TestUtils.findByName("decrementButton");
42+
assertNotNull(increment);
43+
assertNotNull(decrement);
44+
45+
increment.pressed();
46+
increment.released();
47+
TestUtils.waitFor(200);
48+
assertEqual(1, slider.getProgress());
49+
assertEqual("Current value: 1", valueLabel.getText());
50+
51+
slider.setProgress(slider.getMaxValue());
52+
TestUtils.waitFor(200);
53+
assertEqual("Current value: " + slider.getMaxValue(), valueLabel.getText());
54+
55+
increment.pressed();
56+
increment.released();
57+
TestUtils.waitFor(200);
58+
assertEqual(slider.getMaxValue(), slider.getProgress());
59+
assertEqual("Current value: " + slider.getMaxValue(), valueLabel.getText());
60+
61+
decrement.pressed();
62+
decrement.released();
63+
TestUtils.waitFor(200);
64+
assertEqual(slider.getMaxValue() - 1, slider.getProgress());
65+
assertEqual("Current value: " + (slider.getMaxValue() - 1), valueLabel.getText());
66+
67+
slider.setProgress(slider.getMinValue());
68+
TestUtils.waitFor(200);
69+
decrement.pressed();
70+
decrement.released();
71+
TestUtils.waitFor(200);
72+
assertEqual(slider.getMinValue(), slider.getProgress());
73+
assertEqual("Current value: " + slider.getMinValue(), valueLabel.getText());
74+
75+
Command back = current.getBackCommand();
76+
assertNotNull(back, "Back command should be available.");
77+
back.actionPerformed(new ActionEvent(back));
78+
TestUtils.waitForFormTitle("Parent", 5000);
79+
assertEqual(parent, Display.getInstance().getCurrent());
80+
81+
return true;
82+
}
83+
84+
@Override
85+
public boolean shouldExecuteOnEDT() {
86+
return true;
87+
}
88+
}

0 commit comments

Comments
 (0)