- ${this._auth_type != AuthenticationType.NOPASS ? html`
+ ${is_password_protected(this._auth_type) ? html`
@@ -181,6 +206,10 @@ export class QRCodeCardEditor extends LitElement implements LovelaceCardEditor {
this._updateConfig(ev.target.configValue, value);
}
+ private _toggleUnmaskedPassword(): void {
+ this._unmaskedPassword = !this._unmaskedPassword;
+ }
+
private _updateConfig(key: string, value: any) {
if (!this._config || !this.hass) {
return;
@@ -210,9 +239,17 @@ export class QRCodeCardEditor extends LitElement implements LovelaceCardEditor {
margin: 8px;
display: grid;
}
-
- ha-formfield {
- padding: 8px;
+
+ .values ha-icon-button {
+ flex-direction: column;
+ width: 24px;
+ height: 24px;
+ --mdc-icon-button-size: 24px;
+ color: var(--secondary-text-color);
+ }
+
+ .values ha-icon {
+ display: flex;
}
`;
}
diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json
index 5ea5b2d..9eb1168 100644
--- a/src/localize/languages/en.json
+++ b/src/localize/languages/en.json
@@ -6,6 +6,7 @@
},
"editor": {
"label": {
+ "title": "Title (optional)",
"source": "Source type (required)",
"text": "Text (required)",
"entity": "Entity (required)",
@@ -14,6 +15,10 @@
"password": "Password (required)",
"is_hidden": "Hidden (optional)"
},
+ "title": {
+ "show_password": "Show password",
+ "hide_password": "Hide password"
+ },
"options": {
"source": {
"text": "Text",
diff --git a/src/models/authentication-type.ts b/src/models/authentication-type.ts
index d98d277..c3369d4 100644
--- a/src/models/authentication-type.ts
+++ b/src/models/authentication-type.ts
@@ -3,3 +3,9 @@ export enum AuthenticationType {
WPA = "WPA",
NOPASS = "nopass",
}
+
+const PasswordAuthenticationTypes = [AuthenticationType.WEP, AuthenticationType.WPA];
+
+export function is_password_protected(auth_type: AuthenticationType | undefined): boolean {
+ return auth_type !== undefined && PasswordAuthenticationTypes.includes(auth_type);
+}
diff --git a/src/models/generator.ts b/src/models/generator.ts
index 80e3df7..8b02376 100644
--- a/src/models/generator.ts
+++ b/src/models/generator.ts
@@ -7,7 +7,7 @@ import {
TextSourceConfig,
WiFiSourceConfig,
} from "../types/types";
-import { AuthenticationType } from "./authentication-type";
+import { is_password_protected } from "./authentication-type";
import { SourceType } from "./source-type";
import { localize } from "../localize/localize";
import { HomeAssistant } from "custom-card-helpers";
@@ -66,7 +66,7 @@ class WiFiQRCodeGenerator extends QRCodeGenerator
{
protected get input(): string {
let text = `WIFI:T:${this.config.auth_type || ""};S:${this._escape(this.config.ssid || "")};`;
- if (this.config.auth_type !== AuthenticationType.NOPASS) {
+ if (is_password_protected(this.config.auth_type)) {
text += `P:${this._escape(this.config.password || "")};`
}
diff --git a/src/qr-code-card.ts b/src/qr-code-card.ts
index 93e6a98..7b9a296 100644
--- a/src/qr-code-card.ts
+++ b/src/qr-code-card.ts
@@ -113,6 +113,7 @@ export class QRCodeCard extends LitElement {
return html`
+ ${(this.config?.title ?? "").length > 0 ? html``: ""}
diff --git a/src/types/types.ts b/src/types/types.ts
index 72eaffc..274fce7 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -17,9 +17,11 @@ export type Language = string | undefined;
export type DataUrl = string;
export type QRCodeGeneratorClass = new (...args: any[]) => T;
+export type QRCodeValidatorClass = new (...args: any[]) => T;
export interface BaseQRCodeCardConfig extends LovelaceCardConfig {
readonly language?: Language;
+ readonly title?: string;
readonly source: SourceType;
}
diff --git a/src/validators.ts b/src/validators.ts
index 8ff49b8..480d1ac 100644
--- a/src/validators.ts
+++ b/src/validators.ts
@@ -3,59 +3,110 @@ import {
QRCodeCardConfig,
TextSourceConfig,
WiFiSourceConfig,
- EntitySourceConfig
+ EntitySourceConfig,
+ QRCodeValidatorClass
} from "./types/types";
import { localize } from "./localize/localize";
import { SourceType } from "./models/source-type";
-import { AuthenticationType } from "./models/authentication-type";
+import { AuthenticationType, is_password_protected } from "./models/authentication-type";
+
+
+abstract class Validator {
+
+ protected readonly config: T;
+
+ public constructor(config: T) {
+ this.config = config;
+ }
+
+ public validate(): string[] {
+ return this._validate()
+ }
+
+ protected abstract _validate(): string[]
-function validateSource(source: SourceType): string[] {
- if (!source) return ["validation.source.missing"];
- if (!Object.values(SourceType).includes(source)) return ["validation.source.invalid"];
- return [];
}
-function validateTextConfig(text: string): string[] {
- if (!text) return ["validation.text.missing"];
- return [];
+class SourceValidator extends Validator {
+ protected _validate(): string[] {
+ const errors: string[] = [];
+
+ if (!this.config.source) {
+ errors.push("validation.source.missing");
+ }
+ else {
+ if (!Object.values(SourceType).includes(this.config.source)) {
+ errors.push("validation.source.invalid");
+ }
+ }
+
+ return errors;
+ }
}
+class TextValidator extends Validator {
+ protected _validate(): string[] {
+ const errors: string[] = [];
-function validateWiFiConfig(auth_type: AuthenticationType, ssid: string, password: string | undefined): string[] {
- if (!auth_type) return ["validation.auth_type.missing"];
- if (!Object.values(AuthenticationType).includes(auth_type)) return ["validation.auth_type.invalid"];
+ if (!this.config.text) errors.push("validation.text.missing");
- const errors: string[] = [];
- if (!ssid) {
- errors.push("validation.ssid.missing");
+ return errors;
}
- if (auth_type != AuthenticationType.NOPASS && !password) {
- errors.push("validation.password.missing");
+}
+
+class WiFiValidator extends Validator {
+ protected _validate(): string[] {
+ const errors: string[] = [];
+
+ // Validate auth type
+ if (!this.config.auth_type) {
+ errors.push("validation.auth_type.missing");
+ }
+ else {
+ if (!Object.values(AuthenticationType).includes(this.config.auth_type)){
+ errors.push("validation.auth_type.invalid");
+ }
+ }
+
+ // Validate ssid
+ if (!this.config.ssid) {
+ errors.push("validation.ssid.missing");
+ }
+
+ // Validate password
+ if (is_password_protected(this.config.auth_type) && !this.config.password) {
+ errors.push("validation.password.missing");
+ }
+
+ return errors;
}
- return errors;
}
-function validateEntityConfig(entity: string): string[] {
- if (!entity) return ["validation.entity.missing"];
- return [];
+class EntityValidator extends Validator {
+ protected _validate(): string[] {
+ const errors: string[] = [];
+
+ if (!this.config.entity) errors.push("validation.entity.missing");
+
+ return errors;
+ }
}
+const validatorMap = new Map>>([
+ [SourceType.TEXT, TextValidator],
+ [SourceType.WIFI, WiFiValidator],
+ [SourceType.ENTITY, EntityValidator]
+]);
+
export function validateConfig(config: QRCodeCardConfig): string[] {
const errors: TranslatableString[] = [];
- validateSource(config.source).forEach(e => errors.push(e));
- switch (config.source) {
- case SourceType.TEXT:
- config = config as TextSourceConfig;
- validateTextConfig(config.text).forEach(e => errors.push(e));
- break;
- case SourceType.WIFI:
- config = config as WiFiSourceConfig;
- validateWiFiConfig(config.auth_type, config.ssid, config.password).forEach(e => errors.push(e));
- break;
- case SourceType.ENTITY:
- config = config as EntitySourceConfig;
- validateEntityConfig(config.entity).forEach(e => errors.push(e));
- break;
+
+ new SourceValidator(config).validate().forEach(e => errors.push(e));
+
+ if (errors.length == 0) {
+ const validatorCls = validatorMap.get(config.source);
+ if (validatorCls) new validatorCls(config).validate().forEach(e => errors.push(e));
}
+
return errors.map(e => localize(e, config.language));
}