Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BasicUI] Move most of app settings to per-device (browser) settings #2243

Merged
merged 1 commit into from
Mar 3, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions bundles/org.openhab.ui.basic/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/*
2 changes: 1 addition & 1 deletion bundles/org.openhab.ui.basic/gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<String> cssClassList = new ArrayList<>();

private static final Map<String, String> CSS_CLASSES;
private static final Map<String, Boolean> 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<String, Object> configProps) {
cssClassList.clear();

for (Entry<String, String> 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<String, Object> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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() : "");
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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%", "mdl-button-text");
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -102,29 +101,6 @@ public EList<Widget> 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");

Expand All @@ -147,8 +123,10 @@ public EList<Widget> 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<List<String>> periods = List.of(List.of("Last hour", "h"), List.of("Last 2 hours", "2h"),
Expand Down