@servicemind.tis/angular-image-and-file-picker 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +305 -0
- package/fesm2022/servicemind.tis-angular-image-and-file-picker.mjs +3658 -0
- package/fesm2022/servicemind.tis-angular-image-and-file-picker.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/angular-camera-capture-dialog/angular-camera-capture-dialog.component.d.ts +34 -0
- package/lib/angular-confirmation-dialog/angular-confirmation-dialog.component.d.ts +10 -0
- package/lib/angular-error-dialog/angular-error-dialog.component.d.ts +10 -0
- package/lib/angular-file-viewer/angular-excel-file-viewer/angular-excel-file-viewer.component.d.ts +14 -0
- package/lib/angular-file-viewer/angular-file-viewer.component.d.ts +16 -0
- package/lib/angular-file-viewer/angular-pdf-viewer/angular-pdf-viewer.component.d.ts +16 -0
- package/lib/angular-file-viewer/angular-video/angular-video.component.d.ts +13 -0
- package/lib/angular-image-and-file-picker/angular-image-and-file-picker.component.d.ts +186 -0
- package/lib/angular-image-and-file-picker.module.d.ts +31 -0
- package/lib/angular-image-and-file-picker.service.d.ts +6 -0
- package/lib/angular-preview-image/angular-preview-image.component.d.ts +19 -0
- package/lib/angular-qr-code-dialog/angular-qr-code-dialog.component.d.ts +90 -0
- package/lib/angular-view-connection-dialog/angular-view-connection-dialog.component.d.ts +44 -0
- package/lib/interfaces/config.type.d.ts +19 -0
- package/lib/interfaces/file-viewer-file-type.type.d.ts +41 -0
- package/lib/interfaces/index.d.ts +3 -0
- package/lib/interfaces/socket-adapter.interface.d.ts +315 -0
- package/lib/pipes/time-ago.pipe.d.ts +7 -0
- package/lib/services/angular-helper.service.d.ts +45 -0
- package/lib/services/angular-remote-upload.service.d.ts +273 -0
- package/package.json +53 -0
- package/public-api.d.ts +7 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
/**
|
|
3
|
+
* Interface that the host application must implement to enable
|
|
4
|
+
* remote upload functionality via WebSocket.
|
|
5
|
+
*
|
|
6
|
+
* This allows the library to leverage an existing WebSocket connection
|
|
7
|
+
* from the host application instead of creating its own.
|
|
8
|
+
*/
|
|
9
|
+
export interface AngularSocketAdapter {
|
|
10
|
+
/**
|
|
11
|
+
* Subscribe to a channel and return an Observable of messages
|
|
12
|
+
* @param channelName - The channel name to subscribe to
|
|
13
|
+
* @returns Observable that emits messages received on the channel
|
|
14
|
+
*/
|
|
15
|
+
subscribeToChannel(channelName: string): Observable<any>;
|
|
16
|
+
/**
|
|
17
|
+
* Subscribe to channels matching a prefix (optional)
|
|
18
|
+
* @param prefix - The prefix to match channel names
|
|
19
|
+
* @returns Observable that emits messages from matching channels
|
|
20
|
+
*/
|
|
21
|
+
subscribeToChannelPrefix?(prefix: string): Observable<any>;
|
|
22
|
+
/**
|
|
23
|
+
* Unsubscribe from a channel
|
|
24
|
+
* @param channelName - The channel name to unsubscribe from
|
|
25
|
+
*/
|
|
26
|
+
unsubscribeFromChannel?(channelName: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get unique device/browser ID for pairing
|
|
29
|
+
* @returns Device ID string or Promise that resolves to device ID
|
|
30
|
+
*/
|
|
31
|
+
getDeviceId(): string | Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Check if socket is currently connected
|
|
34
|
+
* @returns true if connected, false otherwise
|
|
35
|
+
*/
|
|
36
|
+
isConnected(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Observable that emits connection status changes
|
|
39
|
+
*/
|
|
40
|
+
connectionStatus$: Observable<boolean>;
|
|
41
|
+
/**
|
|
42
|
+
* Get current auth token (for passing to mobile app)
|
|
43
|
+
* @returns Current access token or null
|
|
44
|
+
*/
|
|
45
|
+
getAuthToken?(): string | null | Promise<string | null>;
|
|
46
|
+
/**
|
|
47
|
+
* Get current refresh token (for passing to mobile app)
|
|
48
|
+
* @returns Current refresh token or null
|
|
49
|
+
*/
|
|
50
|
+
getRefreshToken?(): string | null | Promise<string | null>;
|
|
51
|
+
/**
|
|
52
|
+
* Get the WebSocket URL (for passing to mobile app)
|
|
53
|
+
* @returns WebSocket URL string
|
|
54
|
+
*/
|
|
55
|
+
getSocketUrl?(): string;
|
|
56
|
+
/**
|
|
57
|
+
* Get the API base URL (for passing to mobile app)
|
|
58
|
+
* @returns API base URL string
|
|
59
|
+
*/
|
|
60
|
+
getApiUrl?(): string;
|
|
61
|
+
/**
|
|
62
|
+
* Get the current user ID
|
|
63
|
+
* @returns User ID string
|
|
64
|
+
*/
|
|
65
|
+
getUserId?(): string | Promise<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Send a message directly via socket (for handshake and communication)
|
|
68
|
+
* @param message - The message to send { action: string; data: any }
|
|
69
|
+
*/
|
|
70
|
+
sendViaSocket?(message: {
|
|
71
|
+
action: string;
|
|
72
|
+
data: any;
|
|
73
|
+
}): void;
|
|
74
|
+
/**
|
|
75
|
+
* Call API via socket and get response as Observable
|
|
76
|
+
* @param route - The API route to call
|
|
77
|
+
* @param body - The request body
|
|
78
|
+
* @returns Observable that emits the API response
|
|
79
|
+
*/
|
|
80
|
+
callApiViaSocket?(route: string, body: any): Observable<any>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Configuration for remote upload feature
|
|
84
|
+
*/
|
|
85
|
+
export interface AngularRemoteUploadConfig {
|
|
86
|
+
/**
|
|
87
|
+
* Enable/disable remote upload feature
|
|
88
|
+
*/
|
|
89
|
+
enabled: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Socket adapter implementation from host app
|
|
92
|
+
*/
|
|
93
|
+
socketAdapter?: AngularSocketAdapter;
|
|
94
|
+
/**
|
|
95
|
+
* API endpoints for remote upload operations
|
|
96
|
+
*/
|
|
97
|
+
apiEndpoints?: AngularRemoteUploadApiEndpoints;
|
|
98
|
+
/**
|
|
99
|
+
* QR code configuration
|
|
100
|
+
*/
|
|
101
|
+
qrCode?: AngularQrCodeConfig;
|
|
102
|
+
/**
|
|
103
|
+
* Pairing configuration
|
|
104
|
+
*/
|
|
105
|
+
pairing?: AngularPairingConfig;
|
|
106
|
+
/**
|
|
107
|
+
* Auto-accept files from mobile without manual confirmation
|
|
108
|
+
* When true: Files are automatically shown in the component UI and attached to the form.
|
|
109
|
+
* The onFileAccept callback is also called for additional processing.
|
|
110
|
+
* When false: Files are NOT shown in the component UI or attached to the form.
|
|
111
|
+
* Only the onFileAccept callback is called, allowing the host app to
|
|
112
|
+
* handle the file display and processing in a custom way.
|
|
113
|
+
* Default: false
|
|
114
|
+
*/
|
|
115
|
+
autoAcceptFiles?: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Callback when a file is uploaded from mobile device
|
|
118
|
+
* - If autoAcceptFiles=true: Called after file is added to component UI and form
|
|
119
|
+
* - If autoAcceptFiles=false: Called immediately (only way to access the file)
|
|
120
|
+
* This allows the host app to handle the file (e.g., patch a form control, custom display)
|
|
121
|
+
* @param file - The uploaded file data
|
|
122
|
+
*/
|
|
123
|
+
onFileAccept?: (file: AngularRemoteUploadedFile) => void;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* API endpoints configuration for remote upload
|
|
127
|
+
*/
|
|
128
|
+
export interface AngularRemoteUploadApiEndpoints {
|
|
129
|
+
/**
|
|
130
|
+
* Endpoint to generate a mobile upload link token (UUID)
|
|
131
|
+
* POST request with deviceId, userId, returns { token, expiresAt }
|
|
132
|
+
* Default: {apiUrl}/ease-of-access/mobile-upload-link-token
|
|
133
|
+
*/
|
|
134
|
+
generateMobileLinkToken?: string;
|
|
135
|
+
/**
|
|
136
|
+
* Endpoint to generate a pairing code (legacy)
|
|
137
|
+
* POST request with deviceId, returns { pairingCode, channel, expiresAt }
|
|
138
|
+
*/
|
|
139
|
+
generatePairingCode?: string;
|
|
140
|
+
/**
|
|
141
|
+
* Endpoint to validate a pairing code (used by mobile)
|
|
142
|
+
* POST request with pairingCode, returns { valid, deviceId, channel }
|
|
143
|
+
*/
|
|
144
|
+
validatePairingCode?: string;
|
|
145
|
+
/**
|
|
146
|
+
* Endpoint called by mobile after uploading to notify desktop
|
|
147
|
+
* POST request with { channel, uploadedFile }
|
|
148
|
+
*/
|
|
149
|
+
notifyUpload?: string;
|
|
150
|
+
/**
|
|
151
|
+
* Channel prefix for receiving upload notifications
|
|
152
|
+
* Desktop subscribes to: {prefix}{deviceId}
|
|
153
|
+
*/
|
|
154
|
+
uploadChannelPrefix: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* QR code display configuration
|
|
158
|
+
*/
|
|
159
|
+
export interface AngularQrCodeConfig {
|
|
160
|
+
/**
|
|
161
|
+
* Base URL for the mobile upload page
|
|
162
|
+
* The full URL will be: {mobileUploadUrl}?code={pairingCode}&deviceId={deviceId}
|
|
163
|
+
*/
|
|
164
|
+
mobileUploadUrl: string;
|
|
165
|
+
/**
|
|
166
|
+
* QR code expiry time in seconds (default: 300 = 5 minutes)
|
|
167
|
+
*/
|
|
168
|
+
expirySeconds?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Size of the QR code in pixels (default: 200)
|
|
171
|
+
*/
|
|
172
|
+
size?: number;
|
|
173
|
+
/**
|
|
174
|
+
* Logo URL to display in the center of QR code (optional)
|
|
175
|
+
*/
|
|
176
|
+
logoUrl?: string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Pairing persistence configuration
|
|
180
|
+
*/
|
|
181
|
+
export interface AngularPairingConfig {
|
|
182
|
+
/**
|
|
183
|
+
* Whether to persist pairing in localStorage (default: true)
|
|
184
|
+
*/
|
|
185
|
+
persistInStorage?: boolean;
|
|
186
|
+
/**
|
|
187
|
+
* Storage key for pairing data (default: 'angular-remote-upload-pairing')
|
|
188
|
+
*/
|
|
189
|
+
storageKey?: string;
|
|
190
|
+
/**
|
|
191
|
+
* How long pairing remains valid in milliseconds (default: 24 hours)
|
|
192
|
+
* Set to 0 for session-only pairing
|
|
193
|
+
*/
|
|
194
|
+
pairingTTL?: number;
|
|
195
|
+
/**
|
|
196
|
+
* Whether to auto-reconnect on page reload if pairing exists
|
|
197
|
+
*/
|
|
198
|
+
autoReconnect?: boolean;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Pairing session data stored in localStorage
|
|
202
|
+
*/
|
|
203
|
+
export interface AngularPairingSession {
|
|
204
|
+
/**
|
|
205
|
+
* Unique pairing code
|
|
206
|
+
*/
|
|
207
|
+
pairingCode: string;
|
|
208
|
+
/**
|
|
209
|
+
* Desktop device ID
|
|
210
|
+
*/
|
|
211
|
+
desktopDeviceId: string;
|
|
212
|
+
/**
|
|
213
|
+
* Mobile device ID (set after mobile connects)
|
|
214
|
+
*/
|
|
215
|
+
mobileDeviceId?: string;
|
|
216
|
+
/**
|
|
217
|
+
* WebSocket channel for communication
|
|
218
|
+
*/
|
|
219
|
+
channel: string;
|
|
220
|
+
/**
|
|
221
|
+
* When the pairing was created
|
|
222
|
+
*/
|
|
223
|
+
createdAt: number;
|
|
224
|
+
/**
|
|
225
|
+
* When the pairing expires
|
|
226
|
+
*/
|
|
227
|
+
expiresAt: number;
|
|
228
|
+
/**
|
|
229
|
+
* Current pairing status
|
|
230
|
+
*/
|
|
231
|
+
status: 'pending' | 'connected' | 'disconnected' | 'expired';
|
|
232
|
+
/**
|
|
233
|
+
* Last activity timestamp
|
|
234
|
+
*/
|
|
235
|
+
lastActivity?: number;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Event emitted when a remote upload is received
|
|
239
|
+
*/
|
|
240
|
+
export interface AngularRemoteUploadEvent {
|
|
241
|
+
/**
|
|
242
|
+
* The uploaded file data
|
|
243
|
+
*/
|
|
244
|
+
file: AngularRemoteUploadedFile;
|
|
245
|
+
/**
|
|
246
|
+
* Mobile device ID that uploaded the file
|
|
247
|
+
*/
|
|
248
|
+
mobileDeviceId: string;
|
|
249
|
+
/**
|
|
250
|
+
* Timestamp of the upload
|
|
251
|
+
*/
|
|
252
|
+
timestamp: number;
|
|
253
|
+
/**
|
|
254
|
+
* Session ID for grouping multiple uploads
|
|
255
|
+
*/
|
|
256
|
+
sessionId?: string;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* File data received from remote upload
|
|
260
|
+
*/
|
|
261
|
+
export interface AngularRemoteUploadedFile {
|
|
262
|
+
/**
|
|
263
|
+
* S3 or cloud storage URL of the uploaded file
|
|
264
|
+
*/
|
|
265
|
+
s3Url: string;
|
|
266
|
+
/**
|
|
267
|
+
* Original filename
|
|
268
|
+
*/
|
|
269
|
+
fileName: string;
|
|
270
|
+
/**
|
|
271
|
+
* File MIME type
|
|
272
|
+
*/
|
|
273
|
+
mimeType: string;
|
|
274
|
+
/**
|
|
275
|
+
* File size in bytes
|
|
276
|
+
*/
|
|
277
|
+
size: number;
|
|
278
|
+
/**
|
|
279
|
+
* Thumbnail URL (for images)
|
|
280
|
+
*/
|
|
281
|
+
thumbnailUrl?: string;
|
|
282
|
+
/**
|
|
283
|
+
* Additional metadata from the upload
|
|
284
|
+
*/
|
|
285
|
+
metadata?: Record<string, any>;
|
|
286
|
+
/**
|
|
287
|
+
* Upload data from presigned URL response
|
|
288
|
+
*/
|
|
289
|
+
uploadData?: any;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Message format for WebSocket communication
|
|
293
|
+
*/
|
|
294
|
+
export interface AngularRemoteUploadMessage {
|
|
295
|
+
/**
|
|
296
|
+
* Message type
|
|
297
|
+
*/
|
|
298
|
+
type: 'pairing_request' | 'pairing_accepted' | 'upload_started' | 'upload_progress' | 'upload_complete' | 'upload_error' | 'disconnect';
|
|
299
|
+
/**
|
|
300
|
+
* Channel name
|
|
301
|
+
*/
|
|
302
|
+
channel: string;
|
|
303
|
+
/**
|
|
304
|
+
* Message payload
|
|
305
|
+
*/
|
|
306
|
+
payload: any;
|
|
307
|
+
/**
|
|
308
|
+
* Sender device ID
|
|
309
|
+
*/
|
|
310
|
+
senderId: string;
|
|
311
|
+
/**
|
|
312
|
+
* Timestamp
|
|
313
|
+
*/
|
|
314
|
+
timestamp: number;
|
|
315
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PipeTransform } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class TimeAgoPipe implements PipeTransform {
|
|
4
|
+
transform(timestamp: number | undefined, format?: 'short' | 'long'): string;
|
|
5
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TimeAgoPipe, never>;
|
|
6
|
+
static ɵpipe: i0.ɵɵPipeDeclaration<TimeAgoPipe, "timeAgo", false>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
|
2
|
+
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
|
3
|
+
import { MatSnackBar, MatSnackBarRef, TextOnlySnackBar } from '@angular/material/snack-bar';
|
|
4
|
+
import { AngularErrorDialogComponent } from '../angular-error-dialog/angular-error-dialog.component';
|
|
5
|
+
import { Observable } from 'rxjs';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
export declare class AngularHelperService {
|
|
8
|
+
private snackBar;
|
|
9
|
+
private dialog;
|
|
10
|
+
private http;
|
|
11
|
+
constructor(snackBar: MatSnackBar, dialog: MatDialog, http: HttpClient);
|
|
12
|
+
showHttpErrorMsg(error: HttpErrorResponse, duration?: number): MatDialogRef<AngularErrorDialogComponent, any> | MatSnackBarRef<TextOnlySnackBar>;
|
|
13
|
+
showSuccessMsg(message: string, title: string, duration?: number): void;
|
|
14
|
+
showErrorMsg(message: string, title: string, duration?: number): void;
|
|
15
|
+
/**
|
|
16
|
+
* Compresses an image file to ensure it's under MAX_COMPRESSED_FILE_SIZE_MB.
|
|
17
|
+
* Uses iterative compression with decreasing quality levels while maintaining aspect ratio.
|
|
18
|
+
* @param image - Data URL string or File object
|
|
19
|
+
* @param mimeType - The MIME type of the image (e.g., 'image/jpeg', 'image/png')
|
|
20
|
+
* @returns Promise<Blob> - The compressed image as a Blob
|
|
21
|
+
*/
|
|
22
|
+
compressFile(image: any, mimeType: string): Promise<Blob>;
|
|
23
|
+
/**
|
|
24
|
+
* Formats file size in human-readable format
|
|
25
|
+
*/
|
|
26
|
+
private formatFileSize;
|
|
27
|
+
/**
|
|
28
|
+
* Checks if the given MIME type is a compressible image format
|
|
29
|
+
*/
|
|
30
|
+
private isCompressibleImage;
|
|
31
|
+
/**
|
|
32
|
+
* Gets file extension from MIME type
|
|
33
|
+
*/
|
|
34
|
+
private getExtensionFromMimeType;
|
|
35
|
+
dataURItoBlob(dataURI: string, mimeType: string): Blob;
|
|
36
|
+
getDataUrlFromFile(file: any): Promise<unknown>;
|
|
37
|
+
getUploadUrl(url: string, filename: string, mimeType: string, type: string): Observable<any>;
|
|
38
|
+
attachFilesToEntity(url: string, data: any, limit: number): Observable<any>;
|
|
39
|
+
updateTag(url: string, data: any): Observable<any>;
|
|
40
|
+
updateSequence(url: string, data: any): Observable<any>;
|
|
41
|
+
putFile(url: string, file: File | Blob | ArrayBuffer, contentType?: string): Observable<any>;
|
|
42
|
+
deleteUploadedFile(url: string, data: any): Observable<any>;
|
|
43
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AngularHelperService, never>;
|
|
44
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<AngularHelperService>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { OnDestroy } from '@angular/core';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { HttpClient } from '@angular/common/http';
|
|
4
|
+
import { AngularRemoteUploadConfig, AngularPairingSession, AngularRemoteUploadEvent } from '../interfaces/socket-adapter.interface';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
/**
|
|
7
|
+
* Mobile connection info stored in localStorage
|
|
8
|
+
*/
|
|
9
|
+
interface MobileConnectionInfo {
|
|
10
|
+
mobileDeviceId: string;
|
|
11
|
+
connectedAt: number;
|
|
12
|
+
lastActivity: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Field request info for tracking current upload request
|
|
16
|
+
*/
|
|
17
|
+
export interface FieldRequestInfo {
|
|
18
|
+
label: string;
|
|
19
|
+
accept: string;
|
|
20
|
+
type: 'image' | 'file';
|
|
21
|
+
entityType?: string;
|
|
22
|
+
entityId?: any;
|
|
23
|
+
isMultiple?: boolean;
|
|
24
|
+
limit?: number;
|
|
25
|
+
remainingSlots?: number;
|
|
26
|
+
isCompressed?: boolean;
|
|
27
|
+
requestId?: string;
|
|
28
|
+
requestedAt: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Device online status from health check API
|
|
32
|
+
*/
|
|
33
|
+
export interface DeviceOnlineStatus {
|
|
34
|
+
isOnline: boolean;
|
|
35
|
+
deviceId: string;
|
|
36
|
+
lastPing?: number;
|
|
37
|
+
connectionId?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Combined device status for both desktop and mobile
|
|
41
|
+
*/
|
|
42
|
+
export interface DevicesOnlineStatus {
|
|
43
|
+
desktop: DeviceOnlineStatus;
|
|
44
|
+
mobile: DeviceOnlineStatus;
|
|
45
|
+
lastChecked: number;
|
|
46
|
+
isReadyForTransfer: boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare class AngularRemoteUploadService implements OnDestroy {
|
|
49
|
+
private http;
|
|
50
|
+
private static readonly COMPONENT;
|
|
51
|
+
private static readonly MOBILE_CONNECTION_KEY;
|
|
52
|
+
private static readonly LEGACY_MOBILE_CONNECTION_KEY;
|
|
53
|
+
private destroy$;
|
|
54
|
+
private channelSubscription;
|
|
55
|
+
private healthCheckSubscription;
|
|
56
|
+
private config;
|
|
57
|
+
private socketAdapter;
|
|
58
|
+
private deviceId;
|
|
59
|
+
private userId;
|
|
60
|
+
private apiUrl;
|
|
61
|
+
private channelName;
|
|
62
|
+
private pairingSession$;
|
|
63
|
+
private connectionStatus$;
|
|
64
|
+
private mobileConnection$;
|
|
65
|
+
private remoteUpload$;
|
|
66
|
+
private error$;
|
|
67
|
+
private pendingFiles$;
|
|
68
|
+
private isWaitingForUpload$;
|
|
69
|
+
private currentFieldRequest$;
|
|
70
|
+
private devicesStatus$;
|
|
71
|
+
private isCheckingStatus$;
|
|
72
|
+
constructor(http: HttpClient);
|
|
73
|
+
/**
|
|
74
|
+
* Configure the remote upload service
|
|
75
|
+
*/
|
|
76
|
+
configure(config: AngularRemoteUploadConfig): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Get desktop device ID
|
|
79
|
+
*/
|
|
80
|
+
getDesktopDeviceId(): string;
|
|
81
|
+
/**
|
|
82
|
+
* Get current mobile connection info
|
|
83
|
+
*/
|
|
84
|
+
getMobileConnection(): Observable<MobileConnectionInfo | null>;
|
|
85
|
+
/**
|
|
86
|
+
* Get current mobile device ID (if connected)
|
|
87
|
+
*/
|
|
88
|
+
getMobileDeviceId(): string | null;
|
|
89
|
+
/**
|
|
90
|
+
* Get current pairing session
|
|
91
|
+
*/
|
|
92
|
+
getPairingSession(): Observable<AngularPairingSession | null>;
|
|
93
|
+
/**
|
|
94
|
+
* Get connection status
|
|
95
|
+
*/
|
|
96
|
+
getConnectionStatus(): Observable<'disconnected' | 'pending' | 'connected'>;
|
|
97
|
+
/**
|
|
98
|
+
* Get remote upload events
|
|
99
|
+
*/
|
|
100
|
+
getRemoteUploads(): Observable<AngularRemoteUploadEvent>;
|
|
101
|
+
/**
|
|
102
|
+
* Get error events
|
|
103
|
+
*/
|
|
104
|
+
getErrors(): Observable<string>;
|
|
105
|
+
/**
|
|
106
|
+
* Check if remote upload is available (configured and socket connected)
|
|
107
|
+
*/
|
|
108
|
+
isAvailable(): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Check if currently connected to a mobile device
|
|
111
|
+
*/
|
|
112
|
+
isConnectedToMobile(): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Alias for isConnectedToMobile - Check if paired with mobile
|
|
115
|
+
*/
|
|
116
|
+
isPaired(): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Get devices online status (both desktop and mobile)
|
|
119
|
+
*/
|
|
120
|
+
getDevicesStatus(): Observable<DevicesOnlineStatus | null>;
|
|
121
|
+
/**
|
|
122
|
+
* Get current devices status value
|
|
123
|
+
*/
|
|
124
|
+
getDevicesStatusValue(): DevicesOnlineStatus | null;
|
|
125
|
+
/**
|
|
126
|
+
* Check if currently verifying connection status (for blinking indicator)
|
|
127
|
+
*/
|
|
128
|
+
getIsCheckingStatus(): Observable<boolean>;
|
|
129
|
+
/**
|
|
130
|
+
* Check if both devices are online and ready for transfer
|
|
131
|
+
*/
|
|
132
|
+
isReadyForTransfer(): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Get pending files from mobile (waiting to be accepted/rejected)
|
|
135
|
+
*/
|
|
136
|
+
getPendingFiles(): Observable<AngularRemoteUploadEvent[]>;
|
|
137
|
+
/**
|
|
138
|
+
* Get current pending files value
|
|
139
|
+
*/
|
|
140
|
+
getPendingFilesValue(): AngularRemoteUploadEvent[];
|
|
141
|
+
/**
|
|
142
|
+
* Check if waiting for mobile upload
|
|
143
|
+
*/
|
|
144
|
+
getIsWaitingForUpload(): Observable<boolean>;
|
|
145
|
+
/**
|
|
146
|
+
* Get current field request info
|
|
147
|
+
*/
|
|
148
|
+
getCurrentFieldRequest(): Observable<FieldRequestInfo | null>;
|
|
149
|
+
/**
|
|
150
|
+
* Accept a pending file (emit to remoteUpload$ and call onFileAccept callback)
|
|
151
|
+
*/
|
|
152
|
+
acceptPendingFile(file: AngularRemoteUploadEvent): void;
|
|
153
|
+
/**
|
|
154
|
+
* Reject/delete a pending file
|
|
155
|
+
*/
|
|
156
|
+
rejectPendingFile(file: AngularRemoteUploadEvent): void;
|
|
157
|
+
/**
|
|
158
|
+
* Clear all pending files
|
|
159
|
+
*/
|
|
160
|
+
clearPendingFiles(): void;
|
|
161
|
+
/**
|
|
162
|
+
* Generate QR code data for mobile app
|
|
163
|
+
* Flow:
|
|
164
|
+
* 1. Call API to get a short-lived link token (UUID)
|
|
165
|
+
* 2. Build QR URL with: apiUrl, deviceId, userId, token
|
|
166
|
+
*/
|
|
167
|
+
generateQrCode(): Promise<{
|
|
168
|
+
qrData: string;
|
|
169
|
+
expiresAt: number;
|
|
170
|
+
}>;
|
|
171
|
+
/**
|
|
172
|
+
* Build QR URL with minimal parameters
|
|
173
|
+
*/
|
|
174
|
+
private buildQrUrl;
|
|
175
|
+
/**
|
|
176
|
+
* Call API via socket with timeout - helper method
|
|
177
|
+
*/
|
|
178
|
+
private callApiWithTimeout;
|
|
179
|
+
/**
|
|
180
|
+
* Send field request to mobile - tells mobile to show upload UI for this field
|
|
181
|
+
*/
|
|
182
|
+
sendFieldRequest(fieldInfo: {
|
|
183
|
+
label: string;
|
|
184
|
+
accept: string;
|
|
185
|
+
type: 'image' | 'file';
|
|
186
|
+
entityType?: string;
|
|
187
|
+
entityId?: any;
|
|
188
|
+
isMultiple?: boolean;
|
|
189
|
+
limit?: number;
|
|
190
|
+
remainingSlots?: number;
|
|
191
|
+
isCompressed?: boolean;
|
|
192
|
+
}): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* Cancel current field request
|
|
195
|
+
*/
|
|
196
|
+
cancelFieldRequest(): Promise<void>;
|
|
197
|
+
/**
|
|
198
|
+
* Accept mobile connection - update local state
|
|
199
|
+
* Note: Backend already broadcasts mobile-link-established to both parties
|
|
200
|
+
*/
|
|
201
|
+
private acceptMobileConnection;
|
|
202
|
+
/**
|
|
203
|
+
* Disconnect from mobile device - call API and clear local state
|
|
204
|
+
*/
|
|
205
|
+
disconnect(): Promise<void>;
|
|
206
|
+
/**
|
|
207
|
+
* Handle disconnect initiated from remote (mobile) side
|
|
208
|
+
*/
|
|
209
|
+
private handleRemoteDisconnect;
|
|
210
|
+
/**
|
|
211
|
+
* Start periodic health check for device online status
|
|
212
|
+
* Should be called when connection is established
|
|
213
|
+
*/
|
|
214
|
+
startHealthCheck(): void;
|
|
215
|
+
/**
|
|
216
|
+
* Stop health check
|
|
217
|
+
*/
|
|
218
|
+
stopHealthCheck(): void;
|
|
219
|
+
/**
|
|
220
|
+
* Check if both devices are online via API
|
|
221
|
+
*/
|
|
222
|
+
checkDevicesOnline(): Promise<DevicesOnlineStatus | null>;
|
|
223
|
+
/**
|
|
224
|
+
* Force an immediate health check
|
|
225
|
+
*/
|
|
226
|
+
refreshDevicesStatus(): Promise<DevicesOnlineStatus | null>;
|
|
227
|
+
/**
|
|
228
|
+
* Subscribe to channel for receiving messages from mobile
|
|
229
|
+
*/
|
|
230
|
+
private subscribeToChannel;
|
|
231
|
+
/**
|
|
232
|
+
* Handle incoming channel messages from mobile
|
|
233
|
+
*/
|
|
234
|
+
private handleChannelMessage;
|
|
235
|
+
/**
|
|
236
|
+
* Handle mobile-link-established message
|
|
237
|
+
* This is sent when mobile successfully connects via the backend
|
|
238
|
+
*/
|
|
239
|
+
private handleMobileLinkEstablished;
|
|
240
|
+
/**
|
|
241
|
+
* Handle connection state messages from mobile
|
|
242
|
+
*/
|
|
243
|
+
private handleConnectionState;
|
|
244
|
+
/**
|
|
245
|
+
* Handle upload complete from mobile
|
|
246
|
+
* Files are either auto-accepted or added to pending queue based on config
|
|
247
|
+
*/
|
|
248
|
+
private handleUploadComplete;
|
|
249
|
+
/**
|
|
250
|
+
* Handle mobile disconnect
|
|
251
|
+
*/
|
|
252
|
+
private handleMobileDisconnect;
|
|
253
|
+
/**
|
|
254
|
+
* Save mobile connection to localStorage
|
|
255
|
+
*/
|
|
256
|
+
private saveMobileConnection;
|
|
257
|
+
/**
|
|
258
|
+
* Restore mobile connection from localStorage
|
|
259
|
+
*/
|
|
260
|
+
private restoreMobileConnection;
|
|
261
|
+
/**
|
|
262
|
+
* Clear mobile connection from localStorage
|
|
263
|
+
*/
|
|
264
|
+
private clearMobileConnection;
|
|
265
|
+
/**
|
|
266
|
+
* Call HTTP API endpoint
|
|
267
|
+
*/
|
|
268
|
+
private callHttpApi;
|
|
269
|
+
ngOnDestroy(): void;
|
|
270
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AngularRemoteUploadService, never>;
|
|
271
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<AngularRemoteUploadService>;
|
|
272
|
+
}
|
|
273
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@servicemind.tis/angular-image-and-file-picker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Angular image and file upload component with drag-and-drop, pre-signed URL uploads, client-side compression, camera capture, and built-in preview for images, PDFs, video, and Excel.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"angular-material",
|
|
8
|
+
"file-upload",
|
|
9
|
+
"image-upload",
|
|
10
|
+
"drag-and-drop",
|
|
11
|
+
"file-viewer",
|
|
12
|
+
"pdf-viewer",
|
|
13
|
+
"image-compression",
|
|
14
|
+
"camera-capture"
|
|
15
|
+
],
|
|
16
|
+
"author": "Thai Informatics System",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/Thai-Informatics-System/angular-image-and-file-picker.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/Thai-Informatics-System/angular-image-and-file-picker#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/Thai-Informatics-System/angular-image-and-file-picker/issues"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@angular/common": "^19.2.0",
|
|
28
|
+
"@angular/core": "^19.2.0",
|
|
29
|
+
"@angular/material": "^19.2.8",
|
|
30
|
+
"@angular/cdk": "^19.2.8",
|
|
31
|
+
"ngx-extended-pdf-viewer": "^19.2.1",
|
|
32
|
+
"angularx-qrcode": "^19.0.0"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"tslib": "^2.3.0",
|
|
36
|
+
"browser-image-compression": "^2.0.0"
|
|
37
|
+
},
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"module": "fesm2022/servicemind.tis-angular-image-and-file-picker.mjs",
|
|
43
|
+
"typings": "index.d.ts",
|
|
44
|
+
"exports": {
|
|
45
|
+
"./package.json": {
|
|
46
|
+
"default": "./package.json"
|
|
47
|
+
},
|
|
48
|
+
".": {
|
|
49
|
+
"types": "./index.d.ts",
|
|
50
|
+
"default": "./fesm2022/servicemind.tis-angular-image-and-file-picker.mjs"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
package/public-api.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from './lib/angular-image-and-file-picker.service';
|
|
2
|
+
export * from './lib/angular-image-and-file-picker/angular-image-and-file-picker.component';
|
|
3
|
+
export * from './lib/angular-image-and-file-picker.module';
|
|
4
|
+
export * from './lib/interfaces';
|
|
5
|
+
export * from './lib/services/angular-remote-upload.service';
|
|
6
|
+
export * from './lib/angular-qr-code-dialog/angular-qr-code-dialog.component';
|
|
7
|
+
export * from './lib/angular-camera-capture-dialog/angular-camera-capture-dialog.component';
|