From c4778a76fb742d17b1f1d3ca755da45bb3a163d6 Mon Sep 17 00:00:00 2001 From: Laurent Garnier Date: Fri, 2 Feb 2024 22:54:30 +0100 Subject: [PATCH] [BasicUI] Move most of app settings to per-device (browser) settings Fix #1832 Closes #1930 A new page is available to show and update all per-device settings. This page is accessible through the sitemap list page or the home page of any sitemap. Basic UI theme now matches the dark mode of Main UI. It can be updated either in Main UI or in the new page of Baisc UI. Web Audio can also be enabled either in Main UI or Basic UI. New settings are also available to control the size of the chart and the size of content (text, line) in the chart. Signed-off-by: Laurent Garnier --- bundles/org.openhab.ui.basic/.gitignore | 2 + bundles/org.openhab.ui.basic/gulpfile.js | 2 +- .../ui/basic/internal/WebAppConfig.java | 123 +--- .../render/AbstractWidgetRenderer.java | 27 +- .../internal/render/ButtongridRenderer.java | 21 +- .../basic/internal/render/ChartRenderer.java | 32 +- .../basic/internal/render/PageRenderer.java | 164 ++++- .../basic/internal/render/SwitchRenderer.java | 21 +- .../basic/internal/servlet/WebAppServlet.java | 15 +- .../main/resources/OH-INF/config/config.xml | 70 --- .../resources/OH-INF/i18n/basic.properties | 40 +- .../src/main/resources/snippets/button.html | 6 +- .../src/main/resources/snippets/main.html | 12 +- .../main/resources/snippets/main_static.html | 34 +- .../resources/snippets/setting_buttons.html | 16 + .../resources/snippets/setting_selection.html | 25 + .../resources/snippets/setting_switch.html | 19 + .../org.openhab.ui.basic/web-src/_layout.scss | 28 + .../web-src/_theming.scss | 37 +- .../org.openhab.ui.basic/web-src/settings.js | 448 +++++++++++++ .../org.openhab.ui.basic/web-src/smarthome.js | 588 ++++++++++++++---- .../org.openhab.ui.basic/web-src/static.js | 75 +++ .../src/main/resources/conf/basicui.cfg | 29 - 23 files changed, 1315 insertions(+), 519 deletions(-) create mode 100644 bundles/org.openhab.ui.basic/src/main/resources/snippets/setting_buttons.html create mode 100644 bundles/org.openhab.ui.basic/src/main/resources/snippets/setting_selection.html create mode 100644 bundles/org.openhab.ui.basic/src/main/resources/snippets/setting_switch.html create mode 100644 bundles/org.openhab.ui.basic/web-src/settings.js create mode 100644 bundles/org.openhab.ui.basic/web-src/static.js diff --git a/bundles/org.openhab.ui.basic/.gitignore b/bundles/org.openhab.ui.basic/.gitignore index 4a1ea5b512..c816b2df88 100644 --- a/bundles/org.openhab.ui.basic/.gitignore +++ b/bundles/org.openhab.ui.basic/.gitignore @@ -3,4 +3,6 @@ node npm_cache src/main/resources/web/smarthome.css src/main/resources/web/smarthome.js +src/main/resources/web/settings.js +src/main/resources/web/static.js src/main/resources/web/fonts/* diff --git a/bundles/org.openhab.ui.basic/gulpfile.js b/bundles/org.openhab.ui.basic/gulpfile.js index 74ff17ea1c..821942281a 100644 --- a/bundles/org.openhab.ui.basic/gulpfile.js +++ b/bundles/org.openhab.ui.basic/gulpfile.js @@ -9,7 +9,7 @@ var sources = { - js: "web-src/smarthome.js", + js: [ "web-src/smarthome.js", "web-src/static.js", "web-src/settings.js" ], sass: "web-src/smarthome.scss" }; diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/WebAppConfig.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/WebAppConfig.java index 8638ae5af1..cd46fb7c45 100644 --- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/WebAppConfig.java +++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/WebAppConfig.java @@ -12,11 +12,7 @@ */ package org.openhab.ui.basic.internal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -26,143 +22,26 @@ * * @author Vlad Ivanov - Initial contribution * @author Laurent Garnier - New config parameter "enableIconify" + * @author Laurent Garnier - Replace almost all (server) settings by browser settings */ @NonNullByDefault public class WebAppConfig { private static final String DEFAULT_SITEMAP = "default"; - - public static final String THEME_NAME_BRIGHT = "bright"; - public static final String THEME_NAME_DARK = "dark"; - public static final String THEME_NAME_SYSTEM = "system"; - private static final String DEFAULT_THEME = THEME_NAME_BRIGHT; - - private static final String DEFAULT_ICONS = "true"; - private static final String DEFAULT_ICONIFY = "false"; private static final String DEFAULT_INLINE_SVG = "false"; - private static final String DEFAULT_WEB_AUDIO = "false"; - - private static final String DEFAULT_CONFIG_NB_COLUMNS = "3-2"; - private static final int DEFAULT_NB_COLUMNS_DESKTOP = 3; - private static final int DEFAULT_NB_COLUMNS_TABLET = 2; private String defaultSitemap = DEFAULT_SITEMAP; - private String theme = DEFAULT_THEME; - private int nbColsDesktop = DEFAULT_NB_COLUMNS_DESKTOP; - private int nbColsTablet = DEFAULT_NB_COLUMNS_TABLET; - private boolean icons = Boolean.parseBoolean(DEFAULT_ICONS); - private boolean iconify = Boolean.parseBoolean(DEFAULT_ICONIFY); private boolean inlineSvg = Boolean.parseBoolean(DEFAULT_INLINE_SVG); - private boolean webAudio = Boolean.parseBoolean(DEFAULT_WEB_AUDIO); - - private List cssClassList = new ArrayList<>(); - - private static final Map CSS_CLASSES; - private static final Map CSS_DEFAULT_VALUES; - - private static final String CONFIG_ENABLE_ICONS = "enableIcons"; - private static final String CONFIG_CONDENSED_LAYOUT = "condensedLayout"; - private static final String CONFIG_NB_COLUMNS = "nbColumns"; - private static final String CONFIG_CAPITALIZE = "capitalizeValues"; - - static { - CSS_CLASSES = new HashMap<>(); - CSS_CLASSES.put(CONFIG_ENABLE_ICONS, "ui-icons-enabled"); - CSS_CLASSES.put(CONFIG_CONDENSED_LAYOUT, "ui-layout-condensed"); - CSS_CLASSES.put(CONFIG_CAPITALIZE, "ui-capitalize-values"); - - CSS_DEFAULT_VALUES = new HashMap<>(); - CSS_DEFAULT_VALUES.put(CONFIG_ENABLE_ICONS, true); - CSS_DEFAULT_VALUES.put(CONFIG_CONDENSED_LAYOUT, false); - CSS_DEFAULT_VALUES.put(CONFIG_CAPITALIZE, false); - } - - private void applyCssClasses(Map configProps) { - cssClassList.clear(); - - for (Entry entry : CSS_CLASSES.entrySet()) { - String key = entry.getKey(); - Boolean value = CSS_DEFAULT_VALUES.get(key); - Object configValue = configProps.get(key); - if (configValue != null) { - value = "true".equalsIgnoreCase(configValue.toString()); - } - if (value != null && value) { - cssClassList.add(entry.getValue()); - } - } - if (nbColsDesktop == 3) { - cssClassList.add("ui-large-window"); - } - } public void applyConfig(Map configProps) { defaultSitemap = (String) configProps.getOrDefault("defaultSitemap", DEFAULT_SITEMAP); - theme = (String) configProps.getOrDefault("theme", DEFAULT_THEME); - // "default" was previously valid. For backward compatibility, accept it but convert it to DEFAULT_THEME - if ("default".equals(theme)) { - theme = DEFAULT_THEME; - } - String nbColumns = (String) configProps.getOrDefault(CONFIG_NB_COLUMNS, DEFAULT_CONFIG_NB_COLUMNS); - if (nbColumns.length() == 3) { - try { - nbColsDesktop = Integer.parseInt(nbColumns.substring(0, 1)); - } catch (NumberFormatException e) { - nbColsDesktop = DEFAULT_NB_COLUMNS_DESKTOP; - } - try { - nbColsTablet = Integer.parseInt(nbColumns.substring(2, 3)); - } catch (NumberFormatException e) { - nbColsTablet = DEFAULT_NB_COLUMNS_TABLET; - } - } else { - nbColsDesktop = DEFAULT_NB_COLUMNS_DESKTOP; - nbColsTablet = DEFAULT_NB_COLUMNS_TABLET; - } - icons = "true".equalsIgnoreCase((String) configProps.getOrDefault(CONFIG_ENABLE_ICONS, DEFAULT_ICONS)); - iconify = "true".equalsIgnoreCase((String) configProps.getOrDefault("enableIconify", DEFAULT_ICONIFY)); inlineSvg = "true".equalsIgnoreCase((String) configProps.getOrDefault("inlineSvg", DEFAULT_INLINE_SVG)); - webAudio = "true".equalsIgnoreCase((String) configProps.getOrDefault("webAudio", DEFAULT_WEB_AUDIO)); - - applyCssClasses(configProps); } public String getDefaultSitemap() { return defaultSitemap; } - public String getTheme() { - return theme; - } - - public String getCssClassList() { - String result = " "; - for (String item : cssClassList) { - result += item + " "; - } - return result; - } - - public int getNbColsDesktop() { - return nbColsDesktop; - } - - public int getNbColsTablet() { - return nbColsTablet; - } - - public boolean isIconsEnabled() { - return icons; - } - - public boolean isIconifyEnabled() { - return iconify; - } - public boolean isInlineSvgEnabled() { return inlineSvg; } - - public boolean isWebAudio() { - return webAudio; - } } diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/AbstractWidgetRenderer.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/AbstractWidgetRenderer.java index 9ca1d19c0f..58ffac8494 100644 --- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/AbstractWidgetRenderer.java +++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/AbstractWidgetRenderer.java @@ -69,6 +69,9 @@ public abstract class AbstractWidgetRenderer implements WidgetRenderer { public static final String ICON_TYPE = "svg"; + private static final int DEFAULT_NB_COLUMNS_DESKTOP = 3; + private static final int DEFAULT_NB_COLUMNS_TABLET = 2; + public static final String PRIMARY_COLOR = "#3f51b5"; public static final String SECONDARY_COLOR = "#ff4081"; @@ -125,8 +128,8 @@ protected String preprocessSnippet(String originalSnippet, Widget w) { protected String preprocessSnippet(String originalSnippet, Widget w, boolean ignoreStateForIcon) { String snippet = preprocessIcon(originalSnippet, getCategory(w), ignoreStateForIcon); - snippet = snippet.replace("%cells%", String.valueOf(12 / config.getNbColsDesktop())); - snippet = snippet.replace("%cells_tablet%", String.valueOf(8 / config.getNbColsTablet())); + snippet = snippet.replace("%cells%", String.valueOf(12 / DEFAULT_NB_COLUMNS_DESKTOP)); + snippet = snippet.replace("%cells_tablet%", String.valueOf(8 / DEFAULT_NB_COLUMNS_TABLET)); snippet = snippet.replace("%widget_id%", itemUIRegistry.getWidgetId(w)); snippet = snippet.replace("%icon_with_state%", Boolean.valueOf(!ignoreStateForIcon).toString()); snippet = snippet.replace("%item%", w.getItem() != null ? w.getItem() : ""); @@ -170,9 +173,7 @@ protected String preprocessIcon(String originalSnippet, @Nullable String icon, b break; case ICON_SOURCE_IF: case ICON_SOURCE_ICONIFY: - if (config.isIconifyEnabled()) { - iconSnippet = getSnippet("icon_iconify"); - } + iconSnippet = getSnippet("icon_iconify"); break; case ICON_SOURCE_MATERIAL: iconSnippet = getSnippet("icon_material"); @@ -388,18 +389,6 @@ protected String processColor(Widget w, String originalSnippet) { if (color != null) { style = "style=\"color:" + color + "\""; - } else { - switch (config.getTheme()) { - case WebAppConfig.THEME_NAME_BRIGHT: - style = "style=\"color-scheme: light\""; - break; - case WebAppConfig.THEME_NAME_DARK: - style = "style=\"color-scheme: dark\""; - break; - default: - break; - } - } snippet = snippet.replace("%iconstyle%", style); @@ -446,13 +435,13 @@ public void setConfig(WebAppConfig config) { this.config = config; } - protected @Nullable String localizeText(String key) { + protected String localizeText(String key) { String result = ""; if (I18nUtil.isConstant(key)) { result = i18nProvider.getText(bundleContext.getBundle(), I18nUtil.stripConstant(key), "", localeProvider.getLocale()); } - return result; + return result != null ? result : ""; } protected @Nullable String getUnitForWidget(Widget widget) { diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/ButtongridRenderer.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/ButtongridRenderer.java index 23554e56f5..199c518ca8 100644 --- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/ButtongridRenderer.java +++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/ButtongridRenderer.java @@ -25,7 +25,6 @@ import org.openhab.core.model.sitemap.sitemap.Buttongrid; import org.openhab.core.model.sitemap.sitemap.Widget; import org.openhab.core.ui.items.ItemUIRegistry; -import org.openhab.ui.basic.internal.WebAppConfig; import org.openhab.ui.basic.render.RenderException; import org.openhab.ui.basic.render.WidgetRenderer; import org.osgi.framework.BundleContext; @@ -190,26 +189,16 @@ private String buildButton(String item, @Nullable String lab, String cmd, @Nulla button = button.replace("%item%", item); button = button.replace("%cmd%", escapeHtml(cmd)); String buttonClass = "buttongrid-button"; - String style = ""; - if (icon == null || !config.isIconsEnabled()) { - button = button.replace("%label%", escapeHtml(label)); + + button = button.replace("%label%", escapeHtml(label)); + if (icon == null) { + button = button.replace("%textclass%", ""); button = button.replace("%icon_snippet%", ""); } else { - button = button.replace("%label%", ""); + button = button.replace("%textclass%", "mdl-button-icon-text"); button = preprocessIcon(button, icon, true); buttonClass += " mdl-button-icon"; - switch (config.getTheme()) { - case WebAppConfig.THEME_NAME_BRIGHT: - style = "style=\"color-scheme: light\""; - break; - case WebAppConfig.THEME_NAME_DARK: - style = "style=\"color-scheme: dark\""; - break; - default: - break; - } } - button = button.replace("%buttonstyle%", style); button = button.replace("%class%", buttonClass); return button; diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/ChartRenderer.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/ChartRenderer.java index dd2d0cc65a..f57ecd3bee 100644 --- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/ChartRenderer.java +++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/ChartRenderer.java @@ -14,7 +14,6 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.Date; import java.util.List; import org.eclipse.emf.common.util.ECollections; @@ -29,7 +28,6 @@ import org.openhab.core.model.sitemap.sitemap.Chart; import org.openhab.core.model.sitemap.sitemap.Widget; import org.openhab.core.ui.items.ItemUIRegistry; -import org.openhab.ui.basic.internal.WebAppConfig; import org.openhab.ui.basic.render.RenderException; import org.openhab.ui.basic.render.WidgetRenderer; import org.osgi.framework.BundleContext; @@ -45,6 +43,7 @@ * * @author Kai Kreuzer - Initial contribution and API * @author Vlad Ivanov - BasicUI changes + * @author Laurent Garnier - Delegate the definition of certain chart URL parameters to the frontend (smarthome.js) */ @Component(service = WidgetRenderer.class) @NonNullByDefault @@ -102,29 +101,6 @@ public EList renderWidget(Widget w, StringBuilder sb, String sitemap) th chartUrl += "&legend=false"; } } - // add theme GET parameter - String chartTheme = null; - switch (config.getTheme()) { - case WebAppConfig.THEME_NAME_BRIGHT: - chartTheme = "bright"; - break; - case WebAppConfig.THEME_NAME_DARK: - chartTheme = "dark"; - break; - } - if (chartTheme != null) { - chartUrl += "&theme=" + chartTheme; - } - String url; - boolean ignoreRefresh; - if (!itemUIRegistry.getVisiblity(w)) { - url = URL_NONE_ICON; - ignoreRefresh = true; - } else { - // add timestamp to circumvent browser cache - url = chartUrl + "&t=" + (new Date()).getTime(); - ignoreRefresh = false; - } String snippet = getSnippet("chart"); @@ -147,8 +123,10 @@ public EList renderWidget(Widget w, StringBuilder sb, String sitemap) th snippet = snippet.replace("%id%", itemUIRegistry.getWidgetId(w)); snippet = snippet.replace("%proxied_url%", chartUrl); snippet = snippet.replace("%valid_url%", "true"); - snippet = snippet.replace("%ignore_refresh%", ignoreRefresh ? "true" : "false"); - snippet = snippet.replace("%url%", url); + // Let the frontend set the final URL with additional parameters depending on browser settings + // and schedule the refresh + snippet = snippet.replace("%ignore_refresh%", "true"); + snippet = snippet.replace("%url%", URL_NONE_ICON); snippet = snippet.replace("%legend%", Boolean.valueOf(legend).toString()); List> periods = List.of(List.of("Last hour", "h"), List.of("Last 2 hours", "2h"), diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/PageRenderer.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/PageRenderer.java index fbe33e0163..f4bbee1add 100644 --- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/PageRenderer.java +++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/PageRenderer.java @@ -42,6 +42,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.gson.JsonObject; + /** * This is an implementation of the {@link WidgetRenderer} interface, which * is the main entry point for HTML code construction. @@ -52,6 +54,7 @@ * @author Kai Kreuzer - Initial contribution and API * @author Vlad Ivanov - BasicUI changes * @author Laurent Garnier - primary/secondary colors + * @author Laurent Garnier - Build of new page for app settings */ @Component(service = { PageRenderer.class }) @NonNullByDefault @@ -91,16 +94,9 @@ public void removeWidgetRenderer(WidgetRenderer widgetRenderer) { public StringBuilder processPage(String id, String sitemap, String label, EList children, boolean async) throws RenderException { String snippet = getSnippet(async ? "layer" : "main"); - String offlineMsg = localizeText("@text/main.offline-msg"); - if (offlineMsg != null) { - snippet = snippet.replaceAll("%main.offline-msg%", offlineMsg); - } - String longPollingModeMsg = localizeText("@text/main.long-polling-mode-msg"); - if (longPollingModeMsg != null) { - snippet = snippet.replaceAll("%main.long-polling-mode-msg%", longPollingModeMsg); - } + snippet = snippet.replaceAll("%main.offline-msg%", localizeText("@text/main.offline-msg")); + snippet = snippet.replaceAll("%main.long-polling-mode-msg%", localizeText("@text/main.long-polling-mode-msg")); snippet = snippet.replaceAll("%id%", id); - snippet = snippet.replace("%config.web-audio%", Boolean.toString(config.isWebAudio())); // if the label contains a value span, we remove this span as // the title of a page/layer cannot deal with this @@ -114,10 +110,8 @@ public StringBuilder processPage(String id, String sitemap, String label, EList< snippet = snippet.replace("%label%", escapeHtml(labelPlain)); snippet = snippet.replace("%servletname%", WebAppServlet.SERVLET_PATH); snippet = snippet.replace("%sitemap%", sitemap); - snippet = snippet.replace("%htmlclass%", config.getCssClassList()); snippet = snippet.replace("%icon_type%", ICON_TYPE); snippet = snippet.replace("%inline%", config.isInlineSvgEnabled() ? "true" : "false"); - snippet = snippet.replace("%theme%", config.getTheme()); snippet = snippet.replace("%sitemapquery%", String.format("?sitemap=%s", sitemap)); snippet = snippet.replace("%primarycolor%", PRIMARY_COLOR); snippet = snippet.replace("%secondarycolor%", SECONDARY_COLOR); @@ -231,17 +225,14 @@ public CharSequence renderSitemapList(Set sitemapProviders) thr } } - String pageSnippet = getSnippet("main_static"); String listSnippet = getSnippet("sitemaps_list"); String sitemapSnippet = getSnippet("sitemaps_list_item"); StringBuilder sb = new StringBuilder(); if (sitemapList.isEmpty()) { String listEmptySnippet = getSnippet("sitemaps_list_empty"); - String text = localizeText("@text/sitemaps-list-empty.info"); - if (text != null) { - listEmptySnippet = listEmptySnippet.replace("%sitemaps-list-empty.info%", text); - } + listEmptySnippet = listEmptySnippet.replace("%sitemaps-list-empty.info%", + localizeText("@text/sitemaps-list-empty.info")); sb.append(listEmptySnippet); } else { sitemapList.sort((s1, s2) -> { @@ -272,24 +263,141 @@ public CharSequence renderSitemapList(Set sitemapProviders) thr } } - String text = localizeText("@text/sitemaps-list.welcome"); - if (text != null) { - listSnippet = listSnippet.replace("%sitemaps-list.welcome%", text); + listSnippet = listSnippet.replace("%sitemaps-list.welcome%", localizeText("@text/sitemaps-list.welcome")); + listSnippet = listSnippet.replace("%sitemaps-list.available-sitemaps%", + localizeText("@text/sitemaps-list.available-sitemaps")); + + listSnippet = listSnippet.replace("%items%", sb.toString()); + + return getSnippet("main_static") // + .replace("%title%", "Basic UI") // + .replace("%htmlclass%", "page-welcome-sitemaps") // + .replace("%relpath%", "") // + .replace("%script%", "static.js") // + .replace("%navigation%", "navigation-home") // + .replace("%content%", listSnippet); + } + + public CharSequence renderSettings() throws RenderException { + StringBuilder sb = new StringBuilder(); + + StringBuilder buttons = new StringBuilder(); + buildButton(localizeText("@text/ui.config.basic.theme.option.auto"), "", buttons); + buildButton(localizeText("@text/ui.config.basic.theme.option.bright"), "light", buttons); + buildButton(localizeText("@text/ui.config.basic.theme.option.dark"), "dark", buttons); + + sb.append(getSnippet("setting_buttons") + .replace("%label%", escapeHtml(localizeText("@text/ui.config.basic.theme.label"))) + .replace("%description%", escapeHtml(localizeText("@text/ui.config.basic.theme.description"))) + .replace("%key%", "openhab.ui:theme.dark").replace("%default%", "") + .replace("%buttons%", buttons.toString())); + + renderSwitchSetting(localizeText("@text/ui.config.basic.enableIcons.label"), + localizeText("@text/ui.config.basic.enableIcons.description"), "icons", "openhab.ui.basic:icons", + "enabled", "disabled", true, sb); + + renderSwitchSetting(localizeText("@text/ui.config.basic.enableIconify.label"), + localizeText("@text/ui.config.basic.enableIconify.description"), "iconify", "openhab.ui.basic:iconify", + "enabled", "disabled", false, sb); + + renderSwitchSetting(localizeText("@text/ui.config.basic.condensedLayout.label"), + localizeText("@text/ui.config.basic.condensedLayout.description"), "condensedLayout", + "openhab.ui.basic:condensedLayout", "enabled", "disabled", false, sb); + + buttons = new StringBuilder(); + buildButton("1", "1", buttons); + buildButton("2", "", buttons); + + sb.append(getSnippet("setting_buttons") + .replace("%label%", escapeHtml(localizeText("@text/ui.config.basic.nbColumnsTablet.label"))) + .replace("%description%", escapeHtml(localizeText("@text/ui.config.basic.nbColumnsTablet.description"))) + .replace("%key%", "openhab.ui.basic:nbColumnsTablet").replace("%default%", "") + .replace("%buttons%", buttons.toString())); + + buttons = new StringBuilder(); + buildButton("1", "1", buttons); + buildButton("2", "2", buttons); + buildButton("3", "", buttons); + + sb.append(getSnippet("setting_buttons") + .replace("%label%", escapeHtml(localizeText("@text/ui.config.basic.nbColumnsDesktop.label"))) + .replace("%description%", + escapeHtml(localizeText("@text/ui.config.basic.nbColumnsDesktop.description"))) + .replace("%key%", "openhab.ui.basic:nbColumnsDesktop").replace("%default%", "") + .replace("%buttons%", buttons.toString())); + + renderSwitchSetting(localizeText("@text/ui.config.basic.capitalizeValues.label"), + localizeText("@text/ui.config.basic.capitalizeValues.description"), "capitalizeValues", + "openhab.ui.basic:capitalizeValues", "enabled", "disabled", false, sb); + + renderSwitchSetting(localizeText("@text/ui.config.basic.webAudio.label"), + localizeText("@text/ui.config.basic.webAudio.description"), "webAudio", "openhab.ui:webaudio.enable", + "enabled", "", false, sb); + + StringBuilder rows = new StringBuilder(); + JsonObject jsonObject = new JsonObject(); + buildRow("chartSize", localizeText("@text/ui.config.basic.chartSize.option.default"), "", rows, jsonObject); + for (String val : new String[] { "360x180", "480x240", "600x300", "720x360", "840x420", "960x480" }) { + buildRow("chartSize", localizeText("@text/ui.config.basic.chartSize.option." + val), val, rows, jsonObject); } - text = localizeText("@text/sitemaps-list.available-sitemaps"); - if (text != null) { - listSnippet = listSnippet.replace("%sitemaps-list.available-sitemaps%", text); + sb.append(getSnippet("setting_selection") + .replace("%label%", escapeHtml(localizeText("@text/ui.config.basic.chartSize.label"))) + .replace("%description%", escapeHtml(localizeText("@text/ui.config.basic.chartSize.description"))) + .replace("%key%", "openhab.ui.basic:chartSize").replace("%default%", "") + .replace("%value_map%", escapeHtml(jsonObject.toString())).replace("%rows%", rows.toString())); + + rows = new StringBuilder(); + jsonObject = new JsonObject(); + buildRow("chartDPI", localizeText("@text/ui.config.basic.chartDPI.option.96"), "", rows, jsonObject); + for (String val : new String[] { "120", "144", "168", "192", "240" }) { + buildRow("chartDPI", localizeText("@text/ui.config.basic.chartDPI.option." + val), val, rows, jsonObject); } - listSnippet = listSnippet.replace("%items%", sb.toString()); + sb.append(getSnippet("setting_selection") + .replace("%label%", escapeHtml(localizeText("@text/ui.config.basic.chartDPI.label"))) + .replace("%description%", escapeHtml(localizeText("@text/ui.config.basic.chartDPI.description"))) + .replace("%key%", "openhab.ui.basic:chartDPI").replace("%default%", "") + .replace("%value_map%", escapeHtml(jsonObject.toString())).replace("%rows%", rows.toString())); + + return getSnippet("main_static") // + .replace("%title%", "Basic UI Settings") // + .replace("%htmlclass%", "") // + .replace("%relpath%", "../") // + .replace("%script%", "settings.js") // + .replace("%navigation%", "navigation-page") // + .replace("%content%", sb.toString()); + } - pageSnippet = pageSnippet.replace("%title%", "BasicUI"); - pageSnippet = pageSnippet.replace("%htmlclass%", config.getCssClassList() + " page-welcome-sitemaps"); - pageSnippet = pageSnippet.replace("%theme%", config.getTheme()); - pageSnippet = pageSnippet.replace("%content%", listSnippet); + private void buildButton(String label, String cmd, StringBuilder buttons) throws RenderException { + buttons.append(getSnippet("button") // + .replace("%cmd%", escapeHtml(cmd)) // + .replace("%label%", escapeHtml(label)) // + .replace("%textclass%", "") // + .replace("%icon_snippet%", "") // + .replace("%class%", "")); + } + + private void buildRow(String setting, String label, String cmd, StringBuilder rows, JsonObject jsonObject) + throws RenderException { + jsonObject.addProperty(cmd.isEmpty() ? "_empty_" : cmd, label); + rows.append(getSnippet("selection_row") // + .replace("%cmd%", escapeHtml(cmd)) // + .replace("%label%", escapeHtml(label)) // + .replace("%item%", setting) // + .replace("%checked%", "")); + } - return pageSnippet; + private void renderSwitchSetting(String label, String description, String setting, String key, String valueOn, + String valueOff, boolean defaultValue, StringBuilder builder) throws RenderException { + builder.append(getSnippet("setting_switch") // + .replace("%label%", escapeHtml(label)) // + .replace("%description%", escapeHtml(description)) // + .replace("%setting%", setting) // + .replace("%key%", key) // + .replace("%on%", valueOn) // + .replace("%off%", valueOff) // + .replace("%default%", defaultValue ? valueOn : valueOff)); } public CharSequence renderManifest(@Nullable String sitemapName) throws RenderException { diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/SwitchRenderer.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/SwitchRenderer.java index 5898f294a7..841f371f0d 100644 --- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/SwitchRenderer.java +++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/render/SwitchRenderer.java @@ -34,7 +34,6 @@ import org.openhab.core.types.State; import org.openhab.core.types.util.UnitUtils; import org.openhab.core.ui.items.ItemUIRegistry; -import org.openhab.ui.basic.internal.WebAppConfig; import org.openhab.ui.basic.render.RenderException; import org.openhab.ui.basic.render.WidgetRenderer; import org.osgi.framework.BundleContext; @@ -166,29 +165,17 @@ private void buildButton(Switch w, @Nullable String lab, String cmd, @Nullable S label = label.substring(0, maxLabelSize - 1) + ELLIPSIS; } - button = button.replace("%item%", w.getItem()); button = button.replace("%cmd%", escapeHtml(command)); String buttonClass = ""; - String style = ""; - if (icon == null || !config.isIconsEnabled()) { - button = button.replace("%label%", escapeHtml(label)); + button = button.replace("%label%", escapeHtml(label)); + if (icon == null) { + button = button.replace("%textclass%", ""); button = button.replace("%icon_snippet%", ""); } else { - button = button.replace("%label%", ""); + button = button.replace("%textclass%", "mdl-button-icon-text"); button = preprocessIcon(button, icon, true); buttonClass = "mdl-button-icon"; - switch (config.getTheme()) { - case WebAppConfig.THEME_NAME_BRIGHT: - style = "style=\"color-scheme: light\""; - break; - case WebAppConfig.THEME_NAME_DARK: - style = "style=\"color-scheme: dark\""; - break; - default: - break; - } } - button = button.replace("%buttonstyle%", style); State compareMappingState = state; if (state instanceof QuantityType) { // convert the item state to the command value for proper diff --git a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/servlet/WebAppServlet.java b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/servlet/WebAppServlet.java index 0ce2b7cccd..7418ac4592 100644 --- a/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/servlet/WebAppServlet.java +++ b/bundles/org.openhab.ui.basic/src/main/java/org/openhab/ui/basic/internal/servlet/WebAppServlet.java @@ -57,7 +57,7 @@ * * @author Kai Kreuzer - Initial contribution and API * @author Vlad Ivanov - Basic UI changes - * + * @author Laurent Garnier - New page /basicui/app/settings */ @Component(immediate = true, service = Servlet.class, configurationPid = "org.openhab.basicui", // property = Constants.SERVICE_PID + "=org.openhab.basicui") @@ -125,6 +125,14 @@ private void showSitemapList(ServletResponse res) throws IOException, RenderExce res.setContentType(CONTENT_TYPE); } + private void showSettings(ServletResponse res) throws IOException, RenderException { + PrintWriter resWriter; + resWriter = res.getWriter(); + resWriter.append(renderer.renderSettings()); + + res.setContentType(CONTENT_TYPE); + } + @Override protected void service(@NonNullByDefault({}) HttpServletRequest req, @NonNullByDefault({}) HttpServletResponse res) throws ServletException, IOException { @@ -151,6 +159,11 @@ protected void service(@NonNullByDefault({}) HttpServletRequest req, @NonNullByD } try { + if ("/settings".equals(req.getPathInfo())) { + showSettings(res); + return; + } + if (sitemap == null) { showSitemapList(res); return; diff --git a/bundles/org.openhab.ui.basic/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.ui.basic/src/main/resources/OH-INF/config/config.xml index 05d572d337..cddb695295 100644 --- a/bundles/org.openhab.ui.basic/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.ui.basic/src/main/resources/OH-INF/config/config.xml @@ -6,25 +6,6 @@ https://openhab.org/schemas/config-description-1.0.0.xsd"> - - - Defines the UI theme. - - - - - - bright - - - - Defines whether UI renders icons for the widgets or not. - - - - - true - If enabled, any SVG icon provided by the openHAB icon server will automatically be converted to an @@ -41,57 +22,6 @@ false - - - If enabled, the UI will render iconify icons directly by downloading them from the Internet and caching - them in the WEB browser. If disabled, the UI will use the standard method by requesting the server icon proxy and - assuming iconify icons are installed on the server. Default is disabled. - - - - - false - - - - When enabled, changes the layout so that more widgets can fit on the screen. - - - - - false - - - - The number of columns to consider to fill the grid in large screen width (desktop) and medium screen - width (tablet). - - - - - - - - 3-2 - - - - Displays all widget states in uppercase. - - - - - false - - - - Play audio sent to the web audio sink. - - - - - false - The sitemap to show if no parameter is passed. diff --git a/bundles/org.openhab.ui.basic/src/main/resources/OH-INF/i18n/basic.properties b/bundles/org.openhab.ui.basic/src/main/resources/OH-INF/i18n/basic.properties index 779e09224a..9533ee8984 100644 --- a/bundles/org.openhab.ui.basic/src/main/resources/OH-INF/i18n/basic.properties +++ b/bundles/org.openhab.ui.basic/src/main/resources/OH-INF/i18n/basic.properties @@ -1,41 +1,45 @@ ui.config.basic.capitalizeValues.label = Capitalize Values ui.config.basic.capitalizeValues.description = Displays all widget states in uppercase. -ui.config.basic.capitalizeValues.option.true = Enable -ui.config.basic.capitalizeValues.option.false = Disable +ui.config.basic.chartDPI.label = Chart DPI +ui.config.basic.chartDPI.description = Adjusts the size of the content (text, line) in the chart. +ui.config.basic.chartDPI.option.96 = 96 DPI (default) +ui.config.basic.chartDPI.option.120 = 120 DPI +ui.config.basic.chartDPI.option.144 = 144 DPI +ui.config.basic.chartDPI.option.168 = 168 DPI +ui.config.basic.chartDPI.option.192 = 192 DPI +ui.config.basic.chartDPI.option.240 = 240 DPI +ui.config.basic.chartSize.label = Chart Size +ui.config.basic.chartSize.description = Sets the size of the chart. +ui.config.basic.chartSize.option.default = Default +ui.config.basic.chartSize.option.360x180 = 360 x 180 (phone) +ui.config.basic.chartSize.option.480x240 = 480 x 240 (tablet) +ui.config.basic.chartSize.option.600x300 = 600 x 300 (tablet) +ui.config.basic.chartSize.option.720x360 = 720 x 360 (desktop) +ui.config.basic.chartSize.option.840x420 = 840 x 420 (desktop) +ui.config.basic.chartSize.option.960x480 = 960 x 480 (desktop) ui.config.basic.condensedLayout.label = Condensed Layout ui.config.basic.condensedLayout.description = When enabled, changes the layout so that more widgets can fit on the screen. -ui.config.basic.condensedLayout.option.true = Enable -ui.config.basic.condensedLayout.option.false = Disable ui.config.basic.defaultSitemap.label = Default Sitemap ui.config.basic.defaultSitemap.description = The sitemap to show if no parameter is passed. ui.config.basic.enableIconify.label = Enable Iconify Icons ui.config.basic.enableIconify.description = If enabled, the UI will render iconify icons directly by downloading them from the Internet and caching them in the WEB browser. If disabled, the UI will use the standard method by requesting the server icon proxy and assuming iconify icons are installed on the server. Default is disabled. -ui.config.basic.enableIconify.option.true = Enable -ui.config.basic.enableIconify.option.false = Disable ui.config.basic.enableIcons.label = Enable Icons ui.config.basic.enableIcons.description = Defines whether UI renders icons for the widgets or not. -ui.config.basic.enableIcons.option.true = Enable -ui.config.basic.enableIcons.option.false = Disable ui.config.basic.inlineSvg.label = Inline SVG ui.config.basic.inlineSvg.description = If enabled, any SVG icon provided by the openHAB icon server will automatically be converted to an inline SVG in the WEB page, allowing control of its color with the sitemap widget property "iconcolor" in the case where the SVG icon sets "currentColor" as the fill color. Note that this will work with custom SVG icons but not with all the packaged icons from the classic iconset since they are defined with a hard-coded color palette. This feature is disabled by default due to additional non-standard processing required leading to a larger page size and because it is unnecessary if you only use Material/framework7/iconify icons or openHAB icons from the classic icon set. ui.config.basic.inlineSvg.option.true = Enable ui.config.basic.inlineSvg.option.false = Disable -ui.config.basic.nbColumns.label = Number of Columns -ui.config.basic.nbColumns.description = The number of columns to consider to fill the grid in large screen width (desktop) and medium screen width (tablet). -ui.config.basic.nbColumns.option.1-1 = 1 column on desktop and tablet -ui.config.basic.nbColumns.option.2-1 = 2 columns on desktop but only 1 on tablet -ui.config.basic.nbColumns.option.2-2 = 2 columns on desktop and tablet -ui.config.basic.nbColumns.option.3-1 = 3 columns on desktop but only 1 on tablet -ui.config.basic.nbColumns.option.3-2 = 3 columns on desktop but only 2 on tablet +ui.config.basic.nbColumnsDesktop.label = Columns (desktop) +ui.config.basic.nbColumnsDesktop.description = Sets the number of columns to take into account when filling the grid for a large screen width (desktop). +ui.config.basic.nbColumnsTablet.label = Columns (tablet) +ui.config.basic.nbColumnsTablet.description = Sets the number of columns to take into account when filling the grid for a medium screen width (tablet). ui.config.basic.theme.label = Theme ui.config.basic.theme.description = Defines the UI theme. ui.config.basic.theme.option.bright = Bright ui.config.basic.theme.option.dark = Dark -ui.config.basic.theme.option.system = Follow System +ui.config.basic.theme.option.auto = Auto ui.config.basic.webAudio.label = Web Audio ui.config.basic.webAudio.description = Play audio sent to the web audio sink. -ui.config.basic.webAudio.option.true = Enable -ui.config.basic.webAudio.option.false = Disable # service diff --git a/bundles/org.openhab.ui.basic/src/main/resources/snippets/button.html b/bundles/org.openhab.ui.basic/src/main/resources/snippets/button.html index 2148173478..018f7121ce 100644 --- a/bundles/org.openhab.ui.basic/src/main/resources/snippets/button.html +++ b/bundles/org.openhab.ui.basic/src/main/resources/snippets/button.html @@ -1,6 +1,6 @@ - diff --git a/bundles/org.openhab.ui.basic/src/main/resources/snippets/main.html b/bundles/org.openhab.ui.basic/src/main/resources/snippets/main.html index c9285bb78e..f29e775c76 100644 --- a/bundles/org.openhab.ui.basic/src/main/resources/snippets/main.html +++ b/bundles/org.openhab.ui.basic/src/main/resources/snippets/main.html @@ -1,5 +1,5 @@ - + %label% @@ -28,10 +28,8 @@ - - - +