mirror of
https://code.equilibrium.co.ao/ITO/doneit-web.git
synced 2026-04-18 20:47:54 +00:00
improve
This commit is contained in:
@@ -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>
|
|
||||||
Generated
+41
-76
@@ -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
@@ -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
@@ -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]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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 { }
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { SafehtmlPipe } from './safehtml.pipe';
|
||||||
|
|
||||||
|
describe('SafehtmlPipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new SafehtmlPipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user