This commit is contained in:
Eudes Inácio
2022-03-21 10:45:03 +01:00
50 changed files with 1153 additions and 402 deletions
@@ -1,17 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest package="com.gpr.gabinetedigital" xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:name=".App" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:label="@string/title_activity_main" android:launchMode="singleTask" android:name="com.gpr.gabinetedigital.MainActivity" android:theme="@style/AppTheme.NoActionBarLaunch">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
@@ -16,8 +16,5 @@
"sound" "sound"
] ]
} }
},
"server": {
"url": "http://192.168.1.4:8100"
} }
} }
+93 -107
View File
@@ -799,6 +799,14 @@
"integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==",
"dev": true "dev": true
}, },
"@awesome-cordova-plugins/media-capture": {
"version": "5.40.0",
"resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/media-capture/-/media-capture-5.40.0.tgz",
"integrity": "sha512-Es5qhC6VeCzo0pq0V9txlMwSL3v1ZAUKtT74DDsTnItvbX56ZPdawL4u4fLA40VikaRNYZbYNnkYopifb8nJIw==",
"requires": {
"@types/cordova": "^0.0.34"
}
},
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.14.5", "version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
@@ -2043,13 +2051,13 @@
"resolved": "https://registry.npmjs.org/@capacitor-community/camera-preview/-/camera-preview-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@capacitor-community/camera-preview/-/camera-preview-1.2.1.tgz",
"integrity": "sha512-rskj/12TR4X8cUzvkWvygf7A/4TFUld9BU5nAc1gc3LXU06FGP0R/6MxZKQdf20qqRaTRLPrF3HFAlkz7xb6yg==", "integrity": "sha512-rskj/12TR4X8cUzvkWvygf7A/4TFUld9BU5nAc1gc3LXU06FGP0R/6MxZKQdf20qqRaTRLPrF3HFAlkz7xb6yg==",
"requires": { "requires": {
"@capacitor/core": "^3.3.2" "@capacitor/core": "^3.4.3"
}, },
"dependencies": { "dependencies": {
"@capacitor/core": { "@capacitor/core": {
"version": "3.3.2", "version": "3.4.3",
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-3.3.2.tgz", "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-3.4.3.tgz",
"integrity": "sha512-pyI3dQdQjA1L5iEw0jkeKCogx9t5d5kIFTB5M3CJRg9Uj5MIpU2J5CRj+74A7BflvZJo8IBd6IfMJaOArRumaw==", "integrity": "sha512-drfu0IiDMyeJtL4QALQgNFqdgN19DZJkbKh945eXyK44Sk2YkFXUs7Ewq1ZlVI30QF79mHGuM13oZeki0gv5Tw==",
"requires": { "requires": {
"tslib": "^2.1.0" "tslib": "^2.1.0"
} }
@@ -2194,19 +2202,19 @@
"integrity": "sha512-HCFwOxmK7igEgNm20y+zYi+XQ0OlZYnE4oCaI82TGmA7sehlDpBBKbjmI2Bd8aM09+BXFbAAtq7JCxkEfY8nIg==" "integrity": "sha512-HCFwOxmK7igEgNm20y+zYi+XQ0OlZYnE4oCaI82TGmA7sehlDpBBKbjmI2Bd8aM09+BXFbAAtq7JCxkEfY8nIg=="
}, },
"@capacitor/filesystem": { "@capacitor/filesystem": {
"version": "1.0.6", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-1.0.6.tgz", "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-1.1.0.tgz",
"integrity": "sha512-8xqUbDZFGBMhgqoBSn9wEd9OBPdHIRegQ9zCCZcpHNf3FFAIby1ck+aDFnoq+Da49xhD6ks1SKCBSxz/26qWTw==" "integrity": "sha512-8O3UuvL8HNUEJvZnmn8yUmvgB1evtXfcF0oxIo3YbSlylqywJwS3JTiuhKmsvSxCdpbTy8IaTsutVh3gZgWbKg=="
}, },
"@capacitor/haptics": { "@capacitor/haptics": {
"version": "1.1.3", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-1.1.4.tgz",
"integrity": "sha512-ui2mY/riK1Y4bxnJKJfclWO61obZ0RHmtErPhpmt4wIEVjG1segYdFop45R2PxyEwoUJgzEsAxnviM/T6k8seQ==" "integrity": "sha512-+pJIb5X7xAcbrWj6rJaV+cwBlv8aFwB1/Ob6EV4atydThuuVSSsAL4hI4ZYlPNOxM6H5s+ZDLj7Pa2os4eFmtg=="
}, },
"@capacitor/ios": { "@capacitor/ios": {
"version": "3.3.0", "version": "3.4.1",
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.3.0.tgz", "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.4.1.tgz",
"integrity": "sha512-KImT4hVoQJuAfe01wUYiMLnutMu7PxVCv4c8HVWiW+OuyyOua3lC8wQ5gAauGDugAo6mdM7fVva5a0Vtyhnbdg==" "integrity": "sha512-ycFCyKI8DsgedVg7PW5MpCVgqFuD0PMHQGVfC5ichXc2C/jAATX32EVdEMCB0N3guKoH2k6T3Efwg59+Fcdx2w=="
}, },
"@capacitor/keyboard": { "@capacitor/keyboard": {
"version": "1.1.3", "version": "1.1.3",
@@ -2997,6 +3005,13 @@
"integrity": "sha512-lOrkktadlKYbYf1LrDyAtsu1JnQ0oCCdkOU7iHQ8oXnNOkMwobFfD2m62F1CoOr0u9LIkpYnZSPjng8lZbmbNw==", "integrity": "sha512-lOrkktadlKYbYf1LrDyAtsu1JnQ0oCCdkOU7iHQ8oXnNOkMwobFfD2m62F1CoOr0u9LIkpYnZSPjng8lZbmbNw==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic-native/document-viewer": { "@ionic-native/document-viewer": {
@@ -3050,6 +3065,13 @@
"integrity": "sha512-zm7w8h15H9e210z7ZpfP07OD+9wl2B/0Sz87YJutkVAc1clVop3vElcy4IxGd6vqjMz5Xiw9k9AplbGdMPJIYQ==", "integrity": "sha512-zm7w8h15H9e210z7ZpfP07OD+9wl2B/0Sz87YJutkVAc1clVop3vElcy4IxGd6vqjMz5Xiw9k9AplbGdMPJIYQ==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic-native/fingerprint-aio": { "@ionic-native/fingerprint-aio": {
@@ -3093,6 +3115,13 @@
"integrity": "sha512-tX/FBT0jpkgEefZ8iorv5eDKfgP/ExbYr1AWg6okORQ0dwLfXsD5KDJgKHN9GFZvyuLNeaLpC1mN7CvwvLvmgA==", "integrity": "sha512-tX/FBT0jpkgEefZ8iorv5eDKfgP/ExbYr1AWg6okORQ0dwLfXsD5KDJgKHN9GFZvyuLNeaLpC1mN7CvwvLvmgA==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic-native/ionic-webview": { "@ionic-native/ionic-webview": {
@@ -3151,6 +3180,13 @@
"integrity": "sha512-gpa7cJqodEK+zmmViYJCqEpXoKSXcaYLaaRKdv5gn5M++bpmiw2pKM9JH8VoqYWaYDcUwD3S0yYeBBkG5DE0Kg==", "integrity": "sha512-gpa7cJqodEK+zmmViYJCqEpXoKSXcaYLaaRKdv5gn5M++bpmiw2pKM9JH8VoqYWaYDcUwD3S0yYeBBkG5DE0Kg==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic-native/photo-viewer": { "@ionic-native/photo-viewer": {
@@ -3174,6 +3210,13 @@
"integrity": "sha512-+VILGrCJO76Ta6Mudd6IKc66xDek1uw5OEovFWjGCqkg0OYHFIiJFZNx4NLhF5hA1UKN2fWE6qDJaSXR+1w1Rg==", "integrity": "sha512-+VILGrCJO76Ta6Mudd6IKc66xDek1uw5OEovFWjGCqkg0OYHFIiJFZNx4NLhF5hA1UKN2fWE6qDJaSXR+1w1Rg==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic-native/social-sharing": { "@ionic-native/social-sharing": {
@@ -3197,6 +3240,13 @@
"integrity": "sha512-BfNknY1rrGE8JRnCdKfL5wz8yFLhpPU5FRr8/LA3L+EncvPvcb9LGidePoeH3gVLMkolm2DI2a/rCelNrJ1Sxw==", "integrity": "sha512-BfNknY1rrGE8JRnCdKfL5wz8yFLhpPU5FRr8/LA3L+EncvPvcb9LGidePoeH3gVLMkolm2DI2a/rCelNrJ1Sxw==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic-native/sqlite": { "@ionic-native/sqlite": {
@@ -3205,6 +3255,13 @@
"integrity": "sha512-+1nXUqBucwG6MYoEvqKlZecvI3xVGWeKIzdZf8Nc4vQx4JFDUYdluiEw3mfzptCC1S/4l6skBsL8eZLFfpzUKA==", "integrity": "sha512-+1nXUqBucwG6MYoEvqKlZecvI3xVGWeKIzdZf8Nc4vQx4JFDUYdluiEw3mfzptCC1S/4l6skBsL8eZLFfpzUKA==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic-native/sqlite-porter": { "@ionic-native/sqlite-porter": {
@@ -3218,6 +3275,13 @@
"integrity": "sha512-OXC1z+4Iba4lo1dc2+0h4Gvpud3z0XQmEbw0ny9UflCuSkLqBxvmiNRU7CRQwPnT1KaGVXkaSokdwxO8H9IlNg==", "integrity": "sha512-OXC1z+4Iba4lo1dc2+0h4Gvpud3z0XQmEbw0ny9UflCuSkLqBxvmiNRU7CRQwPnT1KaGVXkaSokdwxO8H9IlNg==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic-native/streaming-media": { "@ionic-native/streaming-media": {
@@ -3241,6 +3305,13 @@
"integrity": "sha512-Ovx2KEfYCbkTsBF+xXYoSTbgebg01PJg9+S/4myCfWhNQecF59qxhjeCUiGA29T38u83nqZuZ4H0Jh9w16w0rA==", "integrity": "sha512-Ovx2KEfYCbkTsBF+xXYoSTbgebg01PJg9+S/4myCfWhNQecF59qxhjeCUiGA29T38u83nqZuZ4H0Jh9w16w0rA==",
"requires": { "requires": {
"@types/cordova": "^0.0.34" "@types/cordova": "^0.0.34"
},
"dependencies": {
"@types/cordova": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ="
}
} }
}, },
"@ionic/angular": { "@ionic/angular": {
@@ -5006,11 +5077,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",
@@ -6171,7 +6237,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",
@@ -6892,9 +6959,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"
} }
@@ -7192,7 +7259,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",
@@ -9463,7 +9531,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",
@@ -16473,26 +16542,6 @@
"tslib": "^2.3.0" "tslib": "^2.3.0"
} }
}, },
"ng2-pdf-viewer": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-3.0.8.tgz",
"integrity": "sha512-p2qndFu1wQW4y+xXXw7yk1BhpRo5PGHKWD3PTc7pUULujx9d2vT26lhXR3p9WHitySadGqdCQpkA7W3v1dBlSg==",
"requires": {
"@types/pdfjs-dist": "^0.1.1",
"pdfjs-dist": "1.9.489"
},
"dependencies": {
"pdfjs-dist": {
"version": "1.9.489",
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.9.489.tgz",
"integrity": "sha1-yuWf7d0WouXRlappUnlVz+QALB0=",
"requires": {
"node-ensure": "^0.0.0",
"worker-loader": "^0.8.0"
}
}
}
},
"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",
@@ -16578,11 +16627,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",
@@ -24792,64 +24836,6 @@
"resolved": "https://registry.npmjs.org/wordcloud/-/wordcloud-1.2.2.tgz", "resolved": "https://registry.npmjs.org/wordcloud/-/wordcloud-1.2.2.tgz",
"integrity": "sha512-fUnDsGrHXou+49j1OeKaC7nOeZPx+sWjIet0L/j6eAcm0nXy+a+AuUs/iDAX4PLBg1Zc6wgXWXhoXdQsXRWAEw==" "integrity": "sha512-fUnDsGrHXou+49j1OeKaC7nOeZPx+sWjIet0L/j6eAcm0nXy+a+AuUs/iDAX4PLBg1Zc6wgXWXhoXdQsXRWAEw=="
}, },
"worker-loader": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-0.8.1.tgz",
"integrity": "sha1-6OmVMx6jTfW/aCloJL+38K1XjUM=",
"requires": {
"loader-utils": "^1.0.2",
"schema-utils": "^0.3.0"
},
"dependencies": {
"ajv": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"requires": {
"co": "^4.6.0",
"fast-deep-equal": "^1.0.0",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.3.0"
}
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
},
"schema-utils": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
"integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
"requires": {
"ajv": "^5.0.0"
}
}
}
},
"wrap-ansi": { "wrap-ansi": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+5 -5
View File
@@ -31,6 +31,7 @@
"@angular/platform-browser": "~12.1.2", "@angular/platform-browser": "~12.1.2",
"@angular/platform-browser-dynamic": "~12.1.2", "@angular/platform-browser-dynamic": "~12.1.2",
"@angular/router": "~12.1.2", "@angular/router": "~12.1.2",
"@awesome-cordova-plugins/media-capture": "^5.40.0",
"@byteowls/capacitor-filesharer": "^3.0.0", "@byteowls/capacitor-filesharer": "^3.0.0",
"@capacitor-community/camera-preview": "^1.2.1", "@capacitor-community/camera-preview": "^1.2.1",
"@capacitor/android": "3.3.3", "@capacitor/android": "3.3.3",
@@ -39,9 +40,9 @@
"@capacitor/camera": "^1.2.0", "@capacitor/camera": "^1.2.0",
"@capacitor/core": "^3.3.2", "@capacitor/core": "^3.3.2",
"@capacitor/device": "^1.1.0", "@capacitor/device": "^1.1.0",
"@capacitor/filesystem": "^1.0.6", "@capacitor/filesystem": "^1.1.0",
"@capacitor/haptics": "^1.1.2", "@capacitor/haptics": "^1.1.4",
"@capacitor/ios": "3.3.0", "@capacitor/ios": "3.4.1",
"@capacitor/keyboard": "^1.1.2", "@capacitor/keyboard": "^1.1.2",
"@capacitor/local-notifications": "^1.1.0", "@capacitor/local-notifications": "^1.1.0",
"@capacitor/network": "^1.0.6", "@capacitor/network": "^1.0.6",
@@ -100,7 +101,7 @@
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"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",
@@ -134,7 +135,6 @@
"lite-server": "^2.6.1", "lite-server": "^2.6.1",
"moment": "^2.29.1", "moment": "^2.29.1",
"ng-lazyload-image": "^9.1.2", "ng-lazyload-image": "^9.1.2",
"ng2-pdf-viewer": "^3.0.8",
"ngx-cookie-service": "^12.0.3", "ngx-cookie-service": "^12.0.3",
"ngx-image-compress": "^11.0.3", "ngx-image-compress": "^11.0.3",
"ngx-image-cropper": "^5.0.1", "ngx-image-cropper": "^5.0.1",
+4 -12
View File
@@ -12,18 +12,15 @@ import { HttpClientModule } from '@angular/common/http';
import { InAppBrowser } from '@ionic-native/in-app-browser/ngx'; import { InAppBrowser } from '@ionic-native/in-app-browser/ngx';
//import { File } from '@ionic-native/File/ngx'; //import { File } from '@ionic-native/File/ngx';
import { WebView } from '@ionic-native/ionic-webview/ngx'; import { WebView } from '@ionic-native/ionic-webview/ngx';
import { FilePath } from '@ionic-native/file-path/ngx'; import { FilePath } from '@ionic-native/file-path/ngx';
import { Camera } from '@ionic-native/camera/ngx'; import { Camera } from '@ionic-native/camera/ngx';
import { IonicStorageModule } from '@ionic/storage'; import { IonicStorageModule } from '@ionic/storage';
//
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CalendarModule, DateAdapter } from 'angular-calendar'; import { CalendarModule, DateAdapter } from 'angular-calendar';
import { adapterFactory } from 'angular-calendar/date-adapters/date-fns'; import { adapterFactory } from 'angular-calendar/date-adapters/date-fns';
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -35,10 +32,6 @@ import {MatDatepickerModule} from '@angular/material/datepicker';
import {MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core'; import {MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core';
import { NgxMatDateFormats, NGX_MAT_DATE_FORMATS } from '@angular-material-components/datetime-picker'; import { NgxMatDateFormats, NGX_MAT_DATE_FORMATS } from '@angular-material-components/datetime-picker';
import { Network } from '@ionic-native/network/ngx'; import { Network } from '@ionic-native/network/ngx';
import { File } from '@ionic-native/file/ngx';
import { import {
NgxMatDatetimePickerModule, NgxMatDatetimePickerModule,
NgxMatNativeDateModule, NgxMatNativeDateModule,
@@ -56,13 +49,14 @@ import { far } from '@fortawesome/free-regular-svg-icons'
import { fab } from '@fortawesome/free-brands-svg-icons' import { fab } from '@fortawesome/free-brands-svg-icons'
import { ScreenOrientation } from '@ionic-native/screen-orientation/ngx'; import { ScreenOrientation } from '@ionic-native/screen-orientation/ngx';
import { PdfViewerModule } from 'ng2-pdf-viewer';
import { SQLite } from '@ionic-native/sqlite/ngx'; import { SQLite } from '@ionic-native/sqlite/ngx';
import { CookieService } from 'ngx-cookie-service'; import { CookieService } from 'ngx-cookie-service';
import { ImagePicker } from '@ionic-native/image-picker/ngx'; import { ImagePicker } from '@ionic-native/image-picker/ngx';
import { MediaCapture } from '@ionic-native/media-capture/ngx'; import { MediaCapture } from '@ionic-native/media-capture/ngx';
import { Media } from '@ionic-native/media/ngx'; import { Media } from '@ionic-native/media/ngx';
import { File } from '@ionic-native/file/ngx';
import { StreamingMedia } from '@ionic-native/streaming-media/ngx'; import { StreamingMedia } from '@ionic-native/streaming-media/ngx';
import { PhotoViewer } from '@ionic-native/photo-viewer/ngx'; import { PhotoViewer } from '@ionic-native/photo-viewer/ngx';
import {NgxImageCompressService} from 'ngx-image-compress'; import {NgxImageCompressService} from 'ngx-image-compress';
@@ -111,10 +105,8 @@ import { FirebaseX } from '@ionic-native/firebase-x/ngx'; */
MatSelectModule, MatSelectModule,
MatDialogModule, MatDialogModule,
// //
PdfViewerModule,
HammerModule, HammerModule,
CustomImageCachePageRoutingModule CustomImageCachePageRoutingModule,
], ],
providers: [ providers: [
@@ -126,7 +118,7 @@ import { FirebaseX } from '@ionic-native/firebase-x/ngx'; */
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
InAppBrowser, InAppBrowser,
Camera, Camera,
//File, File,
WebView, WebView,
FilePath, FilePath,
/* FCM, /* FCM,
@@ -7,7 +7,6 @@ import { IonicModule } from '@ionic/angular';
import { DocumentViewerPageRoutingModule } from './document-viewer-routing.module'; import { DocumentViewerPageRoutingModule } from './document-viewer-routing.module';
import { DocumentViewerPage } from './document-viewer.page'; import { DocumentViewerPage } from './document-viewer.page';
import { PdfViewerModule } from 'ng2-pdf-viewer';
@NgModule({ @NgModule({
@@ -17,7 +16,6 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
IonicModule, IonicModule,
DocumentViewerPageRoutingModule, DocumentViewerPageRoutingModule,
// //
PdfViewerModule
], ],
declarations: [DocumentViewerPage] declarations: [DocumentViewerPage]
}) })
@@ -1,9 +1,25 @@
<ion-content class=" bg-blue"> <ion-content class=" bg-blue">
<div class="main-content width-100 overflow-y-auto height-100"> <div class="main-content width-100 overflow-y-auto height-100">
<div class="profile-header width-100"> <div class="profile-header width-100">
<div class="div-logo d-md-none"> <div class="div-logo d-md-none width-40">
<div class="logo height-fit-content"> <div class="logo-icon">
<img class="img" src='assets/images/logo-no-bg.png' alt='logo'> <img *ngIf="ThemeService.currentTheme == 'default' " src='assets/images/logo-no-bg.png' alt='logo'>
<img *ngIf="ThemeService.currentTheme == 'gov' " src='assets/images/theme/gov/governoangola_A.png' alt='logo'>
<img *ngIf="ThemeService.currentTheme == 'tribunal' " src='assets/images/theme/tribunal/tribunal-constitucional.png' alt='logo'>
</div>
<div *ngIf="ThemeService.currentTheme == 'gov'" class="logo-description d-flex align-center justify-content-center">
<div class="logo-description-content">
<p class="logo-description-text">Presidente da República</p>
<div class="add-line"></div>
<p class="logo-description-text tp-5">GABINETE DIGITAL</p>
</div>
</div>
<div *ngIf="ThemeService.currentTheme == 'default'" class="logo-description d-flex align-center justify-content-center">
<div class="logo-description-content">
<p class="logo-description-text color-white">Presidente da República</p>
<div class="add-line-white"></div>
<p class="logo-description-text tp-5 color-white">GABINETE DIGITAL</p>
</div>
</div> </div>
</div> </div>
<div class="btn-close d-flex cursor-pointer" (click)="close()"> <div class="btn-close d-flex cursor-pointer" (click)="close()">
@@ -10,18 +10,68 @@
.div-logo{ .div-logo{
background: transparent; background: transparent;
width: calc(100% - 40px) !important; width: em(140px);
justify-content: center; justify-content: center;
display: flex; display: flex;
color: black;
overflow: auto;
float: left; float: left;
.logo{ .logo-icon{
width: 140px; width: 25.33%;
.img{ overflow: auto;
img{
width: 100%; width: 100%;
margin: 0px auto; margin: 0px auto;
} }
} }
.logo-description{
width: 74.67%;
margin: 0 auto;
overflow: auto;
font-size: 8.5px;
font-family: Bahnschrift;
.logo-description-content{
width: 100%;
.logo-description-text{
font-weight: 700;
text-align: center;
width: 100%;
margin: 0 !important;
padding: 0 !important;
}
.add-line{
width: 100%;
border-bottom: 1px solid #000;
margin-bottom: 2.5px !important;
padding: 0 !important;
}
.add-line-white{
width: 100%;
border-bottom: 1px solid #fff;
margin-bottom: 2.5px !important;
padding: 0 !important;
}
}
.color-white{
color: #fff !important;
}
.add-botton-border{
border-bottom: 1px solid #000;
}
.add-botton-border-white{
border-bottom: 1px solid #fff;
}
}
} }
} }
.btn-close{ .btn-close{
+19 -3
View File
@@ -1,8 +1,24 @@
<ion-header class=" bg-blue ion-no-border"> <ion-header class=" bg-blue ion-no-border">
<div class="profile-header width-100"> <div class="profile-header width-100">
<div class="div-logo d-md-none"> <div class="div-logo d-md-none width-40">
<div class="logo height-fit-content"> <div class="logo-icon">
<img class="img" src='assets/images/logo-no-bg.png' alt='logo'> <img *ngIf="ThemeService.currentTheme == 'default' " src='assets/images/logo-no-bg.png' alt='logo'>
<img *ngIf="ThemeService.currentTheme == 'gov' " src='assets/images/theme/gov/governoangola_A.png' alt='logo'>
<img *ngIf="ThemeService.currentTheme == 'tribunal' " src='assets/images/theme/tribunal/tribunal-constitucional.png' alt='logo'>
</div>
<div *ngIf="ThemeService.currentTheme == 'gov'" class="logo-description d-flex align-center justify-content-center">
<div class="logo-description-content">
<p class="logo-description-text">Presidente da República</p>
<div class="add-line"></div>
<p class="logo-description-text tp-5">GABINETE DIGITAL</p>
</div>
</div>
<div *ngIf="ThemeService.currentTheme == 'default'" class="logo-description d-flex align-center justify-content-center">
<div class="logo-description-content">
<p class="logo-description-text color-white">Presidente da República</p>
<div class="add-line-white"></div>
<p class="logo-description-text tp-5 color-white">GABINETE DIGITAL</p>
</div>
</div> </div>
</div> </div>
<div class="btn-close d-flex cursor-pointer" (click)="close()"> <div class="btn-close d-flex cursor-pointer" (click)="close()">
+55 -5
View File
@@ -4,20 +4,70 @@
padding: 20px 20px; padding: 20px 20px;
border: 0 !important; border: 0 !important;
.div-logo { .div-logo{
background: transparent; background: transparent;
width: calc(100% - 40px) !important; width: em(140px);
justify-content: center; justify-content: center;
display: flex; display: flex;
color: black;
overflow: auto;
float: left; float: left;
.logo { .logo-icon{
width: 140px; width: 25.33%;
.img { overflow: auto;
img{
width: 100%; width: 100%;
margin: 0px auto; margin: 0px auto;
} }
} }
.logo-description{
width: 74.67%;
margin: 0 auto;
overflow: auto;
font-size: 8.5px;
font-family: Bahnschrift;
.logo-description-content{
width: 100%;
.logo-description-text{
font-weight: 700;
text-align: center;
width: 100%;
margin: 0 !important;
padding: 0 !important;
}
.add-line{
width: 100%;
border-bottom: 1px solid #000;
margin-bottom: 2.5px !important;
padding: 0 !important;
}
.add-line-white{
width: 100%;
border-bottom: 1px solid #fff;
margin-bottom: 2.5px !important;
padding: 0 !important;
}
}
.color-white{
color: #fff !important;
}
.add-botton-border{
border-bottom: 1px solid #000;
}
.add-botton-border-white{
border-bottom: 1px solid #fff;
}
}
} }
} }
.btn-close { .btn-close {
@@ -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>
+10 -8
View File
@@ -75,10 +75,12 @@
</ion-label> --> </ion-label> -->
<div *ngIf="room.lastMessage.file"> <div *ngIf="room.lastMessage.file">
<fa-icon *ngIf="room.lastMessage.file.type != 'application/meeting' && room.lastMessage.file.type != 'application/img'" icon="file-alt" class="file-icon" [class.set-active-item-font-to-white]="room.id == idSelected"></fa-icon> <fa-icon *ngIf="room.lastMessage.file.type != 'application/meeting' && room.lastMessage.file.type != 'application/img' && room.lastMessage.file.type != 'application/audio'" icon="file-alt" class="file-icon" [class.set-active-item-font-to-white]="room.id == idSelected"></fa-icon>
<fa-icon *ngIf="room.lastMessage.file.type == 'application/audio'" icon="file-audio" class="file-icon" [class.set-active-item-font-to-white]="room.id == idSelected"></fa-icon>
<span *ngIf="room.lastMessage.file.type == 'application/audio'"> audio </span>
<fa-icon *ngIf="room.lastMessage.file.type == 'application/meeting'" icon="calendar-alt" class="file-icon" [class.set-active-item-font-to-white]="room.id == idSelected"></fa-icon> <fa-icon *ngIf="room.lastMessage.file.type == 'application/meeting'" icon="calendar-alt" class="file-icon" [class.set-active-item-font-to-white]="room.id == idSelected"></fa-icon>
<span> {{room.lastMessage.file.name || room.lastMessage.file.subject }}</span> <span> {{room.lastMessage.file.name || room.lastMessage.file.subject}}</span>
</div> </div>
<ion-label *ngIf="room.lastMessage.attachments"> <ion-label *ngIf="room.lastMessage.attachments">
@@ -120,8 +122,7 @@
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' && group.id != idSelected " class="icon" slot="start" src="assets/images/theme/gov/icons-chat-group-chat-40.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' && group.id != idSelected " class="icon" slot="start" src="assets/images/theme/gov/icons-chat-group-chat-40.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' && group.id == idSelected " class="icon" slot="start" src="assets/images/theme/gov/icons-chat-group-chat-40-hover.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' && group.id == idSelected " class="icon" slot="start" src="assets/images/theme/gov/icons-chat-group-chat-40-hover.svg"></ion-icon>
</div> </div>
<div <div (click)="openGroupMessagesPage(group.id)" class="item-content flex-grow-1 cursor-pointer">
(click)="openGroupMessagesPage(group.id)" class="item-content flex-grow-1 cursor-pointer">
<div class="item-title-time"> <div class="item-title-time">
<div class="item-title" [class.item-title-active]="group.id ==idSelected"> <div class="item-title" [class.item-title-active]="group.id ==idSelected">
<ion-label>{{group.name.split('-').join(' ')}}</ion-label> <ion-label>{{group.name.split('-').join(' ')}}</ion-label>
@@ -132,11 +133,12 @@
<div *ngIf="group.lastMessage" class="item-description d-flex align-items-center" [class.item-description-active]="group.id ==idSelected"> <div *ngIf="group.lastMessage" class="item-description d-flex align-items-center" [class.item-description-active]="group.id ==idSelected">
<div class="item-message" *ngIf="group.otherUserType == false">{{group.lastMessage.u.name}}: {{group.lastMessage.msg}} </div> <div class="item-message" *ngIf="group.otherUserType == false">{{group.lastMessage.u.name}}: {{group.lastMessage.msg}} </div>
<div *ngIf="group.otherUserType == true">{{group.userThatIsTyping}} está escrever ...</div> <div *ngIf="group.otherUserType == true">{{group.userThatIsTyping}} está escrever ...</div>
<div class="item-files add-ellipsis" *ngIf="group.lastMessage.file">
<div class="item-files add-ellipsis" *ngIf="group.file"> <fa-icon *ngIf="group.lastMessage.file.type != 'application/meeting' && group.lastMessage.file.type != 'application/audio'" icon="file-alt" class="file-icon" [class.set-active-item-font-to-white]="group.id == idSelected"></fa-icon>
<fa-icon *ngIf="group.lastMessage.file.type != 'application/meeting'" icon="file-alt" class="file-icon" [class.set-active-item-font-to-white]="group.id == idSelected"></fa-icon> <fa-icon *ngIf="group.lastMessage.file.type == 'application/audio'" icon="file-audio" class="file-icon" [class.set-active-item-font-to-white]="group.id == idSelected"></fa-icon>
<span *ngIf="group.lastMessage.file.type == 'application/audio'" class="item-files-title"> audio </span>
<fa-icon *ngIf="group.lastMessage.file.type == 'application/meeting'" icon="calendar-alt" class="file-icon" [class.set-active-item-font-to-white]="group.id == idSelected"></fa-icon> <fa-icon *ngIf="group.lastMessage.file.type == 'application/meeting'" icon="calendar-alt" class="file-icon" [class.set-active-item-font-to-white]="group.id == idSelected"></fa-icon>
<span class="item-files-title"> {{group.lastMessage.file.name || group.file.subject}}</span> <span *ngIf="group.lastMessage.file.type != 'application/audio'" class="item-files-title"> {{ group.lastMessage.attachments[0].title }}</span>
</div> </div>
<div class="item-files" *ngIf="group.attachments"> <div class="item-files" *ngIf="group.attachments">
<div *ngIf="group.value.lastMessage.attachments[0].image_url"> <div *ngIf="group.value.lastMessage.attachments[0].image_url">
@@ -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 != 'application/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 == 'application/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 != 'application/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() + ".mp3";
//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": "application/audio",
/* "guid": '', */
},
attachments: [{
"title": fileName ,
"title_link": this.audioRecorded,
"title_link_download": true,
"type": "file"
}],
temporaryData: formData
})
this.deleteRecording();
}
async openOptions() { async openOptions() {
const modal = await this.popoverController.create({ const modal = await this.popoverController.create({
component: ChatPopoverPage, component: ChatPopoverPage,
@@ -12,6 +12,7 @@ import { BtnModalDismissPage } from 'src/app/shared/btn-modal-dismiss/btn-modal-
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { MatMenuModule } from '@angular/material/menu'; import { MatMenuModule } from '@angular/material/menu';
import { LettersAvatarModule } from "ngx-letters-avatar"; import { LettersAvatarModule } from "ngx-letters-avatar";
import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -21,7 +22,8 @@ import { LettersAvatarModule } from "ngx-letters-avatar";
FontAwesomeModule, FontAwesomeModule,
MessagesPageRoutingModule, MessagesPageRoutingModule,
MatMenuModule, MatMenuModule,
LettersAvatarModule LettersAvatarModule,
PipesModule,
], ],
declarations: [MessagesPage] declarations: [MessagesPage]
}) })
+30 -29
View File
@@ -87,8 +87,8 @@
<ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon> <ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon>
</div> </div>
<div *ngIf="msg.file.type != 'application/img'"> <div *ngIf="msg.file.type != 'application/img'">
<div class="file"> <div class="file add-attachment-bg-color" *ngIf="msg.file.type != 'application/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 == 'application/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 != 'application/audio'">{{msg.displayType}}</span>
</ion-label> </ion-label>
</div> </div>
</div> </div>
@@ -173,43 +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 hidden>
<ion-item (click)="playFile(storedFileNames)">
{{storedFileNames}}
</ion-item>
<ion-item (click)="playFile(storedFileNames)">
{{storedFileNames}}
</ion-item>
</ion-list>
<audio hidden 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 *ngIf="!recording && !lastAudioRecorded && allowTyping" class="btn-no-color" (click)="openChatOptions()">
<button class="btn-no-color" (click)="openChatOptions()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-options" src="assets/images/icons-add.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-options" src="assets/images/icons-add.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-options" src="assets/images/theme/gov/icons-add.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-options" src="assets/images/theme/gov/icons-add.svg"></ion-icon>
</button> </button>
</div> <button *ngIf="recording || lastAudioRecorded || !allowTyping" class="btn-no-color" (click)="deleteRecording()">
<div class="width-70"> <fa-icon class="icon-size-27" icon="trash"></fa-icon>
<ion-item class="ion-no-padding ion-no-margin type-message" lines="none">
<ion-textarea autocomplete="on" autocorrect="on" spellcheck="true" *ngIf="!recording" clearOnEdit="true" placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getDmRoom(roomId).message" (ionChange)="wsChatMethodsService.getDmRoom(roomId).sendTyping()"></ion-textarea>
<ion-textarea autocomplete="on" spellcheck="true" *ngIf="recording" clearOnEdit="true" placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1" [(ngModel)]="durationDisplay"></ion-textarea>
<button hidden #recordbtn class="btn-no-color" (click)="notImplemented()">
<ion-icon slot="end" src="assets/icon/icons-chat-mic.svg"></ion-icon>
</button> </button>
</ion-item> </div>
<div class="width-70 message-container">
<div *ngIf="!recording && !lastAudioRecorded" class="type-message">
<ion-textarea *ngIf="allowTyping" autocomplete="on" autocorrect="on" spellcheck="true" clearOnEdit="true" placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1" [(ngModel)]="wsChatMethodsService.getDmRoom(roomId).message" (ionChange)="wsChatMethodsService.getDmRoom(roomId).sendTyping()"></ion-textarea>
</div>
<div *ngIf="recording" class="d-flex align-items-center justify-content-center">
<button (click)="stopRecording()" class="btn-no-color d-flex align-items-center justify-content-center">
<ion-icon class="icon-size-45" name="stop-circle-outline" color="danger"></ion-icon>
</button>
</div>
</div> </div>
<div> <div>
<button *ngIf="wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color" (click)="sendMessage()"> <button #recordbtn *ngIf="!wsChatMethodsService.getDmRoom(roomId).message && !lastAudioRecorded" (click)="startRecording()" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/default/icons-chat-record-audio.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-record-audio.svg"></ion-icon>
</button>
<button *ngIf="wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color" (click)="sendMessage()" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
<button *ngIf="!wsChatMethodsService.getDmRoom(roomId).message" class="btn-no-color"> <button *ngIf="!wsChatMethodsService.getDmRoom(roomId).message && lastAudioRecorded" (click)="sendAudio(lastAudioRecorded)" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon> <ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button> </button>
+13 -5
View File
@@ -56,9 +56,6 @@
width: calc(100% - 25px); width: calc(100% - 25px);
text-align: right; text-align: right;
/* ion-icon{
font-size: 25px;
} */
.middle-container-options-icons{ .middle-container-options-icons{
color: #0782c9; color: #0782c9;
font-size: 23px; font-size: 23px;
@@ -117,6 +114,7 @@
} }
} }
} }
ion-content{ ion-content{
.welcome-text{ .welcome-text{
/* width: 322px; */ /* width: 322px; */
@@ -148,7 +146,7 @@
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
.messages-list-item-wrapper{ .messages-list-item-wrapper{
overflow: auto; overflow: hidden;
} }
.messages-list-item-wrapper-active{ .messages-list-item-wrapper-active{
background: #e6f6ff75 !important; background: #e6f6ff75 !important;
@@ -228,7 +226,6 @@
justify-content: center; justify-content: center;
justify-content: space-evenly; justify-content: space-evenly;
align-items: center; align-items: center;
} }
.chat-icon-options{ .chat-icon-options{
@@ -320,3 +317,14 @@ display: block;
.typing ngx-letters-avatar { .typing ngx-letters-avatar {
padding-right: 5px; padding-right: 5px;
} }
button{
padding: 0px;
border: 0px;
}
button::-moz-focus-inner {
padding: 0px;
border: 0px;
}
+114 -52
View File
@@ -20,7 +20,7 @@ import { ChatUserStorage } from 'src/app/store/chat/chat-user.service';
import { environment } from 'src/environments/environment'; import { environment } from 'src/environments/environment';
import { ThemeService } from 'src/app/services/theme.service' import { ThemeService } from 'src/app/services/theme.service'
import { Directory, Encoding, FilesystemDirectory } from '@capacitor/filesystem'; import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
import { VoiceRecorder, VoiceRecorderPlugin, RecordingData, GenericResponse, CurrentRecordingStatus } from 'capacitor-voice-recorder'; import { VoiceRecorder, VoiceRecorderPlugin, RecordingData, GenericResponse, CurrentRecordingStatus } from 'capacitor-voice-recorder';
import { Haptics, ImpactStyle } from '@capacitor/haptics'; import { Haptics, ImpactStyle } from '@capacitor/haptics';
import { PreviewCameraPage } from 'src/app/modals/preview-camera/preview-camera.page'; import { PreviewCameraPage } from 'src/app/modals/preview-camera/preview-camera.page';
@@ -40,13 +40,10 @@ import { SearchPage } from 'src/app/pages/search/search.page';
import { Storage } from '@ionic/storage'; import { Storage } from '@ionic/storage';
import { FileToBase64Service } from 'src/app/services/file/file-to-base64.service'; import { FileToBase64Service } from 'src/app/services/file/file-to-base64.service';
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'; import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { Plugins } from '@capacitor/core'; import { DomSanitizer } from '@angular/platform-browser';
import { fromByteArray } from 'base64-js'; /* import {Plugins} from '@capacitor/core';
const { Filesystem } = Plugins; const { Filesystem } = Plugins; */
const IMAGE_DIR = 'stored-images';
@Component({ @Component({
selector: 'app-messages', selector: 'app-messages',
@@ -87,7 +84,11 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
LoadedDocument: any = null; LoadedDocument: any = null;
recording = false; recording = false;
allowTyping = true;
storedFileNames = []; storedFileNames = [];
lastAudioRecorded = '';
audioRecorded:any = "";
audioDownloaded:any = "";
durationDisplay = ''; durationDisplay = '';
duration = 0; duration = 0;
@ViewChild('recordbtn', { read: ElementRef }) recordBtn: ElementRef; @ViewChild('recordbtn', { read: ElementRef }) recordBtn: ElementRef;
@@ -120,6 +121,7 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
private processesService: ProcessesService, private processesService: ProcessesService,
private storage: Storage, private storage: Storage,
private fileToBase64Service: FileToBase64Service, private fileToBase64Service: FileToBase64Service,
private sanitiser: DomSanitizer,
) { ) {
this.loggedUser = authService.ValidatedUserChat['data']; this.loggedUser = authService.ValidatedUserChat['data'];
this.roomId = this.navParams.get('roomId'); this.roomId = this.navParams.get('roomId');
@@ -131,6 +133,8 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
} }
}; };
console.log(this.wsChatMethodsService.getDmRoom(this.roomId).loadHistory({}));
this.wsChatMethodsService.getDmRoom(this.roomId).loadHistory({}) this.wsChatMethodsService.getDmRoom(this.roomId).loadHistory({})
this.wsChatMethodsService.getDmRoom(this.roomId).scrollDown = this.scrollToBottomClicked this.wsChatMethodsService.getDmRoom(this.roomId).scrollDown = this.scrollToBottomClicked
this.wsChatMethodsService.openRoom(this.roomId) this.wsChatMethodsService.openRoom(this.roomId)
@@ -145,15 +149,14 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
this.wsChatMethodsService.getUserOfRoom(this.roomId).then((value) => { this.wsChatMethodsService.getUserOfRoom(this.roomId).then((value) => {
console.log('MEMBER', value) console.log('MEMBER', value)
}) })
//this.loadFiles(); //this.loadFiles();
VoiceRecorder.requestAudioRecordingPermission(); VoiceRecorder.requestAudioRecordingPermission();
this.getChatMembers(); this.getChatMembers();
Filesystem.mkdir({ /* Filesystem.mkdir({
path: IMAGE_DIR, path: IMAGE_DIR,
directory: Directory.Data, directory: Directory.Data,
recursive: true recursive: true
}); }); */
} }
ngAfterViewInit() { ngAfterViewInit() {
@@ -167,11 +170,14 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
onStart: ev => { onStart: ev => {
Haptics.impact({ style: ImpactStyle.Light }) Haptics.impact({ style: ImpactStyle.Light })
this.startRecording(); this.startRecording();
this.calculateDuration(); //this.calculateDuration();
}, },
onEnd: ev => { onEnd: ev => {
Haptics.impact({ style: ImpactStyle.Light }) Haptics.impact({ style: ImpactStyle.Light })
this.stopRecording(); this.stopRecording();
/* setTimeout(() => {
this.loadFiles();
}, 500); */
} }
}, true); }, true);
longpress.enable(); longpress.enable();
@@ -194,61 +200,73 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
} }
async loadFiles() { async loadFiles() {
Filesystem.readdir({
path: '', this.storage.get('fileName').then((fileName) => {
directory: Directory.Data this.lastAudioRecorded = fileName;
}).then(result => {
console.log(result);
const temp: any[] = result.files.reverse();
this.storedFileNames = temp[0];
console.log(this.storedFileNames);
}) })
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
if(recordData.value.recordDataBase64.includes('data:audio')){
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(recordData.value.recordDataBase64);
}
else{
this.audioRecorded = this.sanitiser.bypassSecurityTrustResourceUrl(`data:${recordData.value.mimeType};base64,${recordData.value.recordDataBase64}`);
}
});
} }
startRecording() { startRecording() {
console.log('Recording');
if (this.recording) { if (this.recording) {
return; return;
} }
this.recording = true; this.recording = true;
VoiceRecorder.startRecording(); VoiceRecorder.startRecording()
.then((result: GenericResponse) => console.log(result.value))
.catch(error => console.log(error));
this.calculateDuration();
} }
stopRecording() { stopRecording() {
this.deleteRecording();
this.allowTyping = false;
console.log('Stop');
if (!this.recording) { if (!this.recording) {
return; return;
} }
this.recording = false; this.recording = false;
VoiceRecorder.stopRecording().then(async (result: RecordingData) => { VoiceRecorder.stopRecording().then(async (result: RecordingData) => {
console.log(result);
this.recording = false; this.recording = false;
if (result.value && result.value.recordDataBase64) { if (result.value && result.value.recordDataBase64) {
const recordData = result.value.recordDataBase64; const recordData = result.value.recordDataBase64;
console.log(recordData); //console.log(recordData);
this.myAudio = recordData; const fileName = new Date().getTime() + ".mp3";
const fileName = new Date().getTime() + ".wav"; //Save file
await Filesystem.writeFile({ this.storage.set('fileName',fileName);
path: fileName, this.storage.set('recordData',result).then(() => {
directory: Directory.Data, console.log('Audio recorded saved');
data: recordData,
}) })
} }
}) })
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": "application/audio",
/* "guid": '', */
},
attachments: [{
"title": fileName ,
"title_link": this.audioRecorded,
"title_link_download": true,
"type": "file"
}],
temporaryData: formData
})
this.deleteRecording();
}
blobToBase64 = blob => {
const reader = new FileReader();
reader.readAsDataURL(blob);
return new Promise(resolve => {
reader.onloadend = () => {
resolve(reader.result);
};
});
};
viewDocument(msg: any, url?: string) { viewDocument(msg: any, url?: string) {
console.log(msg) console.log(msg)
if (msg.attachments.type == "application/webtrix") { if (msg.attachments.type == "application/webtrix") {
@@ -396,6 +451,13 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
} }
} }
/* playSound(url?:any){
alert('here')
console.log(url);
//this.audioDownloaded = this.sanitiser.bypassSecurityTrustResourceUrl(url);
this.audioDownloaded = url;
} */
docIndex(index: number) { docIndex(index: number) {
this.dicIndex = index this.dicIndex = index
} }
-2
View File
@@ -5,7 +5,6 @@ import { IonicModule } from '@ionic/angular';
import { EventsPageRoutingModule } from './events-routing.module'; import { EventsPageRoutingModule } from './events-routing.module';
import { EventsPage } from './events.page'; import { EventsPage } from './events.page';
import { HeaderPageModule } from 'src/app/shared/header/header.module'; import { HeaderPageModule } from 'src/app/shared/header/header.module';
import { PdfViewerModule } from 'ng2-pdf-viewer';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -15,7 +14,6 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
EventsPageRoutingModule, EventsPageRoutingModule,
HeaderPageModule, HeaderPageModule,
// //
PdfViewerModule
], ],
declarations: [EventsPage], declarations: [EventsPage],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
+3 -2
View File
@@ -6,11 +6,12 @@ import { EventPipe } from './event.pipe';
import { PublicationPipe } from './publication.pipe'; import { PublicationPipe } from './publication.pipe';
import { ExpedienteTaskPipe } from './expediente-task.pipe'; import { ExpedienteTaskPipe } from './expediente-task.pipe';
import { ParticipantsPipe } from './participants.pipe'; import { ParticipantsPipe } from './participants.pipe';
import { SafehtmlPipe } from './safehtml.pipe';
@NgModule({ @NgModule({
declarations: [FilterPipe, SearchDocumentPipe, CustomTaskPipe, EventPipe, PublicationPipe, ExpedienteTaskPipe, ParticipantsPipe], declarations: [FilterPipe, SearchDocumentPipe, CustomTaskPipe, EventPipe, PublicationPipe, ExpedienteTaskPipe, ParticipantsPipe, SafehtmlPipe],
exports: [FilterPipe], exports: [FilterPipe, SafehtmlPipe],
imports: [] imports: []
}) })
export class PipesModule { } export class PipesModule { }
+8
View File
@@ -0,0 +1,8 @@
import { SafehtmlPipe } from './safehtml.pipe';
describe('SafehtmlPipe', () => {
it('create an instance', () => {
const pipe = new SafehtmlPipe();
expect(pipe).toBeTruthy();
});
});
+14
View File
@@ -0,0 +1,14 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'safehtml'
})
export class SafehtmlPipe implements PipeTransform {
constructor(private sanitiser: DomSanitizer){}
transform(html): unknown {
return this.sanitiser.bypassSecurityTrustResourceUrl(html);
}
}
+2
View File
@@ -167,6 +167,8 @@ export class AuthService {
message.file.guid = guid.path message.file.guid = guid.path
await this.storage.set(guid.path, message.file.image_url).then(() => { await this.storage.set(guid.path, message.file.image_url).then(() => {
console.log('add picture to chat IMAGE SAVED') console.log('add picture to chat IMAGE SAVED')
console.log(message.attachments);
message.getFileFromDb() message.getFileFromDb()
}); });
+3 -1
View File
@@ -122,6 +122,8 @@ export class RoomService {
setTimeout(()=>{ setTimeout(()=>{
this.scrollDown() this.scrollDown()
}, 50) }, 50)
//Sort list of messages from recent to old
this.sortRoomList()
} }
@@ -515,7 +517,7 @@ export class RoomService {
const found = this.messages.find((MessageService) => { const found = this.messages.find((MessageService) => {
if (MessageService._id == message._id) { if (MessageService._id == message._id) {
if(this.hasLoadHistory) console.log(`${MessageService._id} == ${message._id}`) if(this.hasLoadHistory) /* console.log(`${MessageService._id} == ${message._id}`) */
return true return true
} else { } else {
return false return false
@@ -199,6 +199,7 @@ export class WsChatMethodsService {
* @description sort room list by last message date * @description sort room list by last message date
*/ */
sortRoomList =() => { sortRoomList =() => {
this._dm = this.sortService.sortDate(this._dm,'_updatedAt').reverse() this._dm = this.sortService.sortDate(this._dm,'_updatedAt').reverse()
this._group = this.sortService.sortDate(this._group,'_updatedAt').reverse() this._group = this.sortService.sortDate(this._group,'_updatedAt').reverse()
} }
@@ -252,6 +253,16 @@ export class WsChatMethodsService {
}) })
} }
private fix_updatedAt(message) {
if (message.result) {
message.result._updatedAt = message.result._updatedAt['$date']
} else if(message._updatedAt) {
if(message._updatedAt.hasOwnProperty('$date')) {
message._updatedAt = message._updatedAt['$date']
}
}
return message
}
/** /**
* @description create a representation of an room in these instance this.dm, this.group ... * @description create a representation of an room in these instance this.dm, this.group ...
@@ -263,13 +274,16 @@ export class WsChatMethodsService {
/** /**
* @description data used to define or create room * @description data used to define or create room
*/ */
roomData = this.fix_updatedAt(roomData)
const setData = { const setData = {
customFields: roomData.customFields, customFields: roomData.customFields,
id: this.getRoomId(roomData), id: this.getRoomId(roomData),
name: this.getRoomName(roomData), name: this.getRoomName(roomData),
t: roomData.t, t: roomData.t,
lastMessage: this.getRoomLastMessage(roomData), lastMessage: this.getRoomLastMessage(roomData),
_updatedAt: new Date(roomData._updatedAt['$date']) _updatedAt: roomData._updatedAt
} }
let roomId = this.getRoomId(roomData) let roomId = this.getRoomId(roomData)
+1 -1
View File
@@ -703,7 +703,7 @@ updateRoomEventss(roomId, collection:string, funx: Function, ) {
this.wsMsgQueue[requestId] = {message, requestId, loginRequired} this.wsMsgQueue[requestId] = {message, requestId, loginRequired}
} else { } else {
let messageStr = JSON.stringify(message) let messageStr = JSON.stringify(message)
// console.log('messageStr', messageStr) console.log('messageStr', messageStr)
this.socket.send(messageStr) this.socket.send(messageStr)
} }
-2
View File
@@ -5,7 +5,6 @@ import { IonicModule } from '@ionic/angular';
import { EventsPageRoutingModule } from './events-routing.module'; import { EventsPageRoutingModule } from './events-routing.module';
import { EventsPage } from './events.page'; import { EventsPage } from './events.page';
import { HeaderPageModule } from 'src/app/shared/header/header.module'; import { HeaderPageModule } from 'src/app/shared/header/header.module';
import { PdfViewerModule } from 'ng2-pdf-viewer';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -15,7 +14,6 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
EventsPageRoutingModule, EventsPageRoutingModule,
HeaderPageModule, HeaderPageModule,
// //
PdfViewerModule
], ],
declarations: [EventsPage], declarations: [EventsPage],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
-5
View File
@@ -113,9 +113,4 @@
</div> </div>
</div> </div>
<!-- <pdf-viewer [src]="pdfSrc"
[render-text]="true"
style="display: block;"
></pdf-viewer> -->
</ion-content> </ion-content>
@@ -11,10 +11,10 @@ import { SharedModule } from 'src/app/shared/shared.module';
import { ChatPopoverPageModule } from '../../popover/chat-popover/chat-popover.module'; import { ChatPopoverPageModule } from '../../popover/chat-popover/chat-popover.module';
import { NewEventPageModule } from '../../agenda/new-event/new-event.module'; import { NewEventPageModule } from '../../agenda/new-event/new-event.module';
import { PdfViewerModule } from 'ng2-pdf-viewer';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import {MatMenuModule} from '@angular/material/menu'; import {MatMenuModule} from '@angular/material/menu';
import { LettersAvatarModule } from "ngx-letters-avatar"; import { LettersAvatarModule } from "ngx-letters-avatar";
import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -22,11 +22,11 @@ import { LettersAvatarModule } from "ngx-letters-avatar";
FormsModule, FormsModule,
IonicModule, IonicModule,
FontAwesomeModule, FontAwesomeModule,
PdfViewerModule,
ChatPopoverPageModule, ChatPopoverPageModule,
GroupMessagesPageRoutingModule, GroupMessagesPageRoutingModule,
MatMenuModule, MatMenuModule,
LettersAvatarModule LettersAvatarModule,
PipesModule,
// //
], ],
exports: [GroupMessagesPage], exports: [GroupMessagesPage],
@@ -72,6 +72,7 @@
</mat-menu> </mat-menu>
</div> </div>
<div class="title"> <div class="title">
<ion-label>{{msg.u.name}}</ion-label>
<span class="time">{{msg.duration}}</span> <span class="time">{{msg.duration}}</span>
</div> </div>
<div class="message"> <div class="message">
@@ -82,7 +83,7 @@
<ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon> <ion-icon *ngIf="msg.attachments[0].image_url == null" name="download-outline"></ion-icon>
</div> </div>
<div *ngIf="msg.file.type != 'application/img'"> <div *ngIf="msg.file.type != 'application/img'">
<div class="file"> <div *ngIf="msg.file.type != 'application/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 == 'application/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 != 'application/audio'">{{msg.displayType}}</span>
</ion-label> </ion-label>
</div> </div>
</div> </div>
@@ -205,22 +209,23 @@
<ion-footer> <ion-footer>
<!-- <div class="typing" *ngIf="wsChatMethodsService.getGroupRoom(roomId).otherUserType == true" >A escrever...</div> --> <!-- <div class="typing" *ngIf="wsChatMethodsService.getGroupRoom(roomId).otherUserType == true" >A escrever...</div> -->
<div class="typing" *ngIf="wsChatMethodsService.getGroupRoom(roomId).otherUserType == true"> <!-- <div class="typing" *ngIf="wsChatMethodsService.getGroupRoom(roomId).otherUserType == true">
<ngx-letters-avatar *ngIf="showAvatar" <ngx-letters-avatar *ngIf="showAvatar"
[avatarName]= "wsChatMethodsService.getGroupRoom(roomId).name" [avatarName]= "wsChatMethodsService.getGroupRoom(roomId).name"
[width]="30" [width]="30"
[circular]="true" [circular]="true"
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)="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() + ".mp3";
//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": "application/audio",
/* "guid": '', */
},
attachments: [{
"title": fileName ,
"title_link": this.audioRecorded,
"title_link_download": true,
"type": "file"
}],
temporaryData: formData
})
this.deleteRecording();
}
deleteMessage(msgId: string) { deleteMessage(msgId: string) {
const room = this.wsChatMethodsService.getGroupRoom(this.roomId) const room = this.wsChatMethodsService.getGroupRoom(this.roomId)
this.alertService.confirmDeleteMessage(msgId, room); this.alertService.confirmDeleteMessage(msgId, room);
@@ -12,7 +12,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import {MatMenuModule} from '@angular/material/menu'; import {MatMenuModule} from '@angular/material/menu';
import { LettersAvatarModule } from "ngx-letters-avatar"; import { LettersAvatarModule } from "ngx-letters-avatar";
import { PdfViewerModule } from 'ng2-pdf-viewer'; import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -24,7 +24,7 @@ import { PdfViewerModule } from 'ng2-pdf-viewer';
MatButtonModule, MatButtonModule,
MatMenuModule, MatMenuModule,
LettersAvatarModule, LettersAvatarModule,
PdfViewerModule PipesModule,
], ],
exports: [MessagesPage], exports: [MessagesPage],
+34 -27
View File
@@ -89,7 +89,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 != 'application/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>
@@ -106,11 +106,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 == 'application/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 != 'application/audio'">{{msg.displayType}}</span>
</ion-label> </ion-label>
<!-- <ion-label class="float-status-webtrix float-status-all"> <!-- <ion-label class="float-status-webtrix float-status-all">
<ion-icon *ngIf="!msg.offline && msg.viewed.length == 0" src="assets/images/check-double-solid.svg"></ion-icon> <ion-icon *ngIf="!msg.offline && msg.viewed.length == 0" src="assets/images/check-double-solid.svg"></ion-icon>
@@ -209,14 +212,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>
@@ -238,30 +241,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>
+150 -3
View File
@@ -19,7 +19,6 @@ import { ThemeService } from 'src/app/services/theme.service'
import { ViewMediaPage } from 'src/app/modals/view-media/view-media.page'; import { ViewMediaPage } from 'src/app/modals/view-media/view-media.page';
import { SqliteService } from 'src/app/services/sqlite.service'; import { SqliteService } from 'src/app/services/sqlite.service';
import { StorageService } from 'src/app/services/storage.service'; import { StorageService } from 'src/app/services/storage.service';
import { Directory, Filesystem } from '@capacitor/filesystem';
import { ViewEventPage } from 'src/app/modals/view-event/view-event.page'; import { ViewEventPage } from 'src/app/modals/view-event/view-event.page';
import { Storage } from '@ionic/storage'; import { Storage } from '@ionic/storage';
import { WsChatMethodsService } from 'src/app/services/chat/ws-chat-methods.service' import { WsChatMethodsService } from 'src/app/services/chat/ws-chat-methods.service'
@@ -34,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({
@@ -78,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,
@@ -107,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'];
@@ -130,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();
} }
@@ -209,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() + ".mp3";
//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);
@@ -250,6 +356,47 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
this.wsChatMethodsService.getDmRoom(this.roomId).send({}) this.wsChatMethodsService.getDmRoom(this.roomId).send({})
} }
async sendAudio(fileName) {
const roomId = this.roomId
let audioFile;
this.storage.get('recordData').then((recordData) => {
console.log(recordData);
audioFile = 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": "application/audio",
/* "guid": '', */
"msDuration":audioFile.value.msDuration,
"mimeType":audioFile.value.mimeType,
},
attachments: [{
"title": fileName ,
"title_link": this.audioRecorded,
"title_link_download": true,
"type": "audio"
}],
temporaryData: formData
})
this.deleteRecording();
}
deleteMessage(msgId: string) { deleteMessage(msgId: string) {
const room = this.wsChatMethodsService.getDmRoom(this.roomId) const room = this.wsChatMethodsService.getDmRoom(this.roomId)
this.alertService.confirmDeleteMessage(msgId, room); this.alertService.confirmDeleteMessage(msgId, room);
+8 -1
View File
@@ -22,13 +22,20 @@
<img *ngIf="ThemeService.currentTheme == 'gov' " src='assets/images/theme/gov/governoangola_A.png' alt='logo'> <img *ngIf="ThemeService.currentTheme == 'gov' " src='assets/images/theme/gov/governoangola_A.png' alt='logo'>
<img *ngIf="ThemeService.currentTheme == 'tribunal' " src='assets/images/theme/tribunal/tribunal-constitucional.png' alt='logo'> <img *ngIf="ThemeService.currentTheme == 'tribunal' " src='assets/images/theme/tribunal/tribunal-constitucional.png' alt='logo'>
</div> </div>
<div class="logo-description d-flex align-center justify-content-center"> <div *ngIf="ThemeService.currentTheme == 'gov'" class="logo-description d-flex align-center justify-content-center">
<div class="logo-description-content"> <div class="logo-description-content">
<p class="logo-description-text">Presidente da República</p> <p class="logo-description-text">Presidente da República</p>
<div class="add-line"></div> <div class="add-line"></div>
<p class="logo-description-text tp-5">GABINETE DIGITAL</p> <p class="logo-description-text tp-5">GABINETE DIGITAL</p>
</div> </div>
</div> </div>
<div *ngIf="ThemeService.currentTheme == 'default'" class="logo-description d-flex align-center justify-content-center">
<div class="logo-description-content">
<p class="logo-description-text color-white">Presidente da República</p>
<div class="add-line-white"></div>
<p class="logo-description-text tp-5 color-white">GABINETE DIGITAL</p>
</div>
</div>
</div> </div>
<div title="Perfil" class="div-profile cursor-pointer" (click)="openProfile()"> <div title="Perfil" class="div-profile cursor-pointer" (click)="openProfile()">
+14
View File
@@ -49,12 +49,26 @@
margin-bottom: 2.5px !important; margin-bottom: 2.5px !important;
padding: 0 !important; padding: 0 !important;
} }
.add-line-white{
width: 100%;
border-bottom: 1px solid #fff;
margin-bottom: 2.5px !important;
padding: 0 !important;
}
}
.color-white{
color: #fff !important;
} }
.add-botton-border{ .add-botton-border{
border-bottom: 1px solid #000; border-bottom: 1px solid #000;
} }
.add-botton-border-white{
border-bottom: 1px solid #fff;
}
} }
} }
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,7 @@
<svg width="45" height="45" viewBox="0 0 45 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M28.7999 13.5C28.7999 10.0206 25.9793 7.20001 22.5 7.20001C19.0206 7.20001 16.2 10.0206 16.2 13.5V22.5C16.2 25.9794 19.0206 28.8 22.5 28.8C25.9793 28.8 28.7999 25.9794 28.7999 22.5V13.5Z" stroke="white" stroke-width="2"/>
<path d="M27 12.6H25.2C24.2059 12.6 23.4 13.4059 23.4 14.4C23.4 15.3941 24.2059 16.2 25.2 16.2H27C27.9941 16.2 28.8 15.3941 28.8 14.4C28.8 13.4059 27.9941 12.6 27 12.6Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.6 32.4H23.4V39.6H21.6V32.4Z" fill="white"/>
<path d="M27.9 39.6H17.1C16.6029 39.6 16.2 40.003 16.2 40.5C16.2 40.9971 16.6029 41.4 17.1 41.4H27.9C28.397 41.4 28.7999 40.9971 28.7999 40.5C28.7999 40.003 28.397 39.6 27.9 39.6Z" fill="white"/>
<path d="M32.4 20.7C32.4 27.4104 29.9556 32.4 22.5 32.4C15.0444 32.4 12.6 27.4104 12.6 20.7" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 969 B

@@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.0 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

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