From e019b754a370261fbc4deb9917cc696477702918 Mon Sep 17 00:00:00 2001 From: rusikv Date: Tue, 28 May 2024 13:11:29 +0300 Subject: [PATCH] UI: added basic/advanced config for mobile app qr code widget, added QR code responsiveness --- .../widget_types/mobile_app_qr_code.json | 10 +- .../basic/basic-widget-config.module.ts | 10 +- ...le-app-qr-code-basic-config.component.html | 118 ++++++++++++ ...bile-app-qr-code-basic-config.component.ts | 182 ++++++++++++++++++ .../cards/mobile-app-qr-code-widget.models.ts | 39 ++-- .../mobile-app-qrcode-widget.component.html | 17 +- .../mobile-app-qrcode-widget.component.scss | 59 ++++-- .../lib/mobile-app-qrcode-widget.component.ts | 94 +++++---- ...app-qr-code-widget-settings.component.html | 89 ++++----- ...e-app-qr-code-widget-settings.component.ts | 41 ++-- .../assets/dashboard/sys_admin_home_page.json | 26 ++- .../dashboard/tenant_admin_home_page.json | 26 ++- .../assets/locale/locale.constant-en_US.json | 3 + 13 files changed, 554 insertions(+), 160 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/mobile-app-qr-code-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/mobile-app-qr-code-basic-config.component.ts diff --git a/application/src/main/data/json/system/widget_types/mobile_app_qr_code.json b/application/src/main/data/json/system/widget_types/mobile_app_qr_code.json index 37f7df0ae6..f3929d88f1 100644 --- a/application/src/main/data/json/system/widget_types/mobile_app_qr_code.json +++ b/application/src/main/data/json/system/widget_types/mobile_app_qr_code.json @@ -7,15 +7,17 @@ "descriptor": { "type": "static", "sizeX": 7.5, - "sizeY": 3, + "sizeY": 4, "resources": [], - "templateHtml": "\n", + "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n}\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.typeParameters = function() {\n return {\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true\n };\n};", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-mobile-app-qr-code-widget-settings", - "defaultConfig": "{\n \"showTitle\": true,\n \"backgroundColor\": \"rgb(255, 255, 255)\",\n \"color\": \"rgba(0, 0, 0, 0.87)\",\n \"padding\": \"8px\",\n \"settings\": {\n \"useSystemSettings\": true,\n \"androidConfig\": {\n \"enabled\": true\n },\n \"iosConfig\": {\n \"enabled\": true\n },\n \"qrCodeConfig\": {\n \"badgeEnabled\": true,\n \"badgeStyle\": \"ORIGINAL\",\n \"badgePosition\": \"RIGHT\",\n \"qrCodeLabelEnabled\": true,\n \"qrCodeLabel\": \"Scan to connect or download mobile app\"\n }\n },\n \"title\": \"Mobile app QR code\",\n \"dropShadow\": true,\n \"enableFullscreen\": false,\n \"widgetStyle\": {},\n \"widgetCss\": \"\",\n \"pageSize\": 1024,\n \"noDataDisplayMessage\": \"\",\n \"showTitleIcon\": false,\n \"titleTooltip\": \"\",\n \"titleStyle\": {\n \"fontSize\": \"16px\",\n \"fontWeight\": 400\n }\n}\n" + "hasBasicMode": true, + "basicModeDirective": "tb-mobile-app-qr-code-basic-config", + "defaultConfig": "{\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"useSystemSettings\":true,\"qrCodeConfig\":{\"badgeEnabled\":true,\"badgePosition\":\"RIGHT\",\"qrCodeLabelEnabled\":true,\"qrCodeLabel\":\"Scan to connect or download mobile app\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Mobile app QR code\",\"dropShadow\":true,\"showTitleIcon\":false,\"titleTooltip\":\"\",\"enableFullscreen\":false,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetStyle\":{},\"widgetCss\":\"\",\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}" }, "tags": [ "ios", diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 18b80f86a5..0f4f95650a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -129,6 +129,7 @@ import { import { RadarChartBasicConfigComponent } from '@home/components/widget/config/basic/chart/radar-chart-basic-config.component'; +import { MobileAppQrCodeBasicConfigComponent } from '@home/components/widget/config/basic/cards/mobile-app-qr-code-basic-config.component'; @NgModule({ declarations: [ @@ -171,7 +172,8 @@ import { PieChartBasicConfigComponent, BarChartBasicConfigComponent, PolarAreaChartBasicConfigComponent, - RadarChartBasicConfigComponent + RadarChartBasicConfigComponent, + MobileAppQrCodeBasicConfigComponent ], imports: [ CommonModule, @@ -216,7 +218,8 @@ import { PieChartBasicConfigComponent, BarChartBasicConfigComponent, PolarAreaChartBasicConfigComponent, - RadarChartBasicConfigComponent + RadarChartBasicConfigComponent, + MobileAppQrCodeBasicConfigComponent ] }) export class BasicWidgetConfigModule { @@ -255,5 +258,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type + +
+
+ + {{ 'admin.mobile-app.use-system-settings' | translate }} + +
+
+
+
+
widget-config.appearance
+
{{ 'widgets.mobile-app-qr-code.configuration-hint' | translate }}
+
+ + {{ 'admin.mobile-app.badges' | translate }} + + + + + {{ badgePosition.value | translate }} + + + +
+
+ + {{ 'admin.mobile-app.label' | translate }} + + + + + warning + + +
+
+ + {{ 'widgets.liquid-level-card.title' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.liquid-level-card.icon' | translate }} + +
+ + + + + + + + +
+
+
+
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/mobile-app-qr-code-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/mobile-app-qr-code-basic-config.component.ts new file mode 100644 index 0000000000..25f091df7b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/mobile-app-qr-code-basic-config.component.ts @@ -0,0 +1,182 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// 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. +/// + +import { ChangeDetectorRef, Component, Injector } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { WidgetConfig } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { isUndefined } from '@core/utils'; +import { cssSizeToStrSize, resolveCssSize } from '@shared/models/widget-settings.models'; +import { + mobileAppQrCodeWidgetDefaultSettings, + MobileAppQrCodeWidgetSettings +} from '@home/components/widget/lib/cards/mobile-app-qr-code-widget.models'; +import { badgePositionTranslationsMap } from '@app/shared/models/mobile-app.models'; + +@Component({ + selector: 'tb-mobile-app-qr-code-basic-config', + templateUrl: './mobile-app-qr-code-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class MobileAppQrCodeBasicConfigComponent extends BasicWidgetConfigComponent { + + mobileAppQrCodeWidgetConfigForm: UntypedFormGroup; + badgePositionTranslationsMap = badgePositionTranslationsMap; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private cd: ChangeDetectorRef, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.mobileAppQrCodeWidgetConfigForm; + } + + protected setupConfig(widgetConfig: WidgetConfigComponentData) { + super.setupConfig(widgetConfig); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: MobileAppQrCodeWidgetSettings = {...mobileAppQrCodeWidgetDefaultSettings, ...(configData.config.settings || {})}; + const iconSize = resolveCssSize(configData.config.iconSize); + + this.mobileAppQrCodeWidgetConfigForm = this.fb.group({ + useSystemSettings: [settings.useSystemSettings], + + badgeEnabled: [settings.qrCodeConfig.badgeEnabled], + badgePosition: [settings.qrCodeConfig.badgePosition], + qrCodeLabelEnabled: [settings.qrCodeConfig.qrCodeLabelEnabled], + qrCodeLabel: [settings.qrCodeConfig.qrCodeLabel], + + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], + showTitleIcon: [configData.config.showTitleIcon, []], + iconSize: [iconSize[0], [Validators.min(0)]], + iconSizeUnit: [iconSize[1], []], + titleIcon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + + background: [settings.background, []], + + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; + + this.widgetConfig.config.showTitleIcon = config.showTitleIcon; + this.widgetConfig.config.iconSize = cssSizeToStrSize(config.iconSize, config.iconSizeUnit); + this.widgetConfig.config.titleIcon = config.titleIcon; + this.widgetConfig.config.iconColor = config.iconColor; + + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.widgetConfig.config.settings.useSystemSettings = config.useSystemSettings; + this.widgetConfig.config.settings.qrCodeConfig = { + badgeEnabled: config.badgeEnabled, + badgePosition: config.badgePosition, + qrCodeLabelEnabled: config.qrCodeLabelEnabled, + qrCodeLabel: config.qrCodeLabel + }; + + this.widgetConfig.config.settings.background = config.background; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitleIcon', 'badgeEnabled', 'qrCodeLabelEnabled', 'showTitleIcon', 'showTitle']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const useSystemSettings = this.mobileAppQrCodeWidgetConfigForm.get('useSystemSettings').value; + + if (!useSystemSettings) { + const badgeEnabled = this.mobileAppQrCodeWidgetConfigForm.get('badgeEnabled').value; + const qrCodeLabelEnabled = this.mobileAppQrCodeWidgetConfigForm.get('qrCodeLabelEnabled').value; + const showTitleIcon: boolean = this.mobileAppQrCodeWidgetConfigForm.get('showTitleIcon').value; + const showTitle: boolean = this.mobileAppQrCodeWidgetConfigForm.get('showTitle').value; + + if (badgeEnabled) { + this.mobileAppQrCodeWidgetConfigForm.get('badgePosition').enable({emitEvent: false}); + } else { + this.mobileAppQrCodeWidgetConfigForm.get('badgePosition').disable({emitEvent: false}); + } + if (qrCodeLabelEnabled) { + this.mobileAppQrCodeWidgetConfigForm.get('qrCodeLabel').enable({emitEvent: false}); + } else { + this.mobileAppQrCodeWidgetConfigForm.get('qrCodeLabel').disable({emitEvent: false}); + } + if (showTitle) { + this.mobileAppQrCodeWidgetConfigForm.get('title').enable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('titleFont').enable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('titleColor').enable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); + if (showTitleIcon) { + this.mobileAppQrCodeWidgetConfigForm.get('titleIcon').enable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconColor').enable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconSize').enable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconSizeUnit').enable({emitEvent: false}); + } else { + this.mobileAppQrCodeWidgetConfigForm.get('titleIcon').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconColor').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconSize').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconSizeUnit').disable({emitEvent: false}); + } + } else { + this.mobileAppQrCodeWidgetConfigForm.get('title').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('titleFont').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('titleColor').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('titleIcon').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconColor').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconSize').disable({emitEvent: false}); + this.mobileAppQrCodeWidgetConfigForm.get('iconSizeUnit').disable({emitEvent: false}); + } + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/mobile-app-qr-code-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/mobile-app-qr-code-widget.models.ts index c37c4a9769..df18b8ac49 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/mobile-app-qr-code-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/mobile-app-qr-code-widget.models.ts @@ -14,32 +14,41 @@ /// limitations under the License. /// -import { - AndroidConfig, - BadgePosition, - IosConfig, - QRCodeConfig -} from '@shared/models/mobile-app.models'; +import { BadgePosition, QRCodeConfig } from '@shared/models/mobile-app.models'; +import { BackgroundType } from '@shared/models/widget-settings.models'; +import { WidgetConfig } from '@shared/models/widget.models'; -export interface MobileAppQrCodeWidgetSettings { +export interface MobileAppQrCodeWidgetSettings extends WidgetConfig { useSystemSettings: boolean; - androidConfig: Pick; - iosConfig: Pick; qrCodeConfig: Omit; } export const mobileAppQrCodeWidgetDefaultSettings: MobileAppQrCodeWidgetSettings = { useSystemSettings: true, - androidConfig: { - enabled: true - }, - iosConfig: { - enabled: true - }, qrCodeConfig: { badgeEnabled: true, badgePosition: BadgePosition.RIGHT, qrCodeLabelEnabled: true, qrCodeLabel: 'Scan to connect or download mobile app' + }, + title: 'Download mobile app', + titleFont: { + family: 'Roboto', + size: 16, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '1.5' + }, + showTitleIcon: false, + iconSize: '40', + background: { + type: BackgroundType.color, + color: '#fff', + overlay: { + enabled: false, + color: 'rgba(255,255,255,0.72)', + blur: 3 + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.html index 7e6331b82b..060b2bacf7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.html @@ -15,14 +15,19 @@ limitations under the License. --> -
-
+
+ +
- -
- - +
+
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.scss index 364d7bfad9..83290a27da 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.scss @@ -17,23 +17,60 @@ @import '../../../../../../scss/constants'; :host { + width: 100%; height: 100%; display: flex; - flex-direction: column; - background-color: transparent; + justify-content: center; } -.tb-qrcode-label { - font-size: 14px; - color: rgba(0, 0, 0, 0.54); +.tb-mobile-app-qrcode-panel { + width: 100%; + height: 100%; + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + gap: 8px; + padding: 16px; + &.preview { + max-width: 300px; + padding: 0; + } + > div:not(.tb-mobile-app-qrcode-overlay) { + z-index: 1; + } + .tb-mobile-app-qrcode-overlay { + position: absolute; + top: 12px; + left: 12px; + bottom: 12px; + right: 12px; + } - @media #{$mat-md-lg} { - font-size: 11px; - line-height: 16px; + div.tb-widget-title { + padding: 0; + } + + .tb-qrcode-label { + align-self: center; + font-size: 14px; + color: rgba(0, 0, 0, 0.54); } -} -.tb-qrcode { - border-radius: 6px; + .tb-qrcode { + display: flex; + flex: 0.3; + min-width: 100px; + padding: 3px; + border-radius: 6px; + background-color: #fff; + } + + .tb-badges { + display: flex; + flex-direction: column; + flex: 0.4; + gap: 8px; + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts index b8c9229201..6aeef19b19 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/mobile-app-qrcode-widget.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { AppState } from '@core/core.state'; import { Store } from '@ngrx/store'; @@ -22,11 +22,13 @@ import { BadgePosition, MobileAppSettings } from '@shared/models/mobile-app.mode import { MobileAppService } from '@core/http/mobile-app.service'; import { WidgetContext } from '@home/models/widget-component.models'; import { UtilsService } from '@core/services/utils.service'; -import { Subject } from 'rxjs'; +import { Observable, Subject } from 'rxjs'; import { MINUTE } from '@shared/models/time/time.models'; -import { MobileAppQrCodeWidgetSettings } from '@home/components/widget/lib/cards/mobile-app-qr-code-widget.models'; -import { isDefinedAndNotNull } from '@core/utils'; +import { isDefinedAndNotNull, mergeDeep } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; +import { backgroundStyle, ComponentStyle, overlayStyle } from '@shared/models/widget-settings.models'; +import { ImagePipe } from '@shared/pipe/image.pipe'; +import { DomSanitizer } from '@angular/platform-browser'; @Component({ selector: 'tb-mobile-app-qrcode-widget', @@ -35,61 +37,76 @@ import { ResizeObserver } from '@juggle/resize-observer'; }) export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnInit, OnDestroy { + private readonly destroy$ = new Subject(); + private widgetResize$: ResizeObserver; + + private mobileAppSettingsValue: MobileAppSettings; + private deepLink: string; + private deepLinkTTL: number; + private deepLinkTTLTimeoutID: NodeJS.Timeout; + + previewMode = false; + + badgePosition = BadgePosition; + showBadgeContainer = true; + + backgroundStyle$: Observable; + overlayStyle: ComponentStyle = {}; + + qrCodeSVG = ''; + @Input() ctx: WidgetContext; @Input() - set mobileAppSettings(settings: MobileAppSettings | MobileAppQrCodeWidgetSettings) { + widgetTitlePanel: TemplateRef; + + @Input() + set mobileAppSettings(settings: MobileAppSettings) { if (settings) { this.mobileAppSettingsValue = settings; } }; - get mobileAppSettings(): MobileAppSettings | MobileAppQrCodeWidgetSettings { + get mobileAppSettings(): MobileAppSettings { return this.mobileAppSettingsValue; } - @ViewChild('canvas', {static: true}) canvasRef: ElementRef; - - private readonly destroy$ = new Subject(); - private widgetResize$: ResizeObserver; - - badgePosition = BadgePosition; - showBadgeContainer = true; - - private mobileAppSettingsValue: MobileAppSettings | MobileAppQrCodeWidgetSettings; - private deepLink: string; - private deepLinkTTL: number; - private deepLinkTTLTimeoutID: NodeJS.Timeout; - constructor(protected store: Store, protected cd: ChangeDetectorRef, private mobileAppService: MobileAppService, private utilsService: UtilsService, - private elementRef: ElementRef) { + private elementRef: ElementRef, + private imagePipe: ImagePipe, + private sanitizer: DomSanitizer,) { super(store); } ngOnInit(): void { if (!this.mobileAppSettings) { - if (isDefinedAndNotNull(this.ctx.settings.useSystemSettings) && !this.ctx.settings.useSystemSettings) { - this.mobileAppSettings = this.ctx.settings; - } else { - this.mobileAppService.getMobileAppSettings().subscribe((settings => { - this.mobileAppSettings = settings; - this.cd.markForCheck(); - })); - } + this.mobileAppService.getMobileAppSettings().subscribe((settings => { + this.mobileAppSettings = settings; + if (isDefinedAndNotNull(this.ctx.settings.useSystemSettings) && !this.ctx.settings.useSystemSettings) { + this.mobileAppSettings = mergeDeep(this.mobileAppSettings, this.ctx.settings); + } + + this.widgetResize$ = new ResizeObserver(() => { + const showHideBadgeContainer = this.elementRef.nativeElement.offsetWidth > 250; + if (showHideBadgeContainer !== this.showBadgeContainer) { + this.showBadgeContainer = showHideBadgeContainer; + this.cd.markForCheck(); + } + }); + + this.widgetResize$.observe(this.elementRef.nativeElement); + this.backgroundStyle$ = backgroundStyle(this.ctx.settings.background, this.imagePipe, this.sanitizer); + this.overlayStyle = overlayStyle(this.ctx.settings.background.overlay); + this.cd.markForCheck(); + })); + } else { + this.previewMode = true; } this.initMobileAppQRCode(); - this.widgetResize$ = new ResizeObserver(() => { - const showHideBadgeContainer = this.elementRef.nativeElement.offsetWidth > 250; - if (showHideBadgeContainer !== this.showBadgeContainer) { - this.showBadgeContainer = showHideBadgeContainer; - this.cd.markForCheck(); - } - }); - this.widgetResize$.observe(this.elementRef.nativeElement); } ngOnDestroy() { @@ -126,7 +143,10 @@ export class MobileAppQrcodeWidgetComponent extends PageComponent implements OnI private updateQRCode(link: string) { import('qrcode').then((QRCode) => { - QRCode.toCanvas(this.canvasRef.nativeElement, link, { width: 100 }); + QRCode.toString(link, (err, string) => { + this.qrCodeSVG = string; + this.cd.markForCheck(); + }) }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.html index f164351829..ea849e4f30 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.html @@ -23,57 +23,50 @@
-
-
admin.mobile-app.applications
-
-
- - {{ 'admin.mobile-app.android' | translate }} - +
+
+
widget-config.card-style
+
{{ 'widgets.mobile-app-qr-code.configuration-hint' | translate }}
+
+
+ + {{ 'admin.mobile-app.badges' | translate }} + + + + + {{ badgePosition.value | translate }} + + + +
-
-
-
- - {{ 'admin.mobile-app.ios' | translate }} - -
-
-
-
-
admin.mobile-app.appearance
-
-
- - {{ 'admin.mobile-app.badges' | translate }} - - - - - {{ badgePosition.value | translate }} - - - +
+
+ + {{ 'admin.mobile-app.label' | translate }} + + + + + warning + + +
-
-
- - {{ 'admin.mobile-app.label' | translate }} - - - - - warning - - +
+
+
{{ 'widgets.background.background' | translate }}
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.ts index 85ba53ca34..d4bae4624e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/mobile-app-qr-code-widget-settings.component.ts @@ -49,50 +49,35 @@ export class MobileAppQrCodeWidgetSettingsComponent extends WidgetSettingsCompon protected onSettingsSet(settings: WidgetSettings) { this.mobileAppQRCodeWidgetSettingsForm = this.fb.group({ useSystemSettings: [settings.useSystemSettings], - androidConfig: this.fb.group({ - enabled: [settings.androidConfig.enabled], - }), - iosConfig: this.fb.group({ - enabled: [settings.iosConfig.enabled], - }), qrCodeConfig: this.fb.group({ badgeEnabled: [settings.qrCodeConfig.badgeEnabled], - badgePosition: [{value: settings.qrCodeConfig.badgePosition, disabled: true}], + badgePosition: [settings.qrCodeConfig.badgePosition], qrCodeLabelEnabled: [settings.qrCodeConfig.qrCodeLabelEnabled], - qrCodeLabel: [settings.qrCodeConfig.qrCodeLabel, [Validators.required]] - }) + qrCodeLabel: [settings.qrCodeConfig.qrCodeLabel] + }), + background: [settings.background] }); } protected validatorTriggers(): string[] { - return ['useSystemSettings', 'androidConfig.enabled', 'iosConfig.enabled', 'qrCodeConfig.badgeEnabled', 'qrCodeConfig.qrCodeLabelEnabled']; + return ['useSystemSettings', 'qrCodeConfig.badgeEnabled', 'qrCodeConfig.qrCodeLabelEnabled']; } protected updateValidators(emitEvent: boolean) { const useSystemSettings = this.mobileAppQRCodeWidgetSettingsForm.get('useSystemSettings').value; - const androidEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('androidConfig.enabled').value; - const iosEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('iosConfig.enabled').value; - const badgeEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').value; - const qrCodeLabelEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabelEnabled').value; - - if (!androidEnabled && !iosEnabled) { - this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').disable({emitEvent: false}); - this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').disable({emitEvent: false}); - } - - if (androidEnabled || iosEnabled) { - this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').enable({emitEvent: false}); + if (!useSystemSettings) { + const badgeEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgeEnabled').value; + const qrCodeLabelEnabled = this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabelEnabled').value; if (badgeEnabled) { this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').enable({emitEvent: false}); } else { this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.badgePosition').disable({emitEvent: false}); } - } - - if (qrCodeLabelEnabled && !useSystemSettings) { - this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabel').enable({emitEvent: false}); - } else { - this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabel').disable({emitEvent: false}); + if (qrCodeLabelEnabled) { + this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabel').enable({emitEvent: false}); + } else { + this.mobileAppQRCodeWidgetSettingsForm.get('qrCodeConfig.qrCodeLabel').disable({emitEvent: false}); + } } } diff --git a/ui-ngx/src/assets/dashboard/sys_admin_home_page.json b/ui-ngx/src/assets/dashboard/sys_admin_home_page.json index b79190fddd..25806b0e39 100644 --- a/ui-ngx/src/assets/dashboard/sys_admin_home_page.json +++ b/ui-ngx/src/assets/dashboard/sys_admin_home_page.json @@ -2642,16 +2642,34 @@ "showTitle": true, "backgroundColor": "rgb(255, 255, 255)", "color": "rgba(0, 0, 0, 0.87)", - "padding": "8px", - "settings": {}, + "padding": "16px", + "settings": { + "useSystemSettings": true, + "qrCodeConfig": { + "badgeEnabled": true, + "badgePosition": "RIGHT", + "qrCodeLabelEnabled": true, + "qrCodeLabel": "Scan to connect or download mobile app" + }, + "background": { + "type": "color", + "color": "#fff", + "overlay": { + "enabled": false, + "color": "rgba(255,255,255,0.72)", + "blur": 3 + } + } + }, "title": "{i18n:admin.mobile-app.connect-mobile-app}", "dropShadow": false, "enableFullscreen": false, "widgetStyle": {}, - "widgetCss": ".tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title {\n padding: 0;\n}\n\n.tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title > .title-row > .title {\n padding-bottom: 12px;\n font-weight: 600;\n font-size: 20px;\n line-height: 24px;\n letter-spacing: 0.1px;\n color: rgba(0, 0, 0, 0.76);\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n .tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title > .title-row > .title {\n padding-bottom: 0;\n font-weight: 500;\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.25px;\n }\n}\n", + "widgetCss": " .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding: 0;\n}\n\n .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding-bottom: 8px;\n font-weight: 600;\n font-size: 20px;\n line-height: 24px;\n letter-spacing: 0.1px;\n color: rgba(0, 0, 0, 0.76);\n}\n\n.tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel {\n padding: 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding-bottom: 0;\n font-weight: 500;\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.25px;\n }\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode-label {\n display: none;\n }\n}\n\n@media screen and (min-width: 960px) and (max-width: 1190px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel {\n gap: 0;\n }\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n min-width: 150px;\n }\n}\n\n@media screen and (max-width: 960px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n max-width: 180px;\n }\n \n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-badges {\n max-width: 240px;\n }\n}", "showTitleIcon": false, "titleTooltip": "", - "titleStyle": null + "titleStyle": null, + "borderRadius": "12px" }, "row": 0, "col": 0, diff --git a/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json index 25e4feca45..f91439c009 100644 --- a/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json +++ b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json @@ -1185,16 +1185,34 @@ "showTitle": true, "backgroundColor": "rgb(255, 255, 255)", "color": "rgba(0, 0, 0, 0.87)", - "padding": "8px", - "settings": {}, + "padding": "16px", + "settings": { + "useSystemSettings": true, + "qrCodeConfig": { + "badgeEnabled": true, + "badgePosition": "RIGHT", + "qrCodeLabelEnabled": true, + "qrCodeLabel": "Scan to connect or download mobile app" + }, + "background": { + "type": "color", + "color": "#fff", + "overlay": { + "enabled": false, + "color": "rgba(255,255,255,0.72)", + "blur": 3 + } + } + }, "title": "{i18n:admin.mobile-app.connect-mobile-app}", "dropShadow": false, "enableFullscreen": false, "widgetStyle": {}, - "widgetCss": ".tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title {\n padding: 0;\n}\n\n.tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title > .title-row > .title {\n padding-bottom: 12px;\n font-weight: 600;\n font-size: 20px;\n line-height: 24px;\n letter-spacing: 0.1px;\n color: rgba(0, 0, 0, 0.76);\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n .tb-widget-container > .tb-widget > .tb-widget-header > .tb-widget-title > .title-row > .title {\n padding-bottom: 0;\n font-weight: 500;\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.25px;\n }\n}\n", + "widgetCss": " .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding: 0;\n}\n\n .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding-bottom: 8px;\n font-weight: 600;\n font-size: 20px;\n line-height: 24px;\n letter-spacing: 0.1px;\n color: rgba(0, 0, 0, 0.76);\n}\n\n.tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel {\n padding: 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n .tb-widget-container > .tb-widget > .tb-widget-content .tb-widget-title > .title-row > .title {\n padding-bottom: 0;\n font-weight: 500;\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.25px;\n }\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode-label {\n display: none;\n }\n}\n\n@media screen and (min-width: 960px) and (max-width: 1190px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel {\n gap: 0;\n }\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n min-width: 150px;\n }\n}\n\n@media screen and (max-width: 960px) {\n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-qrcode {\n max-width: 180px;\n }\n \n .tb-widget-container > .tb-widget > .tb-widget-content > .tb-widget .tb-mobile-app-qrcode-panel .tb-badges {\n max-width: 240px;\n }\n}", "showTitleIcon": false, "titleTooltip": "", - "titleStyle": null + "titleStyle": null, + "borderRadius": "12px" }, "row": 0, "col": 0, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 4a6679dcca..1369a5420b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5557,6 +5557,9 @@ "invalid-widget-file-error": "Unable to import widget: Invalid widget data structure." }, "widgets": { + "mobile-app-qr-code": { + "configuration-hint": "The configuration depends on the Mobile app QR code widget in platform main settings" + }, "action-button": { "behavior": "Behavior", "on-click": "On click",