Skip to content
This repository was archived by the owner on May 18, 2025. It is now read-only.

Commit 549d770

Browse files
committed
merged
1 parent a996499 commit 549d770

File tree

97 files changed

+2806
-3218
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+2806
-3218
lines changed

.eslintignore.errorfiles

Lines changed: 0 additions & 16 deletions
This file was deleted.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"start:all": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n build,reskindex \"yarn start:build\" \"yarn reskindex:watch\"",
4646
"start:build": "babel src -w -s -d lib --verbose --extensions \".ts,.js\"",
4747
"lint": "yarn lint:types && yarn lint:js && yarn lint:style",
48-
"lint:js": "eslint --max-warnings 0 --ignore-path .eslintignore.errorfiles src test",
48+
"lint:js": "eslint --max-warnings 0 src test",
4949
"lint:types": "tsc --noEmit --jsx react",
5050
"lint:style": "stylelint 'res/css/**/*.scss'",
5151
"test": "jest",
@@ -54,7 +54,9 @@
5454
},
5555
"dependencies": {
5656
"@babel/runtime": "^7.12.5",
57+
"@types/commonmark": "^0.27.4",
5758
"await-lock": "^2.1.0",
59+
"blurhash": "^1.1.3",
5860
"browser-encrypt-attachment": "^0.3.0",
5961
"browser-request": "^0.3.3",
6062
"cheerio": "^1.0.0-rc.9",

res/css/views/dialogs/security/_AccessSecretStorageDialog.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ limitations under the License.
2828
left: 0;
2929
top: 2px; // alignment
3030
background-image: url("$(res)/img/element-icons/warning-badge.svg");
31+
background-size: contain;
3132
}
3233

3334
.mx_AccessSecretStorageDialog_reset_link {

res/css/views/messages/_MImageBody.scss

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
$timelineImageBorderRadius: 4px;
18+
1719
.mx_MImageBody {
1820
display: block;
1921
margin-right: 34px;
@@ -25,7 +27,11 @@ limitations under the License.
2527
height: 100%;
2628
left: 0;
2729
top: 0;
28-
border-radius: 4px;
30+
border-radius: $timelineImageBorderRadius;
31+
32+
> canvas {
33+
border-radius: $timelineImageBorderRadius;
34+
}
2935
}
3036

3137
.mx_MImageBody_thumbnail_container {

res/css/views/messages/_TextualEvent.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
.mx_TextualEvent {
1818
opacity: 0.5;
1919
overflow-y: hidden;
20+
/* Hide line noise */
21+
display: none;
2022

2123
a {
2224
color: $accent-color;

res/css/views/messages/_common_CryptoEvent.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ limitations under the License.
4848
.mx_cryptoEvent_buttons {
4949
align-items: center;
5050
display: flex;
51+
gap: 5px;
5152
}
5253

5354
.mx_cryptoEvent_state {

res/css/views/rooms/_EventTile.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ $hover-select-border: 4px;
4040
.mx_EventTile.mx_EventTile_info .mx_EventTile_avatar {
4141
top: $font-6px;
4242
left: $left-gutter;
43+
/* Hide line noise */
44+
display: none;
4345
}
4446

4547
.mx_EventTile_continuation {
@@ -113,6 +115,8 @@ $hover-select-border: 4px;
113115
.mx_EventTile_line {
114116
/* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */
115117
margin-right: 110px;
118+
/* Hide line noise */
119+
display: none;
116120
}
117121
}
118122

scripts/generate-eslint-error-ignore-file

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/CallHandler.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,9 @@ interface ThirdpartyLookupResponseFields {
124124
}
125125

126126
interface ThirdpartyLookupResponse {
127-
userid: string,
128-
protocol: string,
129-
fields: ThirdpartyLookupResponseFields,
127+
userid: string;
128+
protocol: string;
129+
fields: ThirdpartyLookupResponseFields;
130130
}
131131

132132
// Unlike 'CallType' in js-sdk, this one includes screen sharing

src/ContentMessages.tsx

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ limitations under the License.
1717
*/
1818

1919
import React from "react";
20-
import dis from './dispatcher/dispatcher';
21-
import { MatrixClientPeg } from './MatrixClientPeg';
20+
import { encode } from "blurhash";
2221
import { MatrixClient } from "matrix-js-sdk/src/client";
22+
23+
import dis from './dispatcher/dispatcher';
2324
import * as sdk from './index';
2425
import { _t } from './languageHandler';
2526
import Modal from './Modal';
@@ -47,6 +48,10 @@ const MAX_HEIGHT = 600;
4748
// 5669 px (x-axis) , 5669 px (y-axis) , per metre
4849
const PHYS_HIDPI = [0x00, 0x00, 0x16, 0x25, 0x00, 0x00, 0x16, 0x25, 0x01];
4950

51+
export const BLURHASH_FIELD = "xyz.amorgan.blurhash"; // MSC2448
52+
const BLURHASH_X_COMPONENTS = 6;
53+
const BLURHASH_Y_COMPONENTS = 6;
54+
5055
export class UploadCanceledError extends Error {}
5156

5257
type ThumbnailableElement = HTMLImageElement | HTMLVideoElement;
@@ -77,6 +82,7 @@ interface IThumbnail {
7782
};
7883
w: number;
7984
h: number;
85+
[BLURHASH_FIELD]: string;
8086
};
8187
thumbnail: Blob;
8288
}
@@ -124,7 +130,16 @@ function createThumbnail(
124130
const canvas = document.createElement("canvas");
125131
canvas.width = targetWidth;
126132
canvas.height = targetHeight;
127-
canvas.getContext("2d").drawImage(element, 0, 0, targetWidth, targetHeight);
133+
const context = canvas.getContext("2d");
134+
context.drawImage(element, 0, 0, targetWidth, targetHeight);
135+
const imageData = context.getImageData(0, 0, targetWidth, targetHeight);
136+
const blurhash = encode(
137+
imageData.data,
138+
imageData.width,
139+
imageData.height,
140+
BLURHASH_X_COMPONENTS,
141+
BLURHASH_Y_COMPONENTS,
142+
);
128143
canvas.toBlob(function(thumbnail) {
129144
resolve({
130145
info: {
@@ -136,8 +151,9 @@ function createThumbnail(
136151
},
137152
w: inputWidth,
138153
h: inputHeight,
154+
[BLURHASH_FIELD]: blurhash,
139155
},
140-
thumbnail: thumbnail,
156+
thumbnail,
141157
});
142158
}, mimeType);
143159
});
@@ -220,7 +236,8 @@ function infoForImageFile(matrixClient, roomId, imageFile) {
220236
}
221237

222238
/**
223-
* Load a file into a newly created video element.
239+
* Load a file into a newly created video element and pull some strings
240+
* in an attempt to guarantee the first frame will be showing.
224241
*
225242
* @param {File} videoFile The file to load in an video element.
226243
* @return {Promise} A promise that resolves with the video image element.
@@ -229,20 +246,25 @@ function loadVideoElement(videoFile): Promise<HTMLVideoElement> {
229246
return new Promise((resolve, reject) => {
230247
// Load the file into an html element
231248
const video = document.createElement("video");
249+
video.preload = "metadata";
250+
video.playsInline = true;
251+
video.muted = true;
232252

233253
const reader = new FileReader();
234254

235255
reader.onload = function(ev) {
236-
video.src = ev.target.result as string;
237-
238-
// Once ready, returns its size
239256
// Wait until we have enough data to thumbnail the first frame.
240-
video.onloadeddata = function() {
257+
video.onloadeddata = async function() {
241258
resolve(video);
259+
video.pause();
242260
};
243261
video.onerror = function(e) {
244262
reject(e);
245263
};
264+
265+
video.src = ev.target.result as string;
266+
video.load();
267+
video.play();
246268
};
247269
reader.onerror = function(e) {
248270
reject(e);
@@ -347,7 +369,7 @@ export function uploadFile(
347369
});
348370
(prom as IAbortablePromise<any>).abort = () => {
349371
canceled = true;
350-
if (uploadPromise) MatrixClientPeg.get().cancelUpload(uploadPromise);
372+
if (uploadPromise) matrixClient.cancelUpload(uploadPromise);
351373
};
352374
return prom;
353375
} else {
@@ -357,11 +379,11 @@ export function uploadFile(
357379
const promise1 = basePromise.then(function(url) {
358380
if (canceled) throw new UploadCanceledError();
359381
// If the attachment isn't encrypted then include the URL directly.
360-
return { "url": url };
382+
return { url };
361383
});
362384
(promise1 as any).abort = () => {
363385
canceled = true;
364-
MatrixClientPeg.get().cancelUpload(basePromise);
386+
matrixClient.cancelUpload(basePromise);
365387
};
366388
return promise1;
367389
}
@@ -373,7 +395,7 @@ export default class ContentMessages {
373395

374396
sendStickerContentToRoom(url: string, roomId: string, info: IImageInfo, text: string, matrixClient: MatrixClient) {
375397
const startTime = CountlyAnalytics.getTimestamp();
376-
const prom = MatrixClientPeg.get().sendStickerMessage(roomId, url, info, text).catch((e) => {
398+
const prom = matrixClient.sendStickerMessage(roomId, url, info, text).catch((e) => {
377399
console.warn(`Failed to send content with URL ${url} to room ${roomId}`, e);
378400
throw e;
379401
});
@@ -415,7 +437,7 @@ export default class ContentMessages {
415437

416438
if (!this.mediaConfig) { // hot-path optimization to not flash a spinner if we don't need to
417439
const modal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner');
418-
await this.ensureMediaConfigFetched();
440+
await this.ensureMediaConfigFetched(matrixClient);
419441
modal.close();
420442
}
421443

@@ -470,7 +492,7 @@ export default class ContentMessages {
470492
return this.inprogress.filter(u => !u.canceled);
471493
}
472494

473-
cancelUpload(promise: Promise<any>) {
495+
cancelUpload(promise: Promise<any>, matrixClient: MatrixClient) {
474496
let upload: IUpload;
475497
for (let i = 0; i < this.inprogress.length; ++i) {
476498
if (this.inprogress[i].promise === promise) {
@@ -480,7 +502,7 @@ export default class ContentMessages {
480502
}
481503
if (upload) {
482504
upload.canceled = true;
483-
MatrixClientPeg.get().cancelUpload(upload.promise);
505+
matrixClient.cancelUpload(upload.promise);
484506
dis.dispatch<UploadCanceledPayload>({ action: Action.UploadCanceled, upload });
485507
}
486508
}
@@ -621,11 +643,11 @@ export default class ContentMessages {
621643
return true;
622644
}
623645

624-
private ensureMediaConfigFetched() {
646+
private ensureMediaConfigFetched(matrixClient: MatrixClient) {
625647
if (this.mediaConfig !== null) return;
626648

627649
console.log("[Media Config] Fetching");
628-
return MatrixClientPeg.get().getMediaConfig().then((config) => {
650+
return matrixClient.getMediaConfig().then((config) => {
629651
console.log("[Media Config] Fetched config:", config);
630652
return config;
631653
}).catch(() => {

0 commit comments

Comments
 (0)