This commit is contained in:
Peter Maquiran
2022-03-18 14:45:05 +01:00
37 changed files with 819 additions and 305 deletions
@@ -1,17 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest package="com.gpr.gabinetedigital" xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:name=".App" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:label="@string/title_activity_main" android:launchMode="singleTask" android:name="com.gpr.gabinetedigital.MainActivity" android:theme="@style/AppTheme.NoActionBarLaunch">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
+41 -76
View File
@@ -799,6 +799,14 @@
"integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==",
"dev": true "dev": true
}, },
"@awesome-cordova-plugins/media-capture": {
"version": "5.40.0",
"resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/media-capture/-/media-capture-5.40.0.tgz",
"integrity": "sha512-Es5qhC6VeCzo0pq0V9txlMwSL3v1ZAUKtT74DDsTnItvbX56ZPdawL4u4fLA40VikaRNYZbYNnkYopifb8nJIw==",
"requires": {
"@types/cordova": "^0.0.34"
}
},
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.14.5", "version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
@@ -2194,6 +2202,7 @@
"integrity": "sha512-HCFwOxmK7igEgNm20y+zYi+XQ0OlZYnE4oCaI82TGmA7sehlDpBBKbjmI2Bd8aM09+BXFbAAtq7JCxkEfY8nIg==" "integrity": "sha512-HCFwOxmK7igEgNm20y+zYi+XQ0OlZYnE4oCaI82TGmA7sehlDpBBKbjmI2Bd8aM09+BXFbAAtq7JCxkEfY8nIg=="
}, },
"@capacitor/filesystem": { "@capacitor/filesystem": {
<<<<<<< HEAD
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-1.0.6.tgz", "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-1.0.6.tgz",
"integrity": "sha512-8xqUbDZFGBMhgqoBSn9wEd9OBPdHIRegQ9zCCZcpHNf3FFAIby1ck+aDFnoq+Da49xhD6ks1SKCBSxz/26qWTw==" "integrity": "sha512-8xqUbDZFGBMhgqoBSn9wEd9OBPdHIRegQ9zCCZcpHNf3FFAIby1ck+aDFnoq+Da49xhD6ks1SKCBSxz/26qWTw=="
@@ -2207,6 +2216,21 @@
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.3.0.tgz", "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.3.0.tgz",
"integrity": "sha512-KImT4hVoQJuAfe01wUYiMLnutMu7PxVCv4c8HVWiW+OuyyOua3lC8wQ5gAauGDugAo6mdM7fVva5a0Vtyhnbdg==" "integrity": "sha512-KImT4hVoQJuAfe01wUYiMLnutMu7PxVCv4c8HVWiW+OuyyOua3lC8wQ5gAauGDugAo6mdM7fVva5a0Vtyhnbdg=="
=======
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-1.1.0.tgz",
"integrity": "sha512-8O3UuvL8HNUEJvZnmn8yUmvgB1evtXfcF0oxIo3YbSlylqywJwS3JTiuhKmsvSxCdpbTy8IaTsutVh3gZgWbKg=="
},
"@capacitor/haptics": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-1.1.4.tgz",
"integrity": "sha512-+pJIb5X7xAcbrWj6rJaV+cwBlv8aFwB1/Ob6EV4atydThuuVSSsAL4hI4ZYlPNOxM6H5s+ZDLj7Pa2os4eFmtg=="
},
"@capacitor/ios": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.4.1.tgz",
"integrity": "sha512-ycFCyKI8DsgedVg7PW5MpCVgqFuD0PMHQGVfC5ichXc2C/jAATX32EVdEMCB0N3guKoH2k6T3Efwg59+Fcdx2w=="
>>>>>>> 0b14c4c0c63a6d55c9945163d7afb971a7375994
}, },
"@capacitor/keyboard": { "@capacitor/keyboard": {
"version": "1.1.3", "version": "1.1.3",
@@ -2989,6 +3013,7 @@
"integrity": "sha512-68hdPn0hA7yn4YNTgmLF32x/l7arFulboGhNiyFQ35/QxqrOmppf77p4xaPOyJtNyICKHLaiStC6w1eEAtl9MA==", "integrity": "sha512-68hdPn0hA7yn4YNTgmLF32x/l7arFulboGhNiyFQ35/QxqrOmppf77p4xaPOyJtNyICKHLaiStC6w1eEAtl9MA==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
<<<<<<< HEAD
}, },
"dependencies": { "dependencies": {
"@types/cordova": { "@types/cordova": {
@@ -2996,6 +3021,8 @@
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
} }
=======
>>>>>>> 0b14c4c0c63a6d55c9945163d7afb971a7375994
} }
}, },
"@ionic-native/core": { "@ionic-native/core": {
@@ -5071,11 +5098,6 @@
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
"dev": true "dev": true
}, },
"@types/pdfjs-dist": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@types/pdfjs-dist/-/pdfjs-dist-0.1.2.tgz",
"integrity": "sha512-BvRLWz6RCI8FMKbgfdTCadVwimUv8920gLsnBEAkECjtqIy95jtt+G1ebNQE2b8PTnLjJICPpmBOGhgkSsiPKA=="
},
"@types/prettier": { "@types/prettier": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz",
@@ -6241,7 +6263,8 @@
"big.js": { "big.js": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"dev": true
}, },
"binary-extensions": { "binary-extensions": {
"version": "2.2.0", "version": "2.2.0",
@@ -6962,9 +6985,9 @@
"dev": true "dev": true
}, },
"capacitor-voice-recorder": { "capacitor-voice-recorder": {
"version": "2.0.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/capacitor-voice-recorder/-/capacitor-voice-recorder-2.0.0.tgz", "resolved": "https://registry.npmjs.org/capacitor-voice-recorder/-/capacitor-voice-recorder-2.1.0.tgz",
"integrity": "sha512-YU0tN8+A963sCYjL9du6jbUqOh5w5dJf++8IFBkuV0sDQZuuLaK//1RypJi0MQLifQESZSjhTVWoXTViIthA/w==", "integrity": "sha512-H0c/sUVD7cduVS5VqutKk00whyqXZUFi56ChRMl9Ke/LBU71HhHwzonPmheT8i9gQmgOaplc3TOpaKqckXb+3A==",
"requires": { "requires": {
"get-blob-duration": "^1.2.0" "get-blob-duration": "^1.2.0"
} }
@@ -7262,7 +7285,8 @@
"co": { "co": {
"version": "4.6.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
"dev": true
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
@@ -8131,8 +8155,8 @@
"integrity": "sha1-TZ6Jgsz7OOBPqQnIe0vsBuLR2Ss=" "integrity": "sha1-TZ6Jgsz7OOBPqQnIe0vsBuLR2Ss="
}, },
"cordova-plugin-dbcopy": { "cordova-plugin-dbcopy": {
"version": "git+ssh://git@github.com/an-rahulpandey/cordova-plugin-dbcopy.git#861f585e4313db828d6b8c7d354c32c83373d0d2", "version": "git+https://github.com/an-rahulpandey/cordova-plugin-dbcopy.git#861f585e4313db828d6b8c7d354c32c83373d0d2",
"from": "cordova-plugin-dbcopy@git+https://github.com/an-rahulpandey/cordova-plugin-dbcopy.git" "from": "git+https://github.com/an-rahulpandey/cordova-plugin-dbcopy.git"
}, },
"cordova-plugin-device": { "cordova-plugin-device": {
"version": "2.0.3", "version": "2.0.3",
@@ -9533,7 +9557,8 @@
"emojis-list": { "emojis-list": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
"dev": true
}, },
"enabled": { "enabled": {
"version": "2.0.0", "version": "2.0.0",
@@ -16543,6 +16568,7 @@
"tslib": "^2.3.0" "tslib": "^2.3.0"
} }
}, },
<<<<<<< HEAD
"ng2-pdf-viewer": { "ng2-pdf-viewer": {
"version": "3.0.8", "version": "3.0.8",
"resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-3.0.8.tgz", "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-3.0.8.tgz",
@@ -16563,6 +16589,8 @@
} }
} }
}, },
=======
>>>>>>> 0b14c4c0c63a6d55c9945163d7afb971a7375994
"ngx-cookie-service": { "ngx-cookie-service": {
"version": "12.0.3", "version": "12.0.3",
"resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-12.0.3.tgz", "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-12.0.3.tgz",
@@ -16648,11 +16676,6 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
}, },
"node-ensure": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz",
"integrity": "sha1-7K52QVDemYYexcgQ/V0Jaxg5Mqc="
},
"node-fetch": { "node-fetch": {
"version": "2.6.1", "version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
@@ -24862,64 +24885,6 @@
"resolved": "https://registry.npmjs.org/wordcloud/-/wordcloud-1.2.2.tgz", "resolved": "https://registry.npmjs.org/wordcloud/-/wordcloud-1.2.2.tgz",
"integrity": "sha512-fUnDsGrHXou+49j1OeKaC7nOeZPx+sWjIet0L/j6eAcm0nXy+a+AuUs/iDAX4PLBg1Zc6wgXWXhoXdQsXRWAEw==" "integrity": "sha512-fUnDsGrHXou+49j1OeKaC7nOeZPx+sWjIet0L/j6eAcm0nXy+a+AuUs/iDAX4PLBg1Zc6wgXWXhoXdQsXRWAEw=="
}, },
"worker-loader": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-0.8.1.tgz",
"integrity": "sha1-6OmVMx6jTfW/aCloJL+38K1XjUM=",
"requires": {
"loader-utils": "^1.0.2",
"schema-utils": "^0.3.0"
},
"dependencies": {
"ajv": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"requires": {
"co": "^4.6.0",
"fast-deep-equal": "^1.0.0",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.3.0"
}
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
},
"schema-utils": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
"integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
"requires": {
"ajv": "^5.0.0"
}
}
}
},
"wrap-ansi": { "wrap-ansi": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+5 -5
View File
@@ -31,6 +31,7 @@
"@angular/platform-browser": "~12.1.2", "@angular/platform-browser": "~12.1.2",
"@angular/platform-browser-dynamic": "~12.1.2", "@angular/platform-browser-dynamic": "~12.1.2",
"@angular/router": "~12.1.2", "@angular/router": "~12.1.2",
"@awesome-cordova-plugins/media-capture": "^5.40.0",
"@byteowls/capacitor-filesharer": "^3.0.0", "@byteowls/capacitor-filesharer": "^3.0.0",
"@capacitor-community/camera-preview": "^1.2.1", "@capacitor-community/camera-preview": "^1.2.1",
"@capacitor/android": "3.3.3", "@capacitor/android": "3.3.3",
@@ -39,9 +40,9 @@
"@capacitor/camera": "^1.2.0", "@capacitor/camera": "^1.2.0",
"@capacitor/core": "^3.3.2", "@capacitor/core": "^3.3.2",
"@capacitor/device": "^1.1.0", "@capacitor/device": "^1.1.0",
"@capacitor/filesystem": "^1.0.6", "@capacitor/filesystem": "^1.1.0",
"@capacitor/haptics": "^1.1.2", "@capacitor/haptics": "^1.1.4",
"@capacitor/ios": "3.3.0", "@capacitor/ios": "3.4.1",
"@capacitor/keyboard": "^1.1.2", "@capacitor/keyboard": "^1.1.2",
"@capacitor/local-notifications": "^1.1.0", "@capacitor/local-notifications": "^1.1.0",
"@capacitor/network": "^1.0.6", "@capacitor/network": "^1.0.6",
@@ -101,7 +102,7 @@
"beast-orm": "^1.0.0", "beast-orm": "^1.0.0",
"bootstrap": "^4.5.0", "bootstrap": "^4.5.0",
"build": "0.1.4", "build": "0.1.4",
"capacitor-voice-recorder": "^2.0.0", "capacitor-voice-recorder": "^2.1.0",
"ci": "^2.1.1", "ci": "^2.1.1",
"cordova": "^10.0.0", "cordova": "^10.0.0",
"cordova-plugin-crop": "^0.4.0", "cordova-plugin-crop": "^0.4.0",
@@ -135,7 +136,6 @@
"lite-server": "^2.6.1", "lite-server": "^2.6.1",
"moment": "^2.29.1", "moment": "^2.29.1",
"ng-lazyload-image": "^9.1.2", "ng-lazyload-image": "^9.1.2",
"ng2-pdf-viewer": "^3.0.8",
"ngx-cookie-service": "^12.0.3", "ngx-cookie-service": "^12.0.3",
"ngx-image-compress": "^11.0.3", "ngx-image-compress": "^11.0.3",
"ngx-image-cropper": "^5.0.1", "ngx-image-cropper": "^5.0.1",
+4 -12
View File
@@ -12,18 +12,15 @@ import { HttpClientModule } from '@angular/common/http';
import { InAppBrowser } from '@ionic-native/in-app-browser/ngx'; import { InAppBrowser } from '@ionic-native/in-app-browser/ngx';
//import { File } from '@ionic-native/File/ngx'; //import { File } from '@ionic-native/File/ngx';
import { WebView } from '@ionic-native/ionic-webview/ngx'; import { WebView } from '@ionic-native/ionic-webview/ngx';
import { FilePath } from '@ionic-native/file-path/ngx'; import { FilePath } from '@ionic-native/file-path/ngx';
import { Camera } from '@ionic-native/camera/ngx'; import { Camera } from '@ionic-native/camera/ngx';
import { IonicStorageModule } from '@ionic/storage'; import { IonicStorageModule } from '@ionic/storage';
//
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CalendarModule, DateAdapter } from 'angular-calendar'; import { CalendarModule, DateAdapter } from 'angular-calendar';
import { adapterFactory } from 'angular-calendar/date-adapters/date-fns'; import { adapterFactory } from 'angular-calendar/date-adapters/date-fns';
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -35,10 +32,6 @@ import {MatDatepickerModule} from '@angular/material/datepicker';
import {MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core'; import {MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core';
import { NgxMatDateFormats, NGX_MAT_DATE_FORMATS } from '@angular-material-components/datetime-picker'; import { NgxMatDateFormats, NGX_MAT_DATE_FORMATS } from '@angular-material-components/datetime-picker';
import { Network } from '@ionic-native/network/ngx'; import { Network } from '@ionic-native/network/ngx';
import { File } from '@ionic-native/file/ngx';
import { import {
NgxMatDatetimePickerModule, NgxMatDatetimePickerModule,
NgxMatNativeDateModule, NgxMatNativeDateModule,
@@ -56,13 +49,14 @@ import { far } from '@fortawesome/free-regular-svg-icons'
import { fab } from '@fortawesome/free-brands-svg-icons' import { fab } from '@fortawesome/free-brands-svg-icons'
import { ScreenOrientation } from '@ionic-native/screen-orientation/ngx'; import { ScreenOrientation } from '@ionic-native/screen-orientation/ngx';
import { PdfViewerModule } from 'ng2-pdf-viewer';
import { SQLite } from '@ionic-native/sqlite/ngx'; import { SQLite } from '@ionic-native/sqlite/ngx';
import { CookieService } from 'ngx-cookie-service'; import { CookieService } from 'ngx-cookie-service';
import { ImagePicker } from '@ionic-native/image-picker/ngx'; import { ImagePicker } from '@ionic-native/image-picker/ngx';
import { MediaCapture } from '@ionic-native/media-capture/ngx'; import { MediaCapture } from '@ionic-native/media-capture/ngx';
import { Media } from '@ionic-native/media/ngx'; import { Media } from '@ionic-native/media/ngx';
import { File } from '@ionic-native/file/ngx';
import { StreamingMedia } from '@ionic-native/streaming-media/ngx'; import { StreamingMedia } from '@ionic-native/streaming-media/ngx';
import { PhotoViewer } from '@ionic-native/photo-viewer/ngx'; import { PhotoViewer } from '@ionic-native/photo-viewer/ngx';
import {NgxImageCompressService} from 'ngx-image-compress'; import {NgxImageCompressService} from 'ngx-image-compress';
@@ -111,10 +105,8 @@ import { FirebaseX } from '@ionic-native/firebase-x/ngx'; */
MatSelectModule, MatSelectModule,
MatDialogModule, MatDialogModule,
// //
PdfViewerModule,
HammerModule, HammerModule,
CustomImageCachePageRoutingModule CustomImageCachePageRoutingModule,
], ],
providers: [ providers: [
@@ -126,7 +118,7 @@ import { FirebaseX } from '@ionic-native/firebase-x/ngx'; */
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
InAppBrowser, InAppBrowser,
Camera, Camera,
//File, File,
WebView, WebView,
FilePath, FilePath,
/* FCM, /* FCM,
@@ -7,7 +7,6 @@ import { IonicModule } from '@ionic/angular';
import { DocumentViewerPageRoutingModule } from './document-viewer-routing.module'; import { DocumentViewerPageRoutingModule } from './document-viewer-routing.module';
import { DocumentViewerPage } from './document-viewer.page'; import { DocumentViewerPage } from './document-viewer.page';
import { PdfViewerModule } from 'ng2-pdf-viewer';
@NgModule({ @NgModule({
@@ -17,7 +16,6 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
IonicModule, IonicModule,
DocumentViewerPageRoutingModule, DocumentViewerPageRoutingModule,
// //
PdfViewerModule
], ],
declarations: [DocumentViewerPage] declarations: [DocumentViewerPage]
}) })
@@ -8,7 +8,6 @@ import { ViewMediaPageRoutingModule } from './view-media-routing.module';
import { ViewMediaPage } from './view-media.page'; import { ViewMediaPage } from './view-media.page';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { PdfViewerModule } from 'ng2-pdf-viewer';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -17,7 +16,6 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
IonicModule, IonicModule,
FontAwesomeModule, FontAwesomeModule,
ViewMediaPageRoutingModule, ViewMediaPageRoutingModule,
PdfViewerModule
], ],
declarations: [ViewMediaPage] declarations: [ViewMediaPage]
}) })
@@ -24,8 +24,6 @@
<img src="{{image}}"> <img src="{{image}}">
</div> </div>
<div *ngIf="type == 'application/pdf'"> <div *ngIf="type == 'application/pdf'">
<pdf-viewer [src]="image" [render-text]="true" [original-size]="false" [zoom]="0.5" style="display: block;">
</pdf-viewer>
</div> </div>
</div> </div>
</ion-slide> </ion-slide>
@@ -16,6 +16,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { ImageCropperModule } from 'ngx-image-cropper'; import { ImageCropperModule } from 'ngx-image-cropper';
import { AngularCropperjsModule } from 'angular-cropperjs'; import { AngularCropperjsModule } from 'angular-cropperjs';
import { LettersAvatarModule } from "ngx-letters-avatar"; import { LettersAvatarModule } from "ngx-letters-avatar";
import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -26,7 +27,8 @@ import { LettersAvatarModule } from "ngx-letters-avatar";
GroupMessagesPageRoutingModule, GroupMessagesPageRoutingModule,
ChatPopoverPageModule, ChatPopoverPageModule,
BtnModalDismissPageModule, BtnModalDismissPageModule,
LettersAvatarModule LettersAvatarModule,
PipesModule,
/* ImageCropperModule, /* ImageCropperModule,
AngularCropperjsModule */ AngularCropperjsModule */
@@ -106,7 +106,7 @@
<ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon> <ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon>
</div> </div>
<div *ngIf="msg.file.type != 'application/img'"> <div *ngIf="msg.file.type != 'application/img'">
<div class="file"> <div class="file add-attachment-bg-color" *ngIf="msg.file.type != 'aplication/audio'">
<div (click)="openPreview(msg)" class="file-details add-ellipsis cursor-pointer" *ngIf="msg.file"> <div (click)="openPreview(msg)" class="file-details add-ellipsis cursor-pointer" *ngIf="msg.file">
<span *ngIf="msg.file.type"> <span *ngIf="msg.file.type">
<fa-icon *ngIf="msg.file.type == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon> <fa-icon *ngIf="msg.file.type == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon>
@@ -117,11 +117,14 @@
<ion-label class="file-title">{{file.title}}</ion-label> <ion-label class="file-title">{{file.title}}</ion-label>
</div> </div>
</div> </div>
<div class="file-details-optional"> <div *ngIf="msg.file.type == 'aplication/audio'">
<ion-label *ngIf="msg.file"> <audio [src]="file.title_link|safehtml" preload="metadata" class="d-flex width-100" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<div class="file-details-optional add-attachment-bg-color">
<ion-label *ngIf="msg.file && msg.file != ''">
<span *ngIf="file.description">{{file.description}}</span> <span *ngIf="file.description">{{file.description}}</span>
<span *ngIf="file.description && msg.file.type != 'application/webtrix'"></span> <span *ngIf="file.description && msg.file.type != 'application/webtrix'"></span>
<span *ngIf="msg.file.type != 'application/webtrix'">{{msg.displayType}}</span> <span *ngIf="msg.file.type != 'application/webtrix' && msg.file.type != 'aplication/audio'">{{msg.displayType}}</span>
</ion-label> </ion-label>
</div> </div>
</div> </div>
@@ -195,27 +198,42 @@
fontFamily="Roboto"></ngx-letters-avatar> fontFamily="Roboto"></ngx-letters-avatar>
{{ wsChatMethodsService.getGroupRoom(roomId).userThatIsTyping }} está a escrever... {{ wsChatMethodsService.getGroupRoom(roomId).userThatIsTyping }} está a escrever...
</div> </div>
<div class="width-100 pl-20 pr-20">
<span *ngIf="!lastAudioRecorded">{{durationDisplay}}</span>
<audio [src]="audioRecorded" class="d-flex width-100 mt-10 mb-10" *ngIf="lastAudioRecorded" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<div class="container width-100 d-flex"> <div class="container width-100 d-flex">
<div> <div>
<button class="btn-no-color" (click)="openChatOptions()"> <button *ngIf="!recording && !lastAudioRecorded && allowTyping" class="btn-no-color" (click)="openChatOptions()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-options" src="assets/images/icons-add.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-options" src="assets/images/icons-add.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-options" src="assets/images/theme/gov/icons-add.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-options" src="assets/images/theme/gov/icons-add.svg"></ion-icon>
</button> </button>
<button *ngIf="recording || lastAudioRecorded || !allowTyping" class="btn-no-color" (click)="deleteRecording()">
<fa-icon class="icon-size-27" icon="trash"></fa-icon>
</button>
</div> </div>
<div class="message-box width-80"> <div class="message-box width-80">
<ion-item class="ion-no-padding type-message" lines="none"> <div *ngIf="!recording && !lastAudioRecorded" class="type-message">
<ion-textarea autocomplete="on" autocorrect="on" spellcheck="true" clearOnEdit="true" placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getGroupRoom(roomId).message" (ionChange)="wsChatMethodsService.getGroupRoom(roomId).sendTyping()"></ion-textarea> <ion-textarea *ngIf="allowTyping" autocomplete="on" autocorrect="on" spellcheck="true" clearOnEdit="true" placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getGroupRoom(roomId).message" (ionChange)="wsChatMethodsService.getGroupRoom(roomId).sendTyping()"></ion-textarea>
<button hidden class="btn-no-color"> </div>
<ion-icon slot="end" src="assets/icon/icons-chat-mic.svg"></ion-icon> <div *ngIf="recording" class="d-flex align-items-center justify-content-center">
<button (click)="stopRecording()" class="btn-no-color d-flex align-items-center justify-content-center">
<ion-icon class="icon-size-45" name="stop-circle-outline" color="danger"></ion-icon>
</button> </button>
</ion-item> </div>
</div> </div>
<div> <div>
<button #recordbtn *ngIf="!wsChatMethodsService.getGroupRoom(roomId).message && !lastAudioRecorded" (click)="startRecording()" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/default/icons-chat-record-audio.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-record-audio.svg"></ion-icon>
</button>
<button *ngIf="wsChatMethodsService.getGroupRoom(roomId).message" class="btn-no-color" (click)="sendMessage()"> <button *ngIf="wsChatMethodsService.getGroupRoom(roomId).message" class="btn-no-color" (click)="sendMessage()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
<button *ngIf="!wsChatMethodsService.getGroupRoom(roomId).message" class="btn-no-color"> <button *ngIf="!wsChatMethodsService.getGroupRoom(roomId).message && lastAudioRecorded" class="btn-no-color" (click)="sendAudio(lastAudioRecorded)">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
@@ -177,7 +177,7 @@
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
.messages-list-item-wrapper{ .messages-list-item-wrapper{
overflow: auto; overflow: hidden;
} }
.messages-list-item-wrapper-active{ .messages-list-item-wrapper-active{
background: #e6f6ff75 !important; background: #e6f6ff75 !important;
@@ -32,6 +32,9 @@ import { Storage } from '@ionic/storage';
import { CameraService } from 'src/app/services/camera.service'; import { CameraService } from 'src/app/services/camera.service';
import { SearchPage } from 'src/app/pages/search/search.page'; import { SearchPage } from 'src/app/pages/search/search.page';
import { ProcessesService } from 'src/app/services/processes.service'; import { ProcessesService } from 'src/app/services/processes.service';
import { VoiceRecorder, VoiceRecorderPlugin, RecordingData, GenericResponse, CurrentRecordingStatus } from 'capacitor-voice-recorder';
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
import { DomSanitizer } from '@angular/platform-browser';
@Component({ @Component({
selector: 'app-group-messages', selector: 'app-group-messages',
@@ -74,6 +77,15 @@ export class GroupMessagesPage implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('scrollMe') private myScrollContainer: ElementRef; @ViewChild('scrollMe') private myScrollContainer: ElementRef;
recording = false;
allowTyping = true;
storedFileNames = [];
lastAudioRecorded = '';
audioRecorded:any = "";
audioDownloaded:any = "";
durationDisplay = '';
duration = 0;
constructor( constructor(
private menu: MenuController, private menu: MenuController,
private modalController: ModalController, private modalController: ModalController,
@@ -97,8 +109,8 @@ export class GroupMessagesPage implements OnInit, AfterViewInit, OnDestroy {
private AttachmentsService: AttachmentsService, private AttachmentsService: AttachmentsService,
private storage: Storage, private storage: Storage,
private processesService: ProcessesService, private processesService: ProcessesService,
private CameraService: CameraService, private CameraService: CameraService,
private sanitiser: DomSanitizer,
) { ) {
this.loggedUserChat = authService.ValidatedUserChat['data']; this.loggedUserChat = authService.ValidatedUserChat['data'];
this.isGroupCreated = true; this.isGroupCreated = true;
@@ -132,6 +144,8 @@ export class GroupMessagesPage implements OnInit, AfterViewInit, OnDestroy {
this.wsChatMethodsService.getUserOfRoom(this.roomId).then((value) => { this.wsChatMethodsService.getUserOfRoom(this.roomId).then((value) => {
console.log('MEMBER', value) console.log('MEMBER', value)
}) })
VoiceRecorder.requestAudioRecordingPermission();
//this.loadFiles();
} }
setStatus(status: string) { setStatus(status: string) {
@@ -145,19 +159,8 @@ export class GroupMessagesPage implements OnInit, AfterViewInit, OnDestroy {
} }
deleteMessage(msgId: string) { deleteMessage(msgId: string) {
let body = { const room = this.wsChatMethodsService.getGroupRoom(this.roomId)
"roomId": this.roomId, this.alertService.confirmDeleteMessage(msgId, room);
"msgId": msgId,
"asUser": false,
}
if (msgId) {
//this.alertService.confirmDeleteMessage(body);
}
else {
this.toastService.badRequest('Não foi possível apagar');
}
this.showMessageOptions = false;
this.selectedMsgId = "";
} }
ngAfterViewInit() { ngAfterViewInit() {
@@ -197,6 +200,106 @@ export class GroupMessagesPage implements OnInit, AfterViewInit, OnDestroy {
this.currentPosition = scroll; this.currentPosition = scroll;
} }
calculateDuration() {
if (!this.recording) {
this.duration = 0;
this.durationDisplay = '';
return;
}
this.duration += 1;
const minutes = Math.floor(this.duration / 60);
const seconds = (this.duration % 60).toString().padStart(2, '0');
this.durationDisplay = `${minutes}:${seconds}`;
setTimeout(() => {
this.calculateDuration();
}, 1000)
}
async getFile(fileName?:any){
const audioFile = await Filesystem.readFile({
path: fileName,
directory: Directory.Data
})
//console.log(audioFile);
const base64sound = audioFile.data;
//Converting base64 to blob
const base64 = await fetch(base64sound);
//console.log(base64);
const base64Response = await fetch(`data:audio/ogg;base64,${base64sound}`);
//console.log(base64Response);
this.audioRecorded = base64Response.url;
console.log(this.audioRecorded);
}
async loadFiles() {
this.storage.get('fileName').then((fileName) => {
this.lastAudioRecorded = fileName;
})
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
if(recordData.value.recordDataBase64.includes('data:audio')){
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(recordData.value.recordDataBase64);
}
else{
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(`data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`);
}
});
}
startRecording() {
console.log('Recording');
if (this.recording) {
return;
}
this.recording = true;
VoiceRecorder.startRecording();
this.calculateDuration();
}
stopRecording() {
this.deleteRecording();
this.allowTyping = false;
console.log('Stop');
if (!this.recording) {
return;
}
this.recording = false;
VoiceRecorder.stopRecording().then(async (result: RecordingData) => {
console.log(result);
this.recording = false;
if (result.value && result.value.recordDataBase64) {
const recordData = result.value.recordDataBase64;
//console.log(recordData);
const fileName = new Date().getTime() + ".wav";
//Save file
this.storage.set('fileName',fileName);
this.storage.set('recordData',result).then(() => {
console.log('Audio recorded saved');
})
}
})
setTimeout(async () => {
this.loadFiles();
}, 1000);
}
async deleteRecording(){
this.storage.remove('fileName');
this.storage.remove('recordData');
this.allowTyping = true;
this.lastAudioRecorded = '';
this.loadFiles();
}
async goToEvent(eventId: any) { async goToEvent(eventId: any) {
let classs; let classs;
@@ -268,6 +371,7 @@ export class GroupMessagesPage implements OnInit, AfterViewInit, OnDestroy {
close() { close() {
this.modalController.dismiss(); this.modalController.dismiss();
this.deleteRecording();
} }
doRefresh(ev: any) { doRefresh(ev: any) {
@@ -311,13 +415,48 @@ export class GroupMessagesPage implements OnInit, AfterViewInit, OnDestroy {
return i; return i;
} }
sendMessage() { sendMessage() {
this.wsChatMethodsService.getGroupRoom(this.roomId).send({}) this.wsChatMethodsService.getGroupRoom(this.roomId).send({})
} }
async sendAudio(fileName) {
const roomId = this.roomId
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
if(recordData.value.recordDataBase64.includes('data:audio')){
this.audioRecorded = recordData.value.recordDataBase64;
}
else{
this.audioRecorded = `data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`;
}
});
//Converting base64 to blob
const base64Response = await fetch(this.audioRecorded);
const blob = await base64Response.blob();
const formData = new FormData();
formData.append("blobFile", blob);
this.wsChatMethodsService.getGroupRoom(roomId).send({
file: {
"type": "aplication/audio",
/* "guid": '', */
},
attachments: [{
"title": fileName ,
"title_link": this.audioRecorded,
"title_link_download": true,
"type": "file"
}],
temporaryData: formData
})
this.deleteRecording();
}
async openOptions() { async openOptions() {
const modal = await this.popoverController.create({ const modal = await this.popoverController.create({
component: ChatPopoverPage, component: ChatPopoverPage,
@@ -12,6 +12,7 @@ import { BtnModalDismissPage } from 'src/app/shared/btn-modal-dismiss/btn-modal-
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { MatMenuModule } from '@angular/material/menu'; import { MatMenuModule } from '@angular/material/menu';
import { LettersAvatarModule } from "ngx-letters-avatar"; import { LettersAvatarModule } from "ngx-letters-avatar";
import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -21,7 +22,8 @@ import { LettersAvatarModule } from "ngx-letters-avatar";
FontAwesomeModule, FontAwesomeModule,
MessagesPageRoutingModule, MessagesPageRoutingModule,
MatMenuModule, MatMenuModule,
LettersAvatarModule LettersAvatarModule,
PipesModule,
], ],
declarations: [MessagesPage] declarations: [MessagesPage]
}) })
+30 -28
View File
@@ -87,8 +87,8 @@
<ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon> <ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon>
</div> </div>
<div *ngIf="msg.file.type != 'application/img'"> <div *ngIf="msg.file.type != 'application/img'">
<div class="file"> <div class="file add-attachment-bg-color" *ngIf="msg.file.type != 'aplication/audio'">
<div (click)="docIndex(i); openPreview(msg)" class="file-details add-ellipsis cursor-pointer" *ngIf="msg.file"> <div (click)="docIndex(i); viewDocument(msg, file.title_link)" class="file-details add-ellipsis cursor-pointer" *ngIf="msg.file">
<span *ngIf="msg.file.type"> <span *ngIf="msg.file.type">
<fa-icon *ngIf="msg.file.type == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon> <fa-icon *ngIf="msg.file.type == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon>
<fa-icon *ngIf="msg.file.type == 'application/word'" icon="file-word" class="word-icon"></fa-icon> <fa-icon *ngIf="msg.file.type == 'application/word'" icon="file-word" class="word-icon"></fa-icon>
@@ -98,11 +98,14 @@
<ion-label class="file-title">{{file.title}}</ion-label> <ion-label class="file-title">{{file.title}}</ion-label>
</div> </div>
</div> </div>
<div class="file-details-optional"> <div *ngIf="msg.file.type == 'aplication/audio'">
<audio [src]="file.title_link|safehtml" preload="metadata" class="d-flex width-100" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<div class="file-details-optional add-attachment-bg-color">
<ion-label *ngIf="msg.file && msg.file != ''"> <ion-label *ngIf="msg.file && msg.file != ''">
<span *ngIf="file.description">{{file.description}}</span> <span *ngIf="file.description">{{file.description}}</span>
<span *ngIf="file.description && msg.file.type != 'application/webtrix'"></span> <span *ngIf="file.description && msg.file.type != 'application/webtrix'"></span>
<span *ngIf="msg.file.type != 'application/webtrix'">{{msg.displayType}}</span> <span *ngIf="msg.file.type != 'application/webtrix' && msg.file.type != 'aplication/audio'">{{msg.displayType}}</span>
</ion-label> </ion-label>
</div> </div>
</div> </div>
@@ -173,42 +176,41 @@
fontFamily="Roboto"></ngx-letters-avatar> fontFamily="Roboto"></ngx-letters-avatar>
está a escrever ... está a escrever ...
</div> </div>
<div class="width-100 pl-20 pr-20">
<span *ngIf="!lastAudioRecorded">{{durationDisplay}}</span>
<audio [src]="audioRecorded" class="d-flex width-100 mt-10 mb-10" *ngIf="lastAudioRecorded" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<ion-list>
<ion-item (click)="playFile(storedFileNames)">
{{storedFileNames}}
</ion-item>
<ion-item (click)="playFile(storedFileNames)">
{{storedFileNames}}
</ion-item>
</ion-list>
<audio controls>
<!-- <source src="https://www.tabularium.pt/file-upload/5g6DkyMC4MHcuaDyp/Audio%20record.mp3" type="audio/mpeg"> -->
</audio>
<button (click)="startRecording()">Start Recording</button>
<button (click)="stopRecording()">Stop Recording</button>
<div class="container width-100 d-flex"> <div class="container width-100 d-flex">
<div> <div>
<button class="btn-no-color" (click)="openChatOptions()"> <button *ngIf="!recording && !lastAudioRecorded && allowTyping" class="btn-no-color" (click)="openChatOptions()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-options" src="assets/images/icons-add.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-options" src="assets/images/icons-add.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-options" src="assets/images/theme/gov/icons-add.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-options" src="assets/images/theme/gov/icons-add.svg"></ion-icon>
</button> </button>
</div> <button *ngIf="recording || lastAudioRecorded || !allowTyping" class="btn-no-color" (click)="deleteRecording()">
<div class="width-70"> <fa-icon class="icon-size-27" icon="trash"></fa-icon>
<ion-item class="ion-no-padding ion-no-margin type-message" lines="none">
<ion-textarea autocomplete="on" autocorrect="on" spellcheck="true" *ngIf="!recording" clearOnEdit="true" placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getDmRoom(roomId).message" (ionChange)="wsChatMethodsService.getDmRoom(roomId).sendTyping()"></ion-textarea>
<ion-textarea autocomplete="on" spellcheck="true" *ngIf="recording" clearOnEdit="true" placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1" [(ngModel)]="durationDisplay"></ion-textarea>
<button hidden #recordbtn class="btn-no-color" (click)="notImplemented()">
<ion-icon slot="end" src="assets/icon/icons-chat-mic.svg"></ion-icon>
</button> </button>
</ion-item> </div>
<div class="width-70 message-container">
<div *ngIf="!recording && !lastAudioRecorded" class="type-message">
<ion-textarea *ngIf="allowTyping" autocomplete="on" autocorrect="on" spellcheck="true" clearOnEdit="true" placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getDmRoom(roomId).message" (ionChange)="wsChatMethodsService.getDmRoom(roomId).sendTyping()"></ion-textarea>
</div>
<div *ngIf="recording" class="d-flex align-items-center justify-content-center">
<button (click)="stopRecording()" class="btn-no-color d-flex align-items-center justify-content-center">
<ion-icon class="icon-size-45" name="stop-circle-outline" color="danger"></ion-icon>
</button>
</div>
</div> </div>
<div> <div>
<button *ngIf="wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color" (click)="sendMessage()"> <button #recordbtn *ngIf="!wsChatMethodsService.getDmRoom(roomId).message && !lastAudioRecorded" (click)="startRecording()" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/default/icons-chat-record-audio.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-record-audio.svg"></ion-icon>
</button>
<button *ngIf="wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color" (click)="sendMessage()" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
<button *ngIf="!wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color"> <button *ngIf="!wsChatMethodsService.getDmRoom(roomId).message && lastAudioRecorded" (click)="sendAudio(lastAudioRecorded)" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
+13 -5
View File
@@ -56,9 +56,6 @@
width: calc(100% - 25px); width: calc(100% - 25px);
text-align: right; text-align: right;
/* ion-icon{
font-size: 25px;
} */
.middle-container-options-icons{ .middle-container-options-icons{
color: #0782c9; color: #0782c9;
font-size: 23px; font-size: 23px;
@@ -117,6 +114,7 @@
} }
} }
} }
ion-content{ ion-content{
.welcome-text{ .welcome-text{
/* width: 322px; */ /* width: 322px; */
@@ -148,7 +146,7 @@
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
.messages-list-item-wrapper{ .messages-list-item-wrapper{
overflow: auto; overflow: hidden;
} }
.messages-list-item-wrapper-active{ .messages-list-item-wrapper-active{
background: #e6f6ff75 !important; background: #e6f6ff75 !important;
@@ -228,7 +226,6 @@
justify-content: center; justify-content: center;
justify-content: space-evenly; justify-content: space-evenly;
align-items: center; align-items: center;
} }
.chat-icon-options{ .chat-icon-options{
@@ -320,3 +317,14 @@ display: block;
.typing ngx-letters-avatar { .typing ngx-letters-avatar {
padding-right: 5px; padding-right: 5px;
} }
button{
padding: 0px;
border: 0px;
}
button::-moz-focus-inner {
padding: 0px;
border: 0px;
}
+113 -51
View File
@@ -20,7 +20,7 @@ import { ChatUserStorage } from 'src/app/store/chat/chat-user.service';
import { environment } from 'src/environments/environment'; import { environment } from 'src/environments/environment';
import { ThemeService } from 'src/app/services/theme.service' import { ThemeService } from 'src/app/services/theme.service'
import { Directory, Encoding, FilesystemDirectory } from '@capacitor/filesystem'; import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
import { VoiceRecorder, VoiceRecorderPlugin, RecordingData, GenericResponse, CurrentRecordingStatus } from 'capacitor-voice-recorder'; import { VoiceRecorder, VoiceRecorderPlugin, RecordingData, GenericResponse, CurrentRecordingStatus } from 'capacitor-voice-recorder';
import { Haptics, ImpactStyle } from '@capacitor/haptics'; import { Haptics, ImpactStyle } from '@capacitor/haptics';
import { PreviewCameraPage } from 'src/app/modals/preview-camera/preview-camera.page'; import { PreviewCameraPage } from 'src/app/modals/preview-camera/preview-camera.page';
@@ -40,13 +40,10 @@ import { SearchPage } from 'src/app/pages/search/search.page';
import { Storage } from '@ionic/storage'; import { Storage } from '@ionic/storage';
import { FileToBase64Service } from 'src/app/services/file/file-to-base64.service'; import { FileToBase64Service } from 'src/app/services/file/file-to-base64.service';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'; import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { Plugins } from '@capacitor/core'; import { DomSanitizer } from '@angular/platform-browser';
import { fromByteArray } from 'base64-js'; /* import {Plugins} from '@capacitor/core';
const { Filesystem } = Plugins; const { Filesystem } = Plugins; */
const IMAGE_DIR = 'stored-images';
@Component({ @Component({
selector: 'app-messages', selector: 'app-messages',
@@ -87,7 +84,11 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
LoadedDocument: any = null; LoadedDocument: any = null;
recording = false; recording = false;
allowTyping = true;
storedFileNames = []; storedFileNames = [];
lastAudioRecorded = '';
audioRecorded:any = "";
audioDownloaded:any = "";
durationDisplay = ''; durationDisplay = '';
duration = 0; duration = 0;
@ViewChild('recordbtn', { read: ElementRef }) recordBtn: ElementRef; @ViewChild('recordbtn', { read: ElementRef }) recordBtn: ElementRef;
@@ -120,6 +121,7 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
private processesService: ProcessesService, private processesService: ProcessesService,
private storage: Storage, private storage: Storage,
private fileToBase64Service: FileToBase64Service, private fileToBase64Service: FileToBase64Service,
private sanitiser: DomSanitizer,
) { ) {
this.loggedUser = authService.ValidatedUserChat['data']; this.loggedUser = authService.ValidatedUserChat['data'];
this.roomId = this.navParams.get('roomId'); this.roomId = this.navParams.get('roomId');
@@ -131,6 +133,8 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
} }
}; };
console.log(this.wsChatMethodsService.getDmRoom(this.roomId).loadHistory({}));
this.wsChatMethodsService.getDmRoom(this.roomId).loadHistory({}) this.wsChatMethodsService.getDmRoom(this.roomId).loadHistory({})
this.wsChatMethodsService.getDmRoom(this.roomId).scrollDown = this.scrollToBottomClicked this.wsChatMethodsService.getDmRoom(this.roomId).scrollDown = this.scrollToBottomClicked
this.wsChatMethodsService.openRoom(this.roomId) this.wsChatMethodsService.openRoom(this.roomId)
@@ -145,15 +149,14 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
this.wsChatMethodsService.getUserOfRoom(this.roomId).then((value) => { this.wsChatMethodsService.getUserOfRoom(this.roomId).then((value) => {
console.log('MEMBER', value) console.log('MEMBER', value)
}) })
//this.loadFiles(); //this.loadFiles();
VoiceRecorder.requestAudioRecordingPermission(); VoiceRecorder.requestAudioRecordingPermission();
this.getChatMembers(); this.getChatMembers();
Filesystem.mkdir({ /* Filesystem.mkdir({
path: IMAGE_DIR, path: IMAGE_DIR,
directory: Directory.Data, directory: Directory.Data,
recursive: true recursive: true
}); }); */
} }
ngAfterViewInit() { ngAfterViewInit() {
@@ -167,11 +170,14 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
onStart: ev => { onStart: ev => {
Haptics.impact({ style: ImpactStyle.Light }) Haptics.impact({ style: ImpactStyle.Light })
this.startRecording(); this.startRecording();
this.calculateDuration(); //this.calculateDuration();
}, },
onEnd: ev => { onEnd: ev => {
Haptics.impact({ style: ImpactStyle.Light }) Haptics.impact({ style: ImpactStyle.Light })
this.stopRecording(); this.stopRecording();
/* setTimeout(() => {
this.loadFiles();
}, 500); */
} }
}, true); }, true);
longpress.enable(); longpress.enable();
@@ -194,61 +200,73 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
} }
async loadFiles() { async loadFiles() {
Filesystem.readdir({
path: '', this.storage.get('fileName').then((fileName) => {
directory: Directory.Data this.lastAudioRecorded = fileName;
}).then(result => {
console.log(result);
const temp: any[] = result.files.reverse();
this.storedFileNames = temp[0];
console.log(this.storedFileNames);
}) })
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
if(recordData.value.recordDataBase64.includes('data:audio')){
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(recordData.value.recordDataBase64);
}
else{
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(`data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`);
}
});
} }
startRecording() { startRecording() {
console.log('Recording');
if (this.recording) { if (this.recording) {
return; return;
} }
this.recording = true; this.recording = true;
VoiceRecorder.startRecording(); VoiceRecorder.startRecording()
.then((result: GenericResponse) => console.log(result.value))
.catch(error => console.log(error));
this.calculateDuration();
} }
stopRecording() { stopRecording() {
this.deleteRecording();
this.allowTyping = false;
console.log('Stop');
if (!this.recording) { if (!this.recording) {
return; return;
} }
this.recording = false; this.recording = false;
VoiceRecorder.stopRecording().then(async (result: RecordingData) => { VoiceRecorder.stopRecording().then(async (result: RecordingData) => {
console.log(result);
this.recording = false; this.recording = false;
if (result.value && result.value.recordDataBase64) { if (result.value && result.value.recordDataBase64) {
const recordData = result.value.recordDataBase64; const recordData = result.value.recordDataBase64;
console.log(recordData); //console.log(recordData);
this.myAudio = recordData;
const fileName = new Date().getTime() + ".wav"; const fileName = new Date().getTime() + ".wav";
await Filesystem.writeFile({ //Save file
path: fileName, this.storage.set('fileName',fileName);
directory: Directory.Data, this.storage.set('recordData',result).then(() => {
data: recordData, console.log('Audio recorded saved');
}) })
} }
}) })
setTimeout(async () => {
this.loadFiles();
}, 1000);
} }
async playFile(fileName?: any) { async deleteRecording(){
const audioFile = await Filesystem.readFile({ this.storage.remove('fileName');
path: fileName, this.storage.remove('recordData');
directory: Directory.Data
})
console.log(audioFile);
const base64sound = audioFile.data;
const audioRef = new Audio(`data:audio/aac;base64,${base64sound}`)
audioRef.oncanplaythrough = () => audioRef.play();
audioRef.load();
this.allowTyping = true;
this.lastAudioRecorded = '';
this.loadFiles();
} }
handlePress(id?: string) { handlePress(id?: string) {
this.selectedMsgId = id; this.selectedMsgId = id;
this.showMessageOptions = true; this.showMessageOptions = true;
@@ -260,19 +278,8 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
} }
deleteMessage(msgId: string) { deleteMessage(msgId: string) {
let body = { const room = this.wsChatMethodsService.getDmRoom(this.roomId)
"roomId": this.roomId, this.alertService.confirmDeleteMessage(msgId, room);
"msgId": msgId,
"asUser": false,
}
if (msgId) {
//this.alertService.confirmDeleteMessage(body);
}
else {
this.toastService.badRequest('Não foi possível apagar');
}
this.showMessageOptions = false;
this.selectedMsgId = "";
} }
@@ -282,6 +289,7 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
close() { close() {
this.modalController.dismiss(); this.modalController.dismiss();
this.deleteRecording();
} }
load() { load() {
@@ -358,6 +366,53 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
this.wsChatMethodsService.getDmRoom(this.roomId).send({}) this.wsChatMethodsService.getDmRoom(this.roomId).send({})
} }
async sendAudio(fileName) {
const roomId = this.roomId
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
if(recordData.value.recordDataBase64.includes('data:audio')){
this.audioRecorded = recordData.value.recordDataBase64;
}
else{
this.audioRecorded = `data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`;
}
});
//Converting base64 to blob
const base64Response = await fetch(this.audioRecorded);
const blob = await base64Response.blob();
const formData = new FormData();
formData.append("blobFile", blob);
this.wsChatMethodsService.getDmRoom(roomId).send({
file: {
"type": "aplication/audio",
/* "guid": '', */
},
attachments: [{
"title": fileName ,
"title_link": this.audioRecorded,
"title_link_download": true,
"type": "file"
}],
temporaryData: formData
})
this.deleteRecording();
}
blobToBase64 = blob => {
const reader = new FileReader();
reader.readAsDataURL(blob);
return new Promise(resolve => {
reader.onloadend = () => {
resolve(reader.result);
};
});
};
viewDocument(msg: any, url?: string) { viewDocument(msg: any, url?: string) {
console.log(msg) console.log(msg)
if (msg.attachments.type == "application/webtrix") { if (msg.attachments.type == "application/webtrix") {
@@ -396,6 +451,13 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
} }
} }
/* playSound(url?:any){
alert('here')
console.log(url);
//this.audioDownloaded = this.sanitiser.bypassSecurityTrustResourceUrl(url);
this.audioDownloaded = url;
} */
docIndex(index: number) { docIndex(index: number) {
this.dicIndex = index this.dicIndex = index
} }
-2
View File
@@ -5,7 +5,6 @@ import { IonicModule } from '@ionic/angular';
import { EventsPageRoutingModule } from './events-routing.module'; import { EventsPageRoutingModule } from './events-routing.module';
import { EventsPage } from './events.page'; import { EventsPage } from './events.page';
import { HeaderPageModule } from 'src/app/shared/header/header.module'; import { HeaderPageModule } from 'src/app/shared/header/header.module';
import { PdfViewerModule } from 'ng2-pdf-viewer';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -15,7 +14,6 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
EventsPageRoutingModule, EventsPageRoutingModule,
HeaderPageModule, HeaderPageModule,
// //
PdfViewerModule
], ],
declarations: [EventsPage], declarations: [EventsPage],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
+3 -2
View File
@@ -6,11 +6,12 @@ import { EventPipe } from './event.pipe';
import { PublicationPipe } from './publication.pipe'; import { PublicationPipe } from './publication.pipe';
import { ExpedienteTaskPipe } from './expediente-task.pipe'; import { ExpedienteTaskPipe } from './expediente-task.pipe';
import { ParticipantsPipe } from './participants.pipe'; import { ParticipantsPipe } from './participants.pipe';
import { SafehtmlPipe } from './safehtml.pipe';
@NgModule({ @NgModule({
declarations: [FilterPipe, SearchDocumentPipe, CustomTaskPipe, EventPipe, PublicationPipe, ExpedienteTaskPipe, ParticipantsPipe], declarations: [FilterPipe, SearchDocumentPipe, CustomTaskPipe, EventPipe, PublicationPipe, ExpedienteTaskPipe, ParticipantsPipe, SafehtmlPipe],
exports: [FilterPipe], exports: [FilterPipe, SafehtmlPipe],
imports: [] imports: []
}) })
export class PipesModule { } export class PipesModule { }
+8
View File
@@ -0,0 +1,8 @@
import { SafehtmlPipe } from './safehtml.pipe';
describe('SafehtmlPipe', () => {
it('create an instance', () => {
const pipe = new SafehtmlPipe();
expect(pipe).toBeTruthy();
});
});
+14
View File
@@ -0,0 +1,14 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'safehtml'
})
export class SafehtmlPipe implements PipeTransform {
constructor(private sanitiser: DomSanitizer){}
transform(html): unknown {
return this.sanitiser.bypassSecurityTrustResourceUrl(html);
}
}
+1 -1
View File
@@ -728,7 +728,7 @@ export class WsChatService {
this.wsMsgQueue[requestId] = {message, requestId, loginRequired} this.wsMsgQueue[requestId] = {message, requestId, loginRequired}
} else { } else {
let messageStr = JSON.stringify(message) let messageStr = JSON.stringify(message)
// console.log('messageStr', messageStr) console.log('messageStr', messageStr)
this.socket.send(messageStr) this.socket.send(messageStr)
} }
-2
View File
@@ -5,7 +5,6 @@ import { IonicModule } from '@ionic/angular';
import { EventsPageRoutingModule } from './events-routing.module'; import { EventsPageRoutingModule } from './events-routing.module';
import { EventsPage } from './events.page'; import { EventsPage } from './events.page';
import { HeaderPageModule } from 'src/app/shared/header/header.module'; import { HeaderPageModule } from 'src/app/shared/header/header.module';
import { PdfViewerModule } from 'ng2-pdf-viewer';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -15,7 +14,6 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
EventsPageRoutingModule, EventsPageRoutingModule,
HeaderPageModule, HeaderPageModule,
// //
PdfViewerModule
], ],
declarations: [EventsPage], declarations: [EventsPage],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
-5
View File
@@ -113,9 +113,4 @@
</div> </div>
</div> </div>
<!-- <pdf-viewer [src]="pdfSrc"
[render-text]="true"
style="display: block;"
></pdf-viewer> -->
</ion-content> </ion-content>
@@ -11,10 +11,10 @@ import { SharedModule } from 'src/app/shared/shared.module';
import { ChatPopoverPageModule } from '../../popover/chat-popover/chat-popover.module'; import { ChatPopoverPageModule } from '../../popover/chat-popover/chat-popover.module';
import { NewEventPageModule } from '../../agenda/new-event/new-event.module'; import { NewEventPageModule } from '../../agenda/new-event/new-event.module';
import { PdfViewerModule } from 'ng2-pdf-viewer';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import {MatMenuModule} from '@angular/material/menu'; import {MatMenuModule} from '@angular/material/menu';
import { LettersAvatarModule } from "ngx-letters-avatar"; import { LettersAvatarModule } from "ngx-letters-avatar";
import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -22,11 +22,11 @@ import { LettersAvatarModule } from "ngx-letters-avatar";
FormsModule, FormsModule,
IonicModule, IonicModule,
FontAwesomeModule, FontAwesomeModule,
PdfViewerModule,
ChatPopoverPageModule, ChatPopoverPageModule,
GroupMessagesPageRoutingModule, GroupMessagesPageRoutingModule,
MatMenuModule, MatMenuModule,
LettersAvatarModule LettersAvatarModule,
PipesModule,
// //
], ],
exports: [GroupMessagesPage], exports: [GroupMessagesPage],
@@ -72,6 +72,7 @@
</mat-menu> </mat-menu>
</div> </div>
<div class="title"> <div class="title">
<ion-label>{{msg.u.name}}</ion-label>
<span class="time">{{msg.duration}}</span> <span class="time">{{msg.duration}}</span>
</div> </div>
<div class="message"> <div class="message">
@@ -82,7 +83,7 @@
<ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon> <ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon>
</div> </div>
<div *ngIf="msg.file.type != 'application/img'"> <div *ngIf="msg.file.type != 'application/img'">
<div class="file"> <div *ngIf="msg.file.type != 'aplication/audio'" class="file add-attachment-bg-color">
<div (click)="openPreview(msg)" class="file-details add-ellipsis cursor-pointer" *ngIf="msg.file"> <div (click)="openPreview(msg)" class="file-details add-ellipsis cursor-pointer" *ngIf="msg.file">
<span *ngIf="msg.file.type"> <span *ngIf="msg.file.type">
<fa-icon *ngIf="msg.file.type == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon> <fa-icon *ngIf="msg.file.type == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon>
@@ -93,11 +94,14 @@
<ion-label class="file-title">{{file.title}}</ion-label> <ion-label class="file-title">{{file.title}}</ion-label>
</div> </div>
</div> </div>
<div class="file-details-optional"> <div class="audio-contentainer" *ngIf="msg.file.type == 'aplication/audio'">
<audio [src]="file.title_link|safehtml" preload="metadata" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<div class="file-details-optional add-attachment-bg-color">
<ion-label *ngIf="msg.file"> <ion-label *ngIf="msg.file">
<span *ngIf="file.description">{{file.description}}</span> <span *ngIf="file.description">{{file.description}}</span>
<span *ngIf="file.description && msg.file.type != 'application/webtrix'"></span> <span *ngIf="file.description && msg.file.type != 'application/webtrix'"></span>
<span *ngIf="msg.file.type != 'application/webtrix'">{{msg.displayType}}</span> <span *ngIf="msg.file.type != 'application/webtrix' && msg.file.type != 'aplication/audio'">{{msg.displayType}}</span>
</ion-label> </ion-label>
</div> </div>
</div> </div>
@@ -214,13 +218,14 @@
{{ wsChatMethodsService.getGroupRoom(roomId).userThatIsTyping }} está a escrever... {{ wsChatMethodsService.getGroupRoom(roomId).userThatIsTyping }} está a escrever...
</div> --> </div> -->
<div class="width-100 pl-20 pr-20">
<span *ngIf="!lastAudioRecorded">{{durationDisplay}}</span>
<audio [src]="audioRecorded" class="d-flex width-100 mt-10 mb-10" *ngIf="lastAudioRecorded" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<div class="container width-100 d-flex"> <div class="container width-100 d-flex">
<div> <div>
<!-- <button class="btn-no-color" (click)="openSendGroupMessageOptions()"> <ion-fab *ngIf="!recording && !lastAudioRecorded && allowTyping" horizontal="start" vertical="bottom" slot="fixed">
<ion-icon class="chat-icon-options" src="assets/images/icons-add.svg"></ion-icon>
</button> -->
<ion-fab horizontal="start" vertical="bottom" slot="fixed">
<ion-fab-button color="light" size="small"> <ion-fab-button color="light" size="small">
<ion-icon name="add"></ion-icon> <ion-icon name="add"></ion-icon>
</ion-fab-button> </ion-fab-button>
@@ -242,22 +247,32 @@
</ion-fab-button> </ion-fab-button>
</ion-fab-list> </ion-fab-list>
</ion-fab> </ion-fab>
<button *ngIf="recording || lastAudioRecorded || !allowTyping" class="btn-delete-recording btn-no-color" (click)="deleteRecording()">
<fa-icon class="icon-size-27" icon="trash"></fa-icon>
</button>
</div> </div>
<div class="width-100"> <div class="width-100">
<ion-item class="ion-no-padding type-message" lines="none"> <div *ngIf="!recording && !lastAudioRecorded" class="type-message">
<ion-textarea autocomplete="on" autocorrect="on" spellcheck="true" (keyup.enter)="sendMessage()" clearOnEdit="true" placeholder="Escrever uma mensagem" class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getGroupRoom(roomId).message" (ionChange)="wsChatMethodsService.getGroupRoom(roomId).sendTyping()"></ion-textarea> <ion-textarea autocomplete="on" autocorrect="on" spellcheck="true" (keyup.enter)="sendMessage()" clearOnEdit="true" placeholder="Escrever uma mensagem" class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getGroupRoom(roomId).message" (ionChange)="wsChatMethodsService.getGroupRoom(roomId).sendTyping()"></ion-textarea>
<button hidden class="btn-no-color">
<ion-icon slot="end" src="assets/icon/icons-chat-mic.svg"></ion-icon>
</button>
</ion-item>
</div> </div>
<div *ngIf="recording" class="d-flex align-items-center justify-content-center">
<button (click)="stopRecording()" class="btn-no-color d-flex align-items-center justify-content-center">
<ion-icon class="icon-size-45" name="stop-circle-outline" color="danger"></ion-icon>
</button>
</div>
</div>
<div class="btn-send"> <div class="btn-send">
<button #recordbtn *ngIf="!wsChatMethodsService.getGroupRoom(roomId).message && !lastAudioRecorded" (click)="startRecording()" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/default/icons-chat-record-audio.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-record-audio.svg"></ion-icon>
</button>
<button *ngIf="wsChatMethodsService.getGroupRoom(roomId).message" class="btn-no-color" (click)="sendMessage()"> <button *ngIf="wsChatMethodsService.getGroupRoom(roomId).message" class="btn-no-color" (click)="sendMessage()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
<button title="Enviar Mensagem" *ngIf="!wsChatMethodsService.getGroupRoom(roomId).message" class="btn-no-color"> <button *ngIf="!wsChatMethodsService.getGroupRoom(roomId).message && lastAudioRecorded" class="btn-no-color" (click)="sendAudio(lastAudioRecorded)">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
@@ -80,6 +80,10 @@
} }
} }
} }
.btn-delete-recording{
margin-left: 20px !important;
}
ion-content{ ion-content{
.welcome-text{ .welcome-text{
/* width: 322px; */ /* width: 322px; */
@@ -33,6 +33,9 @@ import { element } from 'protractor';
import { FileType } from 'src/app/models/fileType'; import { FileType } from 'src/app/models/fileType';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'; import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { VoiceRecorder, VoiceRecorderPlugin, RecordingData, GenericResponse, CurrentRecordingStatus } from 'capacitor-voice-recorder';
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
import { DomSanitizer } from '@angular/platform-browser';
/* /*
import * as pdfjsLib from 'pdfjs-dist'; import * as pdfjsLib from 'pdfjs-dist';
@@ -85,7 +88,16 @@ export class GroupMessagesPage implements OnInit, OnChanges, AfterViewInit, OnDe
pdfurl = "http://www.africau.edu/images/default/sample.pdf"; pdfurl = "http://www.africau.edu/images/default/sample.pdf";
downloadFile: any; downloadFile: any;
showAvatar = false showAvatar = false;
recording = false;
allowTyping = true;
storedFileNames = [];
lastAudioRecorded = '';
audioRecorded:any = "";
audioDownloaded:any = "";
durationDisplay = '';
duration = 0;
constructor( constructor(
public wsChatMethodsService: WsChatMethodsService, public wsChatMethodsService: WsChatMethodsService,
@@ -108,6 +120,7 @@ export class GroupMessagesPage implements OnInit, OnChanges, AfterViewInit, OnDe
private CameraService: CameraService, private CameraService: CameraService,
private toastService: ToastService, private toastService: ToastService,
private sanitiser: DomSanitizer,
) { ) {
console.log('OnCONSTRUCTOR'); console.log('OnCONSTRUCTOR');
@@ -134,6 +147,8 @@ export class GroupMessagesPage implements OnInit, OnChanges, AfterViewInit, OnDe
this.showAvatar = true this.showAvatar = true
}, 50) }, 50)
this.deleteRecording();
} }
ngOnInit() { ngOnInit() {
@@ -146,6 +161,9 @@ export class GroupMessagesPage implements OnInit, OnChanges, AfterViewInit, OnDe
}, 1000); }, 1000);
this.getChatMembers(); this.getChatMembers();
//this.getMessageDB(); //this.getMessageDB();
VoiceRecorder.requestAudioRecordingPermission();
this.deleteRecording();
this.loadFiles();
} }
@@ -229,12 +247,100 @@ export class GroupMessagesPage implements OnInit, OnChanges, AfterViewInit, OnDe
this.currentPosition = scroll; this.currentPosition = scroll;
} }
calculateDuration() {
if (!this.recording) {
this.duration = 0;
this.durationDisplay = '';
return;
}
this.duration += 1;
const minutes = Math.floor(this.duration / 60);
const seconds = (this.duration % 60).toString().padStart(2, '0');
this.durationDisplay = `${minutes}:${seconds}`;
setTimeout(() => {
this.calculateDuration();
}, 1000)
}
async getFile(fileName?:any){
const audioFile = await Filesystem.readFile({
path: fileName,
directory: Directory.Data
})
const base64sound = audioFile.data;
const base64Response = await fetch(`data:audio/ogg;base64,${base64sound}`);
this.audioRecorded = base64Response.url;
}
async loadFiles() {
this.storage.get('fileName').then((fileName) => {
this.lastAudioRecorded = fileName;
})
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
if(recordData.value.recordDataBase64.includes('data:audio')){
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(recordData.value.recordDataBase64);
}
else{
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(`data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`);
}
});
}
startRecording() {
console.log('Recording');
if (this.recording) {
return;
}
this.recording = true;
VoiceRecorder.startRecording();
this.calculateDuration();
}
stopRecording() {
this.deleteRecording();
this.allowTyping = false;
console.log('Stop');
if (!this.recording) {
return;
}
this.recording = false;
VoiceRecorder.stopRecording().then(async (result: RecordingData) => {
console.log(result);
this.recording = false;
if (result.value && result.value.recordDataBase64) {
const recordData = result.value.recordDataBase64;
//console.log(recordData);
const fileName = new Date().getTime() + ".wav";
//Save file
this.storage.set('fileName',fileName);
this.storage.set('recordData',result).then(() => {
console.log('Audio recorded saved');
})
}
})
setTimeout(async () => {
this.loadFiles();
}, 1000);
}
async deleteRecording(){
this.storage.remove('fileName');
this.storage.remove('recordData');
this.allowTyping = true;
this.lastAudioRecorded = '';
this.loadFiles();
}
ngOnDestroy() { ngOnDestroy() {
window.removeEventListener('scroll', this.scrollChangeCallback, true); window.removeEventListener('scroll', this.scrollChangeCallback, true);
} }
async getChatMembers() { async getChatMembers() {
//return await this.chatService.getMembers(roomId).toPromise(); //return await this.chatService.getMembers(roomId).toPromise();
this.chatService.getAllUsers().subscribe(res => { this.chatService.getAllUsers().subscribe(res => {
@@ -311,6 +417,43 @@ export class GroupMessagesPage implements OnInit, OnChanges, AfterViewInit, OnDe
this.wsChatMethodsService.getGroupRoom(this.roomId).send({}) this.wsChatMethodsService.getGroupRoom(this.roomId).send({})
} }
async sendAudio(fileName) {
const roomId = this.roomId
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
if(recordData.value.recordDataBase64.includes('data:audio')){
this.audioRecorded = recordData.value.recordDataBase64;
}
else{
this.audioRecorded = `data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`;
}
});
//Converting base64 to blob
const base64Response = await fetch(this.audioRecorded);
const blob = await base64Response.blob();
const formData = new FormData();
formData.append("blobFile", blob);
this.wsChatMethodsService.getGroupRoom(roomId).send({
file: {
"type": "aplication/audio",
/* "guid": '', */
},
attachments: [{
"title": fileName ,
"title_link": this.audioRecorded,
"title_link_download": true,
"type": "file"
}],
temporaryData: formData
})
this.deleteRecording();
}
deleteMessage(msgId: string) { deleteMessage(msgId: string) {
const room = this.wsChatMethodsService.getGroupRoom(this.roomId) const room = this.wsChatMethodsService.getGroupRoom(this.roomId)
this.alertService.confirmDeleteMessage(msgId, room); this.alertService.confirmDeleteMessage(msgId, room);
@@ -12,7 +12,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import {MatMenuModule} from '@angular/material/menu'; import {MatMenuModule} from '@angular/material/menu';
import { LettersAvatarModule } from "ngx-letters-avatar"; import { LettersAvatarModule } from "ngx-letters-avatar";
import { PdfViewerModule } from 'ng2-pdf-viewer'; import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -24,7 +24,7 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
MatButtonModule, MatButtonModule,
MatMenuModule, MatMenuModule,
LettersAvatarModule, LettersAvatarModule,
PdfViewerModule PipesModule,
], ],
exports: [MessagesPage], exports: [MessagesPage],
+34 -27
View File
@@ -96,7 +96,7 @@
</ion-label> </ion-label>
</div> </div>
<div *ngIf="msg.file.type != 'application/img'"> <div *ngIf="msg.file.type != 'application/img'">
<div class="file"> <div *ngIf="msg.file.type != 'aplication/audio'" class="file add-attachment-bg-color">
<div (click)="openPreview(msg)" class="file-details add-ellipsis cursor-pointer" *ngIf="msg.file"> <div (click)="openPreview(msg)" class="file-details add-ellipsis cursor-pointer" *ngIf="msg.file">
<span *ngIf="msg.file.type"> <span *ngIf="msg.file.type">
<fa-icon *ngIf="msg.file.type == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon> <fa-icon *ngIf="msg.file.type == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon>
@@ -113,11 +113,14 @@
<ion-label class="file-title">{{file.title}}</ion-label> <ion-label class="file-title">{{file.title}}</ion-label>
</div> </div>
</div> </div>
<div class="file-details-optional"> <div class="audio-contentainer" *ngIf="msg.file.type == 'aplication/audio'">
<audio [src]="file.title_link|safehtml" preload="metadata" class="flex-grow-1" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<div class="file-details-optional add-attachment-bg-color">
<ion-label *ngIf="msg.file"> <ion-label *ngIf="msg.file">
<span *ngIf="file.description">{{file.description}}</span> <span *ngIf="file.description">{{file.description}}</span>
<span *ngIf="file.description && msg.file.type != 'application/webtrix'"></span> <span *ngIf="file.description && msg.file.type != 'application/webtrix'"></span>
<span *ngIf="msg.file.type != 'application/webtrix'">{{msg.displayType}}</span> <span *ngIf="msg.file.type != 'application/webtrix' && msg.file.type != 'aplication/audio'">{{msg.displayType}}</span>
</ion-label> </ion-label>
<ion-label class="float-status-all float-status" > <ion-label class="float-status-all float-status" >
@@ -169,14 +172,14 @@
fontFamily="Roboto"></ngx-letters-avatar> fontFamily="Roboto"></ngx-letters-avatar>
está a escrever... está a escrever...
</div> </div>
<div class="width-100 pl-20 pr-20">
<span *ngIf="!lastAudioRecorded">{{durationDisplay}}</span>
<audio [src]="audioRecorded" class="d-flex width-100 mt-10 mb-10" *ngIf="lastAudioRecorded" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<div class="container width-100 d-flex"> <div class="container width-100 d-flex">
<div> <div>
<!-- <button class="btn-no-color" (click)="openSendMessageOptions()"> <ion-fab *ngIf="!recording && !lastAudioRecorded && allowTyping" horizontal="start" vertical="bottom" slot="fixed">
<ion-icon class="chat-icon-options" src="assets/images/icons-add.svg"></ion-icon>
</button> -->
<ion-fab horizontal="start" vertical="bottom" slot="fixed">
<ion-fab-button color="light" size="small"> <ion-fab-button color="light" size="small">
<ion-icon name="add"></ion-icon> <ion-icon name="add"></ion-icon>
</ion-fab-button> </ion-fab-button>
@@ -198,30 +201,34 @@
</ion-fab-button> </ion-fab-button>
</ion-fab-list> </ion-fab-list>
</ion-fab> </ion-fab>
<button *ngIf="recording || lastAudioRecorded || !allowTyping" class="btn-no-color" (click)="deleteRecording()">
<fa-icon class="icon-size-27" icon="trash"></fa-icon>
</button>
</div> </div>
<div class="width-100"> <div class="width-100">
<ion-item class="ion-no-padding type-message" lines="none"> <div *ngIf="!recording && !lastAudioRecorded" class="type-message">
<ion-textarea (keyup.enter)="sendMessage()" clearOnEdit="true" placeholder="Escrever uma mensagem" <ion-textarea *ngIf="allowTyping" (keyup.enter)="sendMessage()" clearOnEdit="true" placeholder="Escrever uma mensagem" class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getDmRoom(roomId).message" (ionChange)="wsChatMethodsService.getDmRoom(roomId).sendTyping()"></ion-textarea>
class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getDmRoom(roomId).message"
(ionChange)="wsChatMethodsService.getDmRoom(roomId).sendTyping()"></ion-textarea>
<button hidden class="btn-no-color">
<ion-icon slot="end" src="assets/icon/icons-chat-mic.svg"></ion-icon>
</button>
</ion-item>
</div> </div>
<div> <div *ngIf="recording" class="d-flex align-items-center justify-content-center">
<button *ngIf="wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color" (click)="sendMessage()"> <button (click)="stopRecording()" class="btn-no-color d-flex align-items-center justify-content-center">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" <ion-icon class="icon-size-45" name="stop-circle-outline" color="danger"></ion-icon>
src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send"
src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
<button *ngIf="!wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color"> </div>
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" </div>
src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" <div>
src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <button #recordbtn *ngIf="!wsChatMethodsService.getDmRoom(roomId).message && !lastAudioRecorded" (click)="startRecording()" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/default/icons-chat-record-audio.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-record-audio.svg"></ion-icon>
</button>
<button *ngIf="wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color" (click)="sendMessage()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button>
<button *ngIf="!wsChatMethodsService.getDmRoom(roomId).message && lastAudioRecorded" class="btn-no-color" (click)="sendAudio(lastAudioRecorded)">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
</div> </div>
</div> </div>
+109 -2
View File
@@ -33,6 +33,9 @@ import { ProcessesService } from 'src/app/services/processes.service';
import { FileToBase64Service } from 'src/app/services/file/file-to-base64.service'; import { FileToBase64Service } from 'src/app/services/file/file-to-base64.service';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'; import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { DocumentViewer, DocumentViewerOptions } from '@ionic-native/document-viewer'; import { DocumentViewer, DocumentViewerOptions } from '@ionic-native/document-viewer';
import { VoiceRecorder, VoiceRecorderPlugin, RecordingData, GenericResponse, CurrentRecordingStatus } from 'capacitor-voice-recorder';
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
import { DomSanitizer } from '@angular/platform-browser';
const IMAGE_DIR = 'stored-images'; const IMAGE_DIR = 'stored-images';
@Component({ @Component({
@@ -77,7 +80,16 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
downloadFile: any; downloadFile: any;
massages: MessageService[] = [] massages: MessageService[] = []
showAvatar = true showAvatar = true;
recording = false;
allowTyping = true;
storedFileNames = [];
lastAudioRecorded = '';
audioRecorded:any = "";
audioDownloaded:any = "";
durationDisplay = '';
duration = 0;
constructor( constructor(
public popoverController: PopoverController, public popoverController: PopoverController,
@@ -106,6 +118,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
private CameraService: CameraService, private CameraService: CameraService,
private processesService: ProcessesService, private processesService: ProcessesService,
private fileToBase64Service: FileToBase64Service, private fileToBase64Service: FileToBase64Service,
private sanitiser: DomSanitizer,
) { ) {
this.loggedUser = authService.ValidatedUserChat['data']; this.loggedUser = authService.ValidatedUserChat['data'];
@@ -129,13 +142,17 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
this.showAvatar = true this.showAvatar = true
}, 150) }, 150)
this.deleteRecording()
} }
ngOnInit() { ngOnInit() {
this.scrollToBottom(); this.scrollToBottom();
this.getChatMembers(); this.getChatMembers();
VoiceRecorder.requestAudioRecordingPermission();
this.deleteRecording();
this.loadFiles();
} }
@@ -208,6 +225,96 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
this.currentPosition = scroll; this.currentPosition = scroll;
} }
calculateDuration() {
if (!this.recording) {
this.duration = 0;
this.durationDisplay = '';
return;
}
this.duration += 1;
const minutes = Math.floor(this.duration / 60);
const seconds = (this.duration % 60).toString().padStart(2, '0');
this.durationDisplay = `${minutes}:${seconds}`;
setTimeout(() => {
this.calculateDuration();
}, 1000)
}
async getFile(fileName?:any){
const audioFile = await Filesystem.readFile({
path: fileName,
directory: Directory.Data
})
const base64sound = audioFile.data;
const base64Response = await fetch(`data:audio/ogg;base64,${base64sound}`);
this.audioRecorded = base64Response.url;
}
async loadFiles() {
this.storage.get('fileName').then((fileName) => {
this.lastAudioRecorded = fileName;
})
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
if(recordData.value.recordDataBase64.includes('data:audio')){
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(recordData.value.recordDataBase64);
}
else{
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(`data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`);
}
});
}
startRecording() {
console.log('Recording');
if (this.recording) {
return;
}
this.recording = true;
VoiceRecorder.startRecording();
this.calculateDuration();
}
stopRecording() {
this.deleteRecording();
this.allowTyping = false;
console.log('Stop');
if (!this.recording) {
return;
}
this.recording = false;
VoiceRecorder.stopRecording().then(async (result: RecordingData) => {
console.log(result);
this.recording = false;
if (result.value && result.value.recordDataBase64) {
const recordData = result.value.recordDataBase64;
//console.log(recordData);
const fileName = new Date().getTime() + ".wav";
//Save file
this.storage.set('fileName',fileName);
this.storage.set('recordData',result).then(() => {
console.log('Audio recorded saved');
})
}
})
setTimeout(async () => {
this.loadFiles();
}, 1000);
}
async deleteRecording(){
this.storage.remove('fileName');
this.storage.remove('recordData');
this.allowTyping = true;
this.lastAudioRecorded = '';
this.loadFiles();
}
ngOnDestroy() { ngOnDestroy() {
this.checktimeOut = false; this.checktimeOut = false;
window.removeEventListener('scroll', this.scrollChangeCallback, true); window.removeEventListener('scroll', this.scrollChangeCallback, true);
Binary file not shown.
@@ -0,0 +1,8 @@
<svg width="45" height="45" viewBox="0 0 45 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.5 45C34.9264 45 45 34.9264 45 22.5C45 10.0736 34.9264 0 22.5 0C10.0736 0 0 10.0736 0 22.5C0 34.9264 10.0736 45 22.5 45Z" fill="#42B9FE"/>
<path d="M27.7273 12.7273C27.7273 9.56419 25.1631 7 22 7C18.8369 7 16.2727 9.56419 16.2727 12.7273V20.9091C16.2727 24.0722 18.8369 26.6364 22 26.6364C25.1631 26.6364 27.7273 24.0722 27.7273 20.9091V12.7273Z" stroke="white" stroke-width="2"/>
<path d="M26.0909 11.9091H24.4545C23.5508 11.9091 22.8182 12.6417 22.8182 13.5455C22.8182 14.4492 23.5508 15.1818 24.4545 15.1818H26.0909C26.9946 15.1818 27.7273 14.4492 27.7273 13.5455C27.7273 12.6417 26.9946 11.9091 26.0909 11.9091Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.1818 29.9091H22.8182V36.4545H21.1818V29.9091Z" fill="white"/>
<path d="M26.9091 36.4545H17.0909C16.639 36.4545 16.2727 36.8209 16.2727 37.2727C16.2727 37.7246 16.639 38.0909 17.0909 38.0909H26.9091C27.3609 38.0909 27.7273 37.7246 27.7273 37.2727C27.7273 36.8209 27.3609 36.4545 26.9091 36.4545Z" fill="white"/>
<path d="M31 19.2727C31 25.3731 28.7778 29.9091 22 29.9091C15.2222 29.9091 13 25.3731 13 19.2727" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,8 @@
<svg width="45" height="45" viewBox="0 0 45 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.5 45C34.9264 45 45 34.9264 45 22.5C45 10.0736 34.9264 0 22.5 0C10.0736 0 0 10.0736 0 22.5C0 34.9264 10.0736 45 22.5 45Z" fill="#FFB81C"/>
<path d="M27.7273 12.7273C27.7273 9.56419 25.1631 7 22 7C18.8369 7 16.2727 9.56419 16.2727 12.7273V20.9091C16.2727 24.0722 18.8369 26.6364 22 26.6364C25.1631 26.6364 27.7273 24.0722 27.7273 20.9091V12.7273Z" stroke="white" stroke-width="2"/>
<path d="M26.0909 11.9091H24.4545C23.5508 11.9091 22.8182 12.6417 22.8182 13.5455C22.8182 14.4492 23.5508 15.1818 24.4545 15.1818H26.0909C26.9946 15.1818 27.7273 14.4492 27.7273 13.5455C27.7273 12.6417 26.9946 11.9091 26.0909 11.9091Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.1818 29.9091H22.8182V36.4545H21.1818V29.9091Z" fill="white"/>
<path d="M26.9091 36.4546H17.0909C16.639 36.4546 16.2727 36.8209 16.2727 37.2727C16.2727 37.7246 16.639 38.0909 17.0909 38.0909H26.9091C27.3609 38.0909 27.7273 37.7246 27.7273 37.2727C27.7273 36.8209 27.3609 36.4546 26.9091 36.4546Z" fill="white"/>
<path d="M31 19.2727C31 25.3731 28.7778 29.9091 22 29.9091C15.2222 29.9091 13 25.3731 13 19.2727" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,4 @@
<svg width="45" height="45" viewBox="0 0 45 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.5 45C34.9264 45 45 34.9264 45 22.5C45 10.0736 34.9264 0 22.5 0C10.0736 0 0 10.0736 0 22.5C0 34.9264 10.0736 45 22.5 45Z" fill="#FFB81C"/>
<path d="M22.25 26.5C24.7358 26.5 26.75 24.4858 26.75 22V14.5C26.75 12.0142 24.7358 10 22.25 10C19.7642 10 17.75 12.0142 17.75 14.5V22C17.75 24.4844 19.7234 26.5 22.25 26.5ZM29.375 19C28.7516 19 28.25 19.5016 28.25 20.0828V22C28.25 25.4373 25.3452 28.2063 21.8609 27.9859C18.7634 27.7905 16.25 24.8645 16.25 21.7609V20.0828C16.25 19.5016 15.7461 19 15.125 19C14.5039 19 14 19.5016 14 20.0828V21.5898C14 25.7927 16.9986 29.5398 21.125 30.107V31.75H19.25C18.3973 31.75 17.7106 32.4616 17.7519 33.3236C17.7702 33.7094 18.1156 34 18.5 34H26C26.3854 34 26.7298 33.7086 26.7481 33.3236C26.7875 32.4625 26.1031 31.75 25.25 31.75H23.375V30.167C27.3922 29.6172 30.5 26.1672 30.5 22V20.0828C30.5 19.5016 29.9984 19 29.375 19Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 986 B

+21 -3
View File
@@ -1138,6 +1138,7 @@ ngx-mat-datetime-content{
.messages{ .messages{
.messages-list-item-wrapper{ .messages-list-item-wrapper{
.message-item{ .message-item{
overflow: auto;
.message-item-options{ .message-item-options{
.message-options-icon{ .message-options-icon{
display: none; display: none;
@@ -1146,6 +1147,11 @@ ngx-mat-datetime-content{
position: absolute !important; position: absolute !important;
} }
} }
.audio-contentainer{
width: 200px !important;
display: flex;
overflow: auto !important;
}
.title{ .title{
//border: 1px solid blue; //border: 1px solid blue;
@@ -1183,15 +1189,20 @@ ngx-mat-datetime-content{
//font-weight: 400; //font-weight: 400;
} }
.add-attachment-bg-color{
background-color: #42b9fe13;
}
.message-attachments{ .message-attachments{
border-radius: 5px; border-radius: 5px;
background-color: #42b9fe13; //background-color: #42b9fe13;
padding: 1px;
.file{ .file{
width: 100%; width: 100%;
align-items: center; align-items: center;
overflow: auto; overflow: auto;
color: #000; color: #000;
//border: 1px solid blue;
padding: 1px;
ion-thumbnail{ ion-thumbnail{
--size: 20px; --size: 20px;
@@ -1199,7 +1210,7 @@ ngx-mat-datetime-content{
.file-details{ .file-details{
max-width: 100%; max-width: 100%;
padding-left: 5px; padding-left: 5px;
padding: 1px;
/* .file-title{ /* .file-title{
padding-left: 5px; padding-left: 5px;
} */ } */
@@ -1238,6 +1249,13 @@ ngx-mat-datetime-content{
.powerpoint-icon{ .powerpoint-icon{
color: #d24726; color: #d24726;
} }
.icon-size-45{
font-size: 45px !important;
}
.icon-size-27{
font-size: 27px !important;
color: #797979;
}
.menu-icon{ .menu-icon{
color: #42b9fe; color: #42b9fe;
padding: 0 5px 0 5px; padding: 0 5px 0 5px;
+19
View File
@@ -0,0 +1,19 @@
{
class AudioPlayer extends HTMLElement{
constructor(){
super()
this.attachShadow({ mode: 'open' });
this.render();
}
render(){
this.shadowRoot.innerHTML = `
<audio *ngIf="audioRecorded" controls src="assets/audio/Audiorecord.mp3"></audio>
`;
}
}
customElements.define('audio-player', AudioPlayer)
}