getCurrentTimeAsync() {
* @return this registration, for chaining
*/
public Registration addCurrentTimeChangeListener(
- PropertyChangeListener listener, long period, TimeUnit periodUnit) {
- int millis = (int) Math.min(periodUnit.toMillis(period), Integer.MAX_VALUE);
+ PropertyChangeListener listener, final long period, final TimeUnit periodUnit) {
+ final int millis = (int) Math.min(periodUnit.toMillis(period), Integer.MAX_VALUE);
if (listener == null) {
listener = ev -> {};
}
@@ -202,7 +206,7 @@ public boolean isVisible() {
}
@Override
- public void setVisible(boolean visible) {
+ public void setVisible(final boolean visible) {
getStyle().set(DISPLAY, visible ? INLINE : "none");
}
}
diff --git a/src/main/resources/META-INF/frontend/simple-timer/simple-timer.js b/src/main/resources/META-INF/frontend/simple-timer/simple-timer.js
index 4965118..568035e 100644
--- a/src/main/resources/META-INF/frontend/simple-timer/simple-timer.js
+++ b/src/main/resources/META-INF/frontend/simple-timer/simple-timer.js
@@ -110,27 +110,30 @@ Polymer({
type: Boolean,
value: false
},
+ targetId: {
+ type: String,
+ value: null,
+ },
/**
* Time the timer has spent running since it was started
*/
- _elapsedTime: {
+ _elapsed: {
type: Number,
value: 0
},
_formattedTime: {
type: String,
- value: '0'
+ value: '0',
+ observer: "_updateTarget",
}
},
ready: function() {
- if (this.countUp) {
- this.set('currentTime', 0);
- } else {
- this.set('currentTime', this.startTime);
- }
- this.set('_formattedTime', this._formatTime(this.currentTime.toString()));
+ if (this.currentTime===undefined) {
+ this.set('currentTime', this.countUp ? 0 : this.startTime);
+ }
+ this.set('_formattedTime', this._formatTime(this.currentTime.toString()));
},
start: function() {
@@ -199,5 +202,10 @@ Polymer({
hours = hours.toString().padStart(2, '0');
}
return (this.hours ? hours + ':' : '') + (this.minutes || this.hours ? minutes + ':' : '') + seconds + (this.fractions ? ('.' + timeString[1].substring(0,2)) : '')
- }
+ },
+ _updateTarget: function(newValue, oldValue){
+ if (document.getElementById(this.targetId)) {
+ document.getElementById(this.targetId).innerText = newValue;
+ }
+ }
});
\ No newline at end of file
diff --git a/src/test/java/com/flowingcode/addons/simpletimer/integration/AbstractViewTest.java b/src/test/java/com/flowingcode/addons/simpletimer/integration/AbstractViewTest.java
new file mode 100644
index 0000000..fff79d5
--- /dev/null
+++ b/src/test/java/com/flowingcode/addons/simpletimer/integration/AbstractViewTest.java
@@ -0,0 +1,106 @@
+/*-
+ * #%L
+ * Template Add-on
+ * %%
+ * Copyright (C) 2024 Flowing Code
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+package com.flowingcode.addons.simpletimer.integration;
+
+import com.vaadin.testbench.ScreenshotOnFailureRule;
+import com.vaadin.testbench.TestBench;
+import com.vaadin.testbench.parallel.ParallelTest;
+import io.github.bonigarcia.wdm.WebDriverManager;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.openqa.selenium.chrome.ChromeDriver;
+
+/**
+ * Base class for ITs
+ *
+ * The tests use Chrome driver (see pom.xml for integration-tests profile) to run integration
+ * tests on a headless Chrome. If a property {@code test.use .hub} is set to true, {@code
+ * AbstractViewTest} will assume that the TestBench test is running in a CI environment. In order to
+ * keep the this class light, it makes certain assumptions about the CI environment (such as
+ * available environment variables). It is not advisable to use this class as a base class for you
+ * own TestBench tests.
+ *
+ *
To learn more about TestBench, visit Vaadin TestBench.
+ */
+public abstract class AbstractViewTest extends ParallelTest {
+ private static final int SERVER_PORT = 8080;
+
+ private final String route;
+
+ @Rule public ScreenshotOnFailureRule rule = new ScreenshotOnFailureRule(this, true);
+
+ public AbstractViewTest() {
+ this("");
+ }
+
+ protected AbstractViewTest(String route) {
+ this.route = route;
+ }
+
+ @BeforeClass
+ public static void setupClass() {
+ WebDriverManager.chromedriver().setup();
+ }
+
+ @Override
+ @Before
+ public void setup() throws Exception {
+ if (isUsingHub()) {
+ super.setup();
+ } else {
+ setDriver(TestBench.createDriver(new ChromeDriver()));
+ }
+ getDriver().get(getURL(route));
+ }
+
+ /**
+ * Returns deployment host name concatenated with route.
+ *
+ * @return URL to route
+ */
+ private static String getURL(String route) {
+ return String.format("http://%s:%d/%s", getDeploymentHostname(), SERVER_PORT, route);
+ }
+
+ /** Property set to true when running on a test hub. */
+ private static final String USE_HUB_PROPERTY = "test.use.hub";
+
+ /**
+ * Returns whether we are using a test hub. This means that the starter is running tests in
+ * Vaadin's CI environment, and uses TestBench to connect to the testing hub.
+ *
+ * @return whether we are using a test hub
+ */
+ private static boolean isUsingHub() {
+ return Boolean.TRUE.toString().equals(System.getProperty(USE_HUB_PROPERTY));
+ }
+
+ /**
+ * If running on CI, get the host name from environment variable HOSTNAME
+ *
+ * @return the host name
+ */
+ private static String getDeploymentHostname() {
+ return isUsingHub() ? System.getenv("HOSTNAME") : "localhost";
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/flowingcode/addons/simpletimer/integration/IntegrationCallables.java b/src/test/java/com/flowingcode/addons/simpletimer/integration/IntegrationCallables.java
new file mode 100644
index 0000000..5513764
--- /dev/null
+++ b/src/test/java/com/flowingcode/addons/simpletimer/integration/IntegrationCallables.java
@@ -0,0 +1,29 @@
+package com.flowingcode.addons.simpletimer.integration;
+
+public interface IntegrationCallables {
+
+ void setStartTime(Integer startTime);
+
+ void setEndTime(Integer endTime);
+
+ void start();
+
+ void pause();
+
+ void reset();
+
+ boolean isRunning();
+
+ void openDialog();
+
+ void closeDialog();
+ // BigDecimal getCurrentTime();
+ //
+ // CompletableFuture getCurrentTimeAsync();
+ //
+ // Registration addCurrentTimeChangeListener(PropertyChangeListener listener, long period,
+ // TimeUnit periodUnit);
+ //
+ // Registration addTimerEndEvent(ComponentEventListener listener);
+
+}
diff --git a/src/test/java/com/flowingcode/addons/simpletimer/integration/IntegrationView.java b/src/test/java/com/flowingcode/addons/simpletimer/integration/IntegrationView.java
new file mode 100644
index 0000000..60f7bcd
--- /dev/null
+++ b/src/test/java/com/flowingcode/addons/simpletimer/integration/IntegrationView.java
@@ -0,0 +1,77 @@
+package com.flowingcode.addons.simpletimer.integration;
+
+import com.flowingcode.vaadin.addons.simpletimer.SimpleTimer;
+import com.vaadin.flow.component.ClientCallable;
+import com.vaadin.flow.component.dialog.Dialog;
+import com.vaadin.flow.component.html.Div;
+import com.vaadin.flow.component.html.Label;
+import com.vaadin.flow.router.Route;
+
+@Route("/it")
+public class IntegrationView extends Div implements IntegrationCallables {
+
+ private final SimpleTimer timer = new SimpleTimer();
+
+ private Dialog dialog;
+
+ private final Label timerTarget;
+
+ public IntegrationView() {
+ add(timer);
+ timerTarget = new Label();
+ timerTarget.setId("timerTarget");
+ timer.setTargetId("timerTarget");
+ }
+
+ @Override
+ @ClientCallable
+ public void openDialog() {
+ if (dialog == null) {
+ dialog = new Dialog(timerTarget);
+ }
+ dialog.open();
+ }
+
+ @Override
+ @ClientCallable
+ public void closeDialog() {
+ dialog.close();
+ }
+
+ @Override
+ @ClientCallable
+ public void setStartTime(final Integer startTime) {
+ timer.setStartTime(startTime);
+ }
+
+ @Override
+ @ClientCallable
+ public void setEndTime(final Integer endTime) {
+ timer.setEndTime(endTime);
+ }
+
+ @Override
+ @ClientCallable
+ public void start() {
+ timer.start();
+ }
+
+ @Override
+ @ClientCallable
+ public void pause() {
+ timer.pause();
+ }
+
+ @Override
+ @ClientCallable
+ public void reset() {
+ timer.reset();
+ }
+
+ @Override
+ @ClientCallable
+ public boolean isRunning() {
+ return timer.isRunning();
+ }
+
+}
diff --git a/src/test/java/com/flowingcode/addons/simpletimer/integration/SimpleIT.java b/src/test/java/com/flowingcode/addons/simpletimer/integration/SimpleIT.java
new file mode 100644
index 0000000..e9fae66
--- /dev/null
+++ b/src/test/java/com/flowingcode/addons/simpletimer/integration/SimpleIT.java
@@ -0,0 +1,90 @@
+package com.flowingcode.addons.simpletimer.integration;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+import com.flowingcode.vaadin.testbench.rpc.HasRpcSupport;
+import java.util.concurrent.TimeUnit;
+import org.junit.Test;
+
+public class SimpleIT extends AbstractViewTest implements HasRpcSupport {
+
+ IntegrationCallables $server = createCallableProxy(IntegrationCallables.class);
+
+ public SimpleIT() {
+ super("it");
+ }
+
+ private static void sleep(final long millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ private Double currentTime() {
+ return $(SimpleTimerElement.class).first().currentTime();
+ }
+
+ @Test
+ public void countDown() {
+ assertThat(currentTime(), nullValue());
+ assertFalse($server.isRunning());
+
+ $server.setStartTime(1);
+ assertThat(currentTime(), equalTo(1.0));
+
+ $server.start();
+ assertTrue($server.isRunning());
+ final double t0 = currentTime();
+ final double t1 = currentTime();
+ assertThat(t0, lessThan(1.0));
+ assertThat(t1, lessThan(t0));
+ }
+
+ @Test
+ public void countUp() {
+ assertThat(currentTime(), nullValue());
+ assertFalse($server.isRunning());
+
+ $server.setEndTime(1);
+ assertThat(currentTime(), equalTo(0.0));
+
+ $server.start();
+ assertTrue($server.isRunning());
+ final double t0 = currentTime();
+ final double t1 = currentTime();
+ assertThat(t0, greaterThan(0.0));
+ assertThat(t1, greaterThan(t0));
+ }
+
+ @Test
+ public void countUpInDialog() {
+ $server.openDialog();
+ $server.setEndTime(100);
+ assertThat(currentTime(), equalTo(0.0));
+
+ final long w0 = System.nanoTime();
+ $server.start();
+ final double t0 = currentTime();
+ assertThat(t0, greaterThan(0.0));
+ final long w1 = System.nanoTime();
+
+ $server.closeDialog();
+ sleep(0);
+ $server.openDialog();
+
+ final long w2 = System.nanoTime();
+ // double delta = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - now) / 1000.0;
+ final double t1 = currentTime();
+ final long w3 = System.nanoTime();
+ // assertThat(t1, greaterThan(t0 + delta));
+ System.out.println(TimeUnit.NANOSECONDS.toMillis(w3 - w0) / 1000.0);
+ System.out.println(TimeUnit.NANOSECONDS.toMillis(w2 - w1) / 1000.0);
+ System.out.println(t1 - t0);
+ System.out.println(t0);
+ System.out.println(t1);
+ }
+
+}
diff --git a/src/test/java/com/flowingcode/addons/simpletimer/integration/SimpleTimerElement.java b/src/test/java/com/flowingcode/addons/simpletimer/integration/SimpleTimerElement.java
new file mode 100644
index 0000000..a84b5b2
--- /dev/null
+++ b/src/test/java/com/flowingcode/addons/simpletimer/integration/SimpleTimerElement.java
@@ -0,0 +1,15 @@
+package com.flowingcode.addons.simpletimer.integration;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.elementsbase.Element;
+import java.util.Optional;
+
+@Element("simple-timer")
+public class SimpleTimerElement extends TestBenchElement {
+
+ Double currentTime() {
+ Number time = (Number) executeScript("return arguments[0].currentTime", this);
+ return Optional.ofNullable(time).map(Number::doubleValue).orElse(null);
+ }
+
+}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemo.java b/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemo.java
index adb133a..4be6692 100644
--- a/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemo.java
+++ b/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemo.java
@@ -75,7 +75,7 @@ public SimpletimerDemo() {
}
update();
});
- final Button start = new Button("Start/Stop", e -> timer.start());
+ final Button start = new Button("Start", e -> timer.start());
final Button stop = new Button("Stop", e -> timer.pause());
final Button reset =
new Button(
diff --git a/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemo2.java b/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemo2.java
new file mode 100644
index 0000000..c6a3ba5
--- /dev/null
+++ b/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemo2.java
@@ -0,0 +1,144 @@
+/*-
+ * #%L
+ * Simple Timer Addon
+ * %%
+ * Copyright (C) 2019 - 2020 Flowing Code
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+package com.flowingcode.vaadin.addons.simpletimer;
+
+import com.flowingcode.vaadin.addons.demo.DemoSource;
+import com.vaadin.flow.component.button.Button;
+import com.vaadin.flow.component.checkbox.Checkbox;
+import com.vaadin.flow.component.dialog.Dialog;
+import com.vaadin.flow.component.html.Div;
+import com.vaadin.flow.component.html.Label;
+import com.vaadin.flow.component.html.Span;
+import com.vaadin.flow.component.notification.Notification;
+import com.vaadin.flow.component.orderedlayout.FlexComponent.Alignment;
+import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+import com.vaadin.flow.component.textfield.TextField;
+import com.vaadin.flow.router.PageTitle;
+import com.vaadin.flow.router.Route;
+import java.math.BigDecimal;
+
+@SuppressWarnings("serial")
+@PageTitle("Simple Timer Demo")
+@DemoSource
+@Route(value = "simple-timer/simple-timer2", layout = SimpletimerDemoView.class)
+public class SimpletimerDemo2 extends Div {
+
+ private final SimpleTimer timer = new SimpleTimer();
+
+ private boolean countUpMode;
+ private BigDecimal time = new BigDecimal(60);
+
+ public SimpletimerDemo2() {
+ setSizeFull();
+ timer.setWidth("100px");
+ timer.setHeight("50px");
+ timer.getStyle().set("font-size", "40px");
+ timer.setStartTime(60);
+
+ final Span timerTitle = new Span("Simple Count Up Timer");
+
+ final TextField startTime =
+ new TextField("Start Time", e -> {
+ time = new BigDecimal(e.getValue());
+ update();
+ });
+ final Checkbox countUp = new Checkbox("Count Up", false);
+ countUp.addValueChangeListener(
+ e -> {
+ countUpMode = countUp.getValue();
+ if (countUpMode) {
+ startTime.setLabel("End Time");
+ timerTitle.setText("Simple Count Up Timer");
+ } else {
+ startTime.setLabel("Start Time");
+ timerTitle.setText("Simple Countdown Timer");
+ }
+ update();
+ });
+ final Button start = new Button("Start/Stop", e -> timer.start());
+ final Button stop = new Button("Stop", e -> timer.pause());
+ final Button reset =
+ new Button(
+ "Reset",
+ e -> {
+ timer.reset();
+ });
+ final Button running =
+ new Button(
+ "Current Time",
+ e ->
+ timer
+ .getCurrentTimeAsync()
+ .thenAccept(
+ time ->
+ Notification.show(
+ time.toPlainString()
+ + (timer.isRunning() ? "" : " (Not Running)"))));
+ final Checkbox fractions = new Checkbox("Fractions", true);
+ fractions.addValueChangeListener(e -> timer.setFractions(e.getValue()));
+ final Checkbox minutes = new Checkbox("Minutes", e -> timer.setMinutes(e.getValue()));
+ final Checkbox hours = new Checkbox("Hours", e -> timer.setHours(e.getValue()));
+ final Checkbox doubleDigitHours =
+ new Checkbox("Double digit hours", e -> timer.setDoubleDigitHours(e.getValue()));
+ final Checkbox visible =
+ new Checkbox(
+ "Visible",
+ e -> {
+ if (e.isFromClient()) {
+ timer.setVisible(!timer.isVisible());
+ }
+ });
+ visible.setValue(true);
+
+ timer.addTimerEndEvent(e -> Notification.show("Timer Ended"));
+
+ timer.setVisible(false);
+ final HorizontalLayout topLayout = new HorizontalLayout(timerTitle, timer);
+ topLayout.setAlignItems(Alignment.CENTER);
+
+ final HorizontalLayout options =
+ new HorizontalLayout(countUp, fractions, minutes, hours, visible, doubleDigitHours);
+ options.setAlignItems(Alignment.CENTER);
+ options.getStyle().set("flex-wrap", "wrap");
+
+ final HorizontalLayout bottomLayout = new HorizontalLayout(start, stop, reset, running);
+ bottomLayout.setAlignItems(Alignment.BASELINE);
+
+ add(new VerticalLayout(topLayout, startTime, options, bottomLayout));
+
+ final Label timerTarget = new Label();
+ timerTarget.setId("timerTarget");
+
+ final Dialog dlg = new Dialog(timerTarget);
+ dlg.setModal(false);
+ dlg.setCloseOnOutsideClick(false);
+ dlg.add(new Button("Close", ev -> dlg.close()));
+ add(new Button("OPEN", ev -> dlg.open()));
+ }
+
+ private void update() {
+ if (countUpMode) {
+ timer.setEndTime(time);
+ } else {
+ timer.setStartTime(time);
+ }
+ }
+}
diff --git a/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemoView.java b/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemoView.java
index 9367ae6..30549be 100644
--- a/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemoView.java
+++ b/src/test/java/com/flowingcode/vaadin/addons/simpletimer/SimpletimerDemoView.java
@@ -33,6 +33,7 @@ public class SimpletimerDemoView extends TabbedDemo {
public SimpletimerDemoView() {
addDemo(SimpletimerDemo.class);
+ addDemo(SimpletimerDemo2.class);
setSizeFull();
}
}
diff --git a/webpack.config.js b/webpack.config.js
deleted file mode 100644
index 4e575ad..0000000
--- a/webpack.config.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * This file has been autogenerated as it didn't exist or was made for an older incompatible version.
- * This file can be used for manual configuration will not be modified if the flowDefaults constant exists.
- */
-const merge = require('webpack-merge');
-const flowDefaults = require('./webpack.generated.js');
-
-module.exports = merge(flowDefaults, {
-
-});
-
-/**
- * This file can be used to configure the flow plugin defaults.
- *
- * // Add a custom plugin
- * flowDefaults.plugins.push(new MyPlugin());
- *
- * // Update the rules to also transpile `.mjs` files
- * if (!flowDefaults.module.rules[0].test) {
- * throw "Unexpected structure in generated webpack config";
- * }
- * flowDefaults.module.rules[0].test = /\.m?js$/
- *
- * // Include a custom JS in the entry point in addition to generated-flow-imports.js
- * if (typeof flowDefaults.entry.index != "string") {
- * throw "Unexpected structure in generated webpack config";
- * }
- * flowDefaults.entry.index = [flowDefaults.entry.index, "myCustomFile.js"];
- *
- * or add new configuration in the merge block.
- *
- * module.exports = merge(flowDefaults, {
- * mode: 'development',
- * devtool: 'inline-source-map'
- * });
- *
- */