From 04fcbd36dccaf27bb0d2a33d8b83c554a7c1c287 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Tue, 14 Oct 2025 10:35:27 +0300 Subject: [PATCH 1/4] added save to image gallery --- .../lib/photo-camera-input.component.html | 2 +- .../lib/photo-camera-input.component.ts | 94 +++++++++++++------ ...amera-input-widget-settings.component.html | 84 +++++++++++------ ...-camera-input-widget-settings.component.ts | 24 ++++- .../assets/locale/locale.constant-en_US.json | 13 ++- 5 files changed, 152 insertions(+), 65 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.html index bc3ad72e58..fe53ef9f66 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.html @@ -20,7 +20,7 @@
widgets.input-widgets.no-image - last photo + last photo
+ + @if (photoCameraInputWidgetSettingsForm.get('imageFormat').value !== 'image/png') { +
+
widgets.input-widgets.image-quality
+ + + % + +
+ } + +
+
Size
+
+
widgets.input-widgets.max-image-width
+ + + px + + +
widgets.input-widgets.max-image-height
+ + + px + +
+
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.ts index 30c3e39833..7bc75573f1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.ts @@ -19,6 +19,7 @@ import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.m import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; +import { deepClone } from '@app/core/utils'; @Component({ selector: 'tb-photo-camera-input-widget-settings', @@ -42,6 +43,8 @@ export class PhotoCameraInputWidgetSettingsComponent extends WidgetSettingsCompo return { widgetTitle: '', + saveToGallery: false, + imageVisibility: true, imageFormat: 'image/png', imageQuality: 0.92, maxWidth: 640, @@ -57,11 +60,28 @@ export class PhotoCameraInputWidgetSettingsComponent extends WidgetSettingsCompo widgetTitle: [settings.widgetTitle, []], // Image settings - + saveToGallery: [settings.saveToGallery], + imageVisibility: [settings.imageVisibility], imageFormat: [settings.imageFormat, []], - imageQuality: [settings.imageQuality, [Validators.min(0), Validators.max(1)]], + imageQuality: [settings.imageQuality, [Validators.min(0), Validators.max(100)]], maxWidth: [settings.maxWidth, [Validators.min(1)]], maxHeight: [settings.maxHeight, [Validators.min(1)]] }); } + + protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { + return { + ...settings, + saveToGallery: settings.saveToGallery || false, + imageQuality: settings.imageQuality * 100 + } + } + + protected prepareOutputSettings(settings: WidgetSettings): WidgetSettings { + return { + ...settings, + saveToGallery: settings.saveToGallery || false, + imageQuality: settings.imageQuality / 100 + } + } } 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 4a347ab6cd..36f62219cd 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -8049,14 +8049,14 @@ "attribute-scope-server": "Server attribute", "attribute-scope-shared": "Shared attribute", "value-required": "Value required", - "image-settings": "Image settings", + "image-settings": "Image output settings", "image-format": "Image format", "image-format-jpeg": "JPEG", "image-format-png": "PNG", "image-format-webp": "WEBP", - "image-quality": "Image quality that use lossy compression such as jpeg and webp", - "max-image-width": "Maximum image width", - "max-image-height": "Maximum image height", + "image-quality": "Image quality", + "max-image-width": "Max width", + "max-image-height": "Max height", "action-buttons": "Action buttons", "show-action-buttons": "Show action buttons", "update-all-values": "Update all values, not only modified", @@ -8137,7 +8137,10 @@ "add-radio-option": "Add radio option", "radio-label-position": "Label position", "radio-label-position-before": "Before", - "radio-label-position-after": "After" + "radio-label-position-after": "After", + "save-image": "Save image", + "save-to-gallery": "Automatically store captured images in Image Gallery", + "public-image": "Makes image avaliable for any unauthorized user" }, "invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type", "qr-code": { From 9c6170d8c0c75e68f10c68b7fe479eed4a3244b4 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Thu, 23 Oct 2025 14:24:43 +0300 Subject: [PATCH 2/4] refactore --- .../lib/photo-camera-input.component.ts | 25 +++++++++---------- ...-camera-input-widget-settings.component.ts | 13 +++++----- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.ts index d977dc80e2..38d14a937b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/photo-camera-input.component.ts @@ -24,25 +24,25 @@ import { ViewChild, ViewEncapsulation } from '@angular/core'; -import { PageComponent } from '@shared/components/page.component'; -import { WidgetContext } from '@home/models/widget-component.models'; -import { Store } from '@ngrx/store'; +import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; +import { ImageService } from '@app/core/public-api'; import { AppState } from '@core/core.state'; +import { AttributeService } from '@core/http/attribute.service'; import { UtilsService } from '@core/services/utils.service'; -import { Datasource, DatasourceData, DatasourceType } from '@shared/models/widget.models'; import { WINDOW } from '@core/services/window.service'; -import { AttributeService } from '@core/http/attribute.service'; +import { isString } from '@core/utils'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { Store } from '@ngrx/store'; +import { PageComponent } from '@shared/components/page.component'; import { EntityId } from '@shared/models/id/entity-id'; import { AttributeScope, DataKeyType } from '@shared/models/telemetry/telemetry.models'; -import { map, Observable, of, switchMap, tap } from 'rxjs'; -import { isFile, isString } from '@core/utils'; -import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; -import { ImageService } from '@app/core/public-api'; +import { Datasource, DatasourceData, DatasourceType } from '@shared/models/widget.models'; +import { map, Observable, of, switchMap } from 'rxjs'; interface PhotoCameraInputWidgetSettings { widgetTitle: string; saveToGallery: boolean; - imageVisibility: boolean; + usePublicGalleryLink: boolean; imageQuality: number; imageFormat: string; maxWidth: number; @@ -284,8 +284,7 @@ export class PhotoCameraInputWidgetComponent extends PageComponent implements On this.canvasElement.height = this.videoHeight; this.canvasElement.getContext('2d').drawImage(this.videoElement, 0, 0, this.videoWidth, this.videoHeight); - const previewDataUrl = this.canvasElement.toDataURL(this.mimeType, this.quality); - this.previewPhoto = previewDataUrl; + this.previewPhoto = this.canvasElement.toDataURL(this.mimeType, this.quality); this.isPreviewPhoto = true; } @@ -310,7 +309,7 @@ export class PhotoCameraInputWidgetComponent extends PageComponent implements On return this.imageService.uploadImage(file, fileName); }), map((imageInfo) => - this.settings.imageVisibility ? imageInfo.publicLink : imageInfo.link + this.settings.usePublicGalleryLink ? imageInfo.publicLink : imageInfo.link ) ); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.ts index 7bc75573f1..4e7d552f44 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.ts @@ -15,11 +15,10 @@ /// import { Component } from '@angular/core'; -import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; -import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { deepClone } from '@app/core/utils'; +import { Store } from '@ngrx/store'; +import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; @Component({ selector: 'tb-photo-camera-input-widget-settings', @@ -44,7 +43,7 @@ export class PhotoCameraInputWidgetSettingsComponent extends WidgetSettingsCompo widgetTitle: '', saveToGallery: false, - imageVisibility: true, + usePublicGalleryLink: true, imageFormat: 'image/png', imageQuality: 0.92, maxWidth: 640, @@ -61,7 +60,7 @@ export class PhotoCameraInputWidgetSettingsComponent extends WidgetSettingsCompo // Image settings saveToGallery: [settings.saveToGallery], - imageVisibility: [settings.imageVisibility], + usePublicGalleryLink: [settings.usePublicGalleryLink], imageFormat: [settings.imageFormat, []], imageQuality: [settings.imageQuality, [Validators.min(0), Validators.max(100)]], maxWidth: [settings.maxWidth, [Validators.min(1)]], @@ -72,7 +71,8 @@ export class PhotoCameraInputWidgetSettingsComponent extends WidgetSettingsCompo protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { return { ...settings, - saveToGallery: settings.saveToGallery || false, + saveToGallery: settings.saveToGallery ?? false, + usePublicGalleryLink: settings.usePublicGalleryLink ?? false, imageQuality: settings.imageQuality * 100 } } @@ -80,7 +80,6 @@ export class PhotoCameraInputWidgetSettingsComponent extends WidgetSettingsCompo protected prepareOutputSettings(settings: WidgetSettings): WidgetSettings { return { ...settings, - saveToGallery: settings.saveToGallery || false, imageQuality: settings.imageQuality / 100 } } From e09f7df512eacd63758892d4c8406ffda0df484c Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Fri, 24 Oct 2025 11:34:46 +0300 Subject: [PATCH 3/4] minor fix --- .../input/photo-camera-input-widget-settings.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.html index 8d0d60364e..cabd91d4e7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/photo-camera-input-widget-settings.component.html @@ -31,7 +31,7 @@ {{ 'widgets.input-widgets.save-to-gallery' | translate }} @if (photoCameraInputWidgetSettingsForm.get('saveToGallery').value) { - + {{ 'widgets.input-widgets.public-image' | translate }} } From 52597229cf4e29befd12128b56f1ee34d56e0eb9 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Fri, 31 Oct 2025 13:28:44 +0200 Subject: [PATCH 4/4] updated widget json --- .../main/data/json/system/widget_types/photo_camera_input.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_types/photo_camera_input.json b/application/src/main/data/json/system/widget_types/photo_camera_input.json index 69327395cc..fc676380ab 100644 --- a/application/src/main/data/json/system/widget_types/photo_camera_input.json +++ b/application/src/main/data/json/system/widget_types/photo_camera_input.json @@ -15,7 +15,7 @@ "settingsSchema": "", "dataKeySettingsSchema": "{}\n", "settingsDirective": "tb-photo-camera-input-widget-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Photo camera input\",\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetTitle\":\"\",\"saveToGallery\":true,\"usePublicGalleryLink\":false,\"imageFormat\":\"image/png\",\"imageQuality\":0.92,\"maxWidth\":640,\"maxHeight\":480},\"title\":\"Photo camera input\",\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false,\"actions\":{}}" }, "resources": [ {