Skip to content

Commit

Permalink
[BasicUI] Move some app settings to per-device (browser) settings
Browse files Browse the repository at this point in the history
Fix #1832

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.

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
  • Loading branch information
lolodomo committed Jan 3, 2024
1 parent b6aeaa5 commit 31795e0
Show file tree
Hide file tree
Showing 20 changed files with 576 additions and 237 deletions.
1 change: 1 addition & 0 deletions bundles/org.openhab.ui.basic/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ 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/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/settings.js" ],
sass: "web-src/smarthome.scss"
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@
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 @@ -31,77 +29,32 @@
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 {
Expand All @@ -118,10 +71,8 @@ public void applyConfig(Map<String, Object> configProps) {
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);
}
Expand All @@ -130,10 +81,6 @@ public String getDefaultSitemap() {
return defaultSitemap;
}

public String getTheme() {
return theme;
}

public String getCssClassList() {
String result = " ";
for (String item : cssClassList) {
Expand All @@ -150,19 +97,11 @@ 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 @@ -393,18 +393,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 @@ -452,6 +440,11 @@ public void setConfig(WebAppConfig config) {
this.config = config;
}

protected String localizeText(String key, String defaultValue) {
String val = localizeText(key);
return val != null ? val : defaultValue;
}

protected @Nullable String localizeText(String key) {
String result = "";
if (I18nUtil.isConstant(key)) {
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 @@ -191,26 +190,16 @@ private String buildButton(String item, @Nullable String lab, String cmd, @Nulla
button = button.replace("%item%", item);
button = button.replace("%cmd%", escapeHtml(command));
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;
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 Down Expand Up @@ -102,29 +100,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 +122,8 @@ 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);
snippet = snippet.replace("%ignore_refresh%", itemUIRegistry.getVisiblity(w) ? "false" : "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
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ public StringBuilder processPage(String id, String sitemap, String label, EList<
snippet = snippet.replaceAll("%main.long-polling-mode-msg%", longPollingModeMsg);
}
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
Expand All @@ -117,7 +116,6 @@ public StringBuilder processPage(String id, String sitemap, String label, EList<
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);
Expand Down Expand Up @@ -231,7 +229,6 @@ public CharSequence renderSitemapList(Set<SitemapProvider> sitemapProviders) thr
}
}

String pageSnippet = getSnippet("main_static");
String listSnippet = getSnippet("sitemaps_list");
String sitemapSnippet = getSnippet("sitemaps_list_item");

Expand Down Expand Up @@ -284,12 +281,70 @@ public CharSequence renderSitemapList(Set<SitemapProvider> sitemapProviders) thr

listSnippet = listSnippet.replace("%items%", 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);
return getSnippet("main_static") //
.replace("%title%", "Basic UI") //
.replace("%htmlclass%", "page-welcome-sitemaps") //
.replace("%show_settings%", "false") //
.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", "Auto"), "", buttons);
buildButton(localizeText("@text/ui.config.basic.theme.option.bright", "Bright"), "light", buttons);
buildButton(localizeText("@text/ui.config.basic.theme.option.dark", "Dark"), "dark", buttons);

String description = localizeText("@text/ui.config.basic.theme.description");
sb.append(getSnippet("setting_buttons")
.replace("%label%", escapeHtml(localizeText("@text/ui.config.basic.theme.label", "Theme")))
.replace("%description%", description != null ? escapeHtml(description) : "")
.replace("%key%", "openhab.ui:theme.dark").replace("%default%", "")
.replace("%buttons%", buttons.toString()));

renderSwitchSetting(localizeText("@text/ui.config.basic.enableIcons.label", "Enable Icons"),
localizeText("@text/ui.config.basic.enableIcons.description"), "enableIcons",
"openhab.ui.basic:enableIcons", "enabled", "disabled", true, sb);
// renderSwitchSetting(localizeText("@text/ui.config.basic.enableIconify.label", "Enable Iconify Icons"),
// localizeText("@text/ui.config.basic.enableIconify.description"), "enableIconify",
// "openhab.ui.basic:enableIconify", "enabled", "disabled", false, sb);
renderSwitchSetting(localizeText("@text/ui.config.basic.condensedLayout.label", "Condensed Layout"),
localizeText("@text/ui.config.basic.condensedLayout.description"), "condensedLayout",
"openhab.ui.basic:condensedLayout", "enabled", "disabled", false, sb);
renderSwitchSetting(localizeText("@text/ui.config.basic.capitalizeValues.label", "Capitalize Values"),
localizeText("@text/ui.config.basic.capitalizeValues.description"), "capitalizeValues",
"openhab.ui.basic:capitalizeValues", "enabled", "disabled", false, sb);
renderSwitchSetting(localizeText("@text/ui.config.basic.webAudio.label", "Web Audio"),
localizeText("@text/ui.config.basic.webAudio.description"), "webAudio", "openhab.ui:webaudio.enable",
"enabled", "", false, sb);

return getSnippet("main_static") //
.replace("%title%", "Basic UI Settings") //
.replace("%htmlclass%", "") //
.replace("%show_settings%", "true") //
.replace("%content%", sb.toString());
}

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%", ""));
}

return pageSnippet;
private void renderSwitchSetting(String label, @Nullable 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%", description != null ? 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 {
Expand Down

0 comments on commit 31795e0

Please sign in to comment.