Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/ts/8

 Conflicts:
	src/components/structures/MessagePanel.tsx
	src/components/structures/TimelinePanel.tsx
This commit is contained in:
Michael Telatynski 2021-06-29 15:22:54 +01:00
commit 623317cd47
76 changed files with 1524 additions and 719 deletions

View File

@ -111,6 +111,29 @@ $roomListCollapsedWidth: 68px;
}
}
.mx_LeftPanel_dialPadButton {
width: 32px;
height: 32px;
border-radius: 8px;
background-color: $roomlist-button-bg-color;
position: relative;
margin-left: 8px;
&::before {
content: '';
position: absolute;
top: 8px;
left: 8px;
width: 16px;
height: 16px;
mask-image: url('$(res)/img/element-icons/call/dialpad.svg');
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $secondary-fg-color;
}
}
.mx_LeftPanel_exploreButton {
width: 32px;
height: 32px;
@ -185,6 +208,12 @@ $roomListCollapsedWidth: 68px;
flex-direction: column;
justify-content: center;
.mx_LeftPanel_dialPadButton {
margin-left: 0;
margin-top: 8px;
background-color: transparent;
}
.mx_LeftPanel_exploreButton {
margin-left: 0;
margin-top: 8px;

View File

@ -112,7 +112,7 @@ limitations under the License.
.mx_AccessibleButton {
padding: 5px 10px;
padding-left: 28px; // 16px for the icon, 2px margin to text, 10px regular padding
padding-left: 30px; // 18px for the icon, 2px margin to text, 10px regular padding
display: inline-block;
position: relative;
@ -128,13 +128,14 @@ limitations under the License.
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
width: 18px;
height: 18px;
top: 50%; // text sizes are dynamic
transform: translateY(-50%);
}
&.mx_RoomStatusBar_unsentCancelAllBtn::before {
mask-image: url('$(res)/img/element-icons/trashcan.svg');
width: 12px;
height: 16px;
top: calc(50% - 8px); // text sizes are dynamic
}
&.mx_RoomStatusBar_unsentResendAllBtn {
@ -142,9 +143,6 @@ limitations under the License.
&::before {
mask-image: url('$(res)/img/element-icons/retry.svg');
width: 18px;
height: 18px;
top: calc(50% - 9px); // text sizes are dynamic
}
}
}

View File

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2021 Michael Weimann <mail@michael-weimann.eu>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -15,16 +16,69 @@ limitations under the License.
*/
.mx_MessageContextMenu {
padding: 6px;
}
.mx_MessageContextMenu_field {
display: block;
padding: 3px 6px 3px 6px;
cursor: pointer;
white-space: nowrap;
}
.mx_IconizedContextMenu_icon {
width: 16px;
height: 16px;
display: block;
.mx_MessageContextMenu_field.mx_MessageContextMenu_fieldSet {
font-weight: bold;
&::before {
content: '';
width: 16px;
height: 16px;
display: block;
mask-position: center;
mask-size: contain;
mask-repeat: no-repeat;
background: $primary-fg-color;
}
}
.mx_MessageContextMenu_iconCollapse::before {
mask-image: url('$(res)/img/element-icons/message/chevron-up.svg');
}
.mx_MessageContextMenu_iconReport::before {
mask-image: url('$(res)/img/element-icons/warning-badge.svg');
}
.mx_MessageContextMenu_iconLink::before {
mask-image: url('$(res)/img/element-icons/link.svg');
}
.mx_MessageContextMenu_iconPermalink::before {
mask-image: url('$(res)/img/element-icons/room/share.svg');
}
.mx_MessageContextMenu_iconUnhidePreview::before {
mask-image: url('$(res)/img/element-icons/settings/appearance.svg');
}
.mx_MessageContextMenu_iconForward::before {
mask-image: url('$(res)/img/element-icons/message/fwd.svg');
}
.mx_MessageContextMenu_iconRedact::before {
mask-image: url('$(res)/img/element-icons/trashcan.svg');
}
.mx_MessageContextMenu_iconResend::before {
mask-image: url('$(res)/img/element-icons/retry.svg');
}
.mx_MessageContextMenu_iconSource::before {
mask-image: url('$(res)/img/element-icons/room/format-bar/code.svg');
}
.mx_MessageContextMenu_iconQuote::before {
mask-image: url('$(res)/img/element-icons/room/format-bar/quote.svg');
}
.mx_MessageContextMenu_iconPin::before {
mask-image: url('$(res)/img/element-icons/room/pin-upright.svg');
}
.mx_MessageContextMenu_iconUnpin::before {
mask-image: url('$(res)/img/element-icons/room/pin.svg');
}
}

View File

@ -34,7 +34,7 @@ limitations under the License.
> .mx_ForwardDialog_preview {
max-height: 30%;
flex-shrink: 0;
overflow: scroll;
overflow-y: auto;
div {
pointer-events: none;

View File

@ -17,4 +17,9 @@ limitations under the License.
.mx_TextualEvent {
opacity: 0.5;
overflow-y: hidden;
a {
color: $accent-color;
cursor: pointer;
}
}

View File

@ -29,6 +29,7 @@ $irc-line-height: $font-18px;
// timestamps are links which shouldn't be underlined
> a {
text-decoration: none;
min-width: 45px;
}
display: flex;
@ -49,18 +50,6 @@ $irc-line-height: $font-18px;
}
}
> .mx_SenderProfile {
order: 2;
flex-shrink: 0;
width: var(--name-width);
text-overflow: ellipsis;
text-align: left;
display: flex;
align-items: center;
overflow: visible;
justify-content: flex-end;
}
.mx_EventTile_line, .mx_EventTile_reply {
padding: 0;
display: flex;
@ -173,27 +162,37 @@ $irc-line-height: $font-18px;
border-left: 0;
}
.mx_SenderProfile_hover {
background-color: $primary-bg-color;
overflow: hidden;
.mx_SenderProfile {
width: var(--name-width);
display: flex;
order: 2;
flex-shrink: 0;
justify-content: flex-start;
align-items: center;
> .mx_SenderProfile_displayName {
width: 100%;
text-align: end;
overflow: hidden;
text-overflow: ellipsis;
min-width: var(--name-width);
text-align: end;
}
> .mx_SenderProfile_mxid {
visibility: collapse;
}
}
.mx_SenderProfile:hover {
justify-content: flex-start;
}
.mx_SenderProfile_hover:hover {
overflow: visible;
width: max(auto, 100%);
z-index: 10;
> .mx_SenderProfile_displayName {
overflow: visible;
}
> .mx_SenderProfile_mxid {
visibility: visible;
}
}
.mx_ReplyThread {
@ -201,16 +200,7 @@ $irc-line-height: $font-18px;
.mx_SenderProfile {
width: unset;
max-width: var(--name-width);
}
.mx_SenderProfile_hover {
background: transparent;
> span {
> .mx_SenderProfile_displayName {
min-width: inherit;
}
}
}
.mx_EventTile_emote {

View File

@ -36,10 +36,10 @@ limitations under the License.
}
.mx_VoiceRecordComposerTile_delete {
width: 14px; // w&h are size of icon
height: 18px;
width: 24px;
height: 24px;
vertical-align: middle;
margin-right: 11px; // distance from left edge of waveform container (container has some margin too)
margin-right: 8px; // distance from left edge of waveform container (container has some margin too)
background-color: $voice-record-icon-color;
mask-repeat: no-repeat;
mask-size: contain;

View File

@ -73,7 +73,7 @@ limitations under the License.
}
}
.mx_AccessibleButton {
.mx_AccessibleButton_hasKind {
padding: 8px 22px;
margin-left: auto;
display: block;

View File

@ -33,9 +33,14 @@ limitations under the License.
font-size: $font-14px;
line-height: $font-24px;
contain: content;
.mx_Waveform {
.mx_Waveform_bar {
background-color: $voice-record-waveform-incomplete-fg-color;
height: 100%;
/* Variable set by a JS component */
transform: scaleY(max(0.05, var(--barHeight)));
&.mx_Waveform_bar_100pct {
// Small animation to remove the mechanical feel of progress

View File

@ -0,0 +1,3 @@
<svg width="12" height="18" viewBox="0 0 12 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 14.25C5.175 14.25 4.5 14.925 4.5 15.75C4.5 16.575 5.175 17.25 6 17.25C6.825 17.25 7.5 16.575 7.5 15.75C7.5 14.925 6.825 14.25 6 14.25ZM1.5 0.75C0.675 0.75 0 1.425 0 2.25C0 3.075 0.675 3.75 1.5 3.75C2.325 3.75 3 3.075 3 2.25C3 1.425 2.325 0.75 1.5 0.75ZM1.5 5.25C0.675 5.25 0 5.925 0 6.75C0 7.575 0.675 8.25 1.5 8.25C2.325 8.25 3 7.575 3 6.75C3 5.925 2.325 5.25 1.5 5.25ZM1.5 9.75C0.675 9.75 0 10.425 0 11.25C0 12.075 0.675 12.75 1.5 12.75C2.325 12.75 3 12.075 3 11.25C3 10.425 2.325 9.75 1.5 9.75ZM10.5 3.75C11.325 3.75 12 3.075 12 2.25C12 1.425 11.325 0.75 10.5 0.75C9.675 0.75 9 1.425 9 2.25C9 3.075 9.675 3.75 10.5 3.75ZM6 9.75C5.175 9.75 4.5 10.425 4.5 11.25C4.5 12.075 5.175 12.75 6 12.75C6.825 12.75 7.5 12.075 7.5 11.25C7.5 10.425 6.825 9.75 6 9.75ZM10.5 9.75C9.675 9.75 9 10.425 9 11.25C9 12.075 9.675 12.75 10.5 12.75C11.325 12.75 12 12.075 12 11.25C12 10.425 11.325 9.75 10.5 9.75ZM10.5 5.25C9.675 5.25 9 5.925 9 6.75C9 7.575 9.675 8.25 10.5 8.25C11.325 8.25 12 7.575 12 6.75C12 5.925 11.325 5.25 10.5 5.25ZM6 5.25C5.175 5.25 4.5 5.925 4.5 6.75C4.5 7.575 5.175 8.25 6 8.25C6.825 8.25 7.5 7.575 7.5 6.75C7.5 5.925 6.825 5.25 6 5.25ZM6 0.75C5.175 0.75 4.5 1.425 4.5 2.25C4.5 3.075 5.175 3.75 6 3.75C6.825 3.75 7.5 3.075 7.5 2.25C7.5 1.425 6.825 0.75 6 0.75Z" fill="#737D8C"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up"><polyline points="18 15 12 9 6 15"></polyline></svg>

After

Width:  |  Height:  |  Size: 268 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-corner-up-right"><polyline points="15 14 20 9 15 4"></polyline><path d="M4 20v-7a4 4 0 0 1 4-4h12"></path></svg>

After

Width:  |  Height:  |  Size: 316 B

View File

@ -0,0 +1,3 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.9454 4.27941C10.653 3.98601 10.6539 3.51114 10.9472 3.21875C11.2406 2.92637 11.7155 2.92719 12.0079 3.22059L15.5312 6.75612C15.8229 7.0488 15.8229 7.52226 15.5312 7.81494L12.0079 11.3505C11.7155 11.6439 11.2407 11.6447 10.9473 11.3523C10.6539 11.06 10.653 10.5851 10.9454 10.2917L13.2292 8H6.36588C4.95064 8 3.75282 9.20272 3.75282 10.75C3.75282 12.2973 4.95064 13.5 6.36588 13.5H7.93524C8.34945 13.5 8.68524 13.8358 8.68524 14.25C8.68524 14.6642 8.34945 15 7.93524 15H6.36588C4.06634 15 2.25282 13.0687 2.25282 10.75C2.25282 8.43128 4.06634 6.5 6.36588 6.5H13.1583L10.9454 4.27941Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 755 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>

After

Width:  |  Height:  |  Size: 371 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-repeat"><polyline points="17 1 21 5 17 9"></polyline><path d="M3 11V9a4 4 0 0 1 4-4h14"></path><polyline points="7 23 3 19 7 15"></polyline><path d="M21 13v2a4 4 0 0 1-4 4H3"></path></svg>

After

Width:  |  Height:  |  Size: 392 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-share"><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"></path><polyline points="16 6 12 2 8 6"></polyline><line x1="12" y1="2" x2="12" y2="15"></line></svg>

After

Width:  |  Height:  |  Size: 364 B

View File

@ -1,3 +1,3 @@
<svg width="12" height="17" viewBox="0 0 12 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.857143 14.5C0.857143 15.4491 1.62857 16.5 2.57143 16.5H9.42857C10.3714 16.5 11.1429 15.2542 11.1429 14.3051V5.67692C11.1429 4.72781 10.3714 3.95128 9.42857 3.95128H2.57143C1.62857 3.95128 0.857143 4.72781 0.857143 5.67692V14.5ZM11.1429 1.36282H9L8.39143 0.750218C8.23714 0.59491 8.01429 0.5 7.79143 0.5H4.20857C3.98571 0.5 3.76286 0.59491 3.60857 0.750218L3 1.36282H0.857143C0.385714 1.36282 0 1.75109 0 2.22564C0 2.70019 0.385714 3.08846 0.857143 3.08846H11.1429C11.6143 3.08846 12 2.70019 12 2.22564C12 1.75109 11.6143 1.36282 11.1429 1.36282Z" fill="#737D8C"/>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 19C6 20.1 6.9 21 8 21H16C17.1 21 18 20.1 18 19V9C18 7.9 17.1 7 16 7H8C6.9 7 6 7.9 6 9V19ZM18 4H15.5L14.79 3.29C14.61 3.11 14.35 3 14.09 3H9.91C9.65 3 9.39 3.11 9.21 3.29L8.5 4H6C5.45 4 5 4.45 5 5C5 5.55 5.45 6 6 6H18C18.55 6 19 5.55 19 5C19 4.45 18.55 4 18 4Z" fill="#8D99A5"/>
</svg>

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 397 B

View File

@ -1,5 +1,32 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="8" fill="#FF4B55"/>
<rect x="7" y="3" width="2" height="6" rx="1" fill="white"/>
<rect x="7" y="11" width="2" height="2" rx="1" fill="white"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg8"
version="1.1"
fill="none"
viewBox="0 0 24 24"
height="24"
width="24">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12" />
<path
id="path2"
d="M 12 2 C 6.47715 2 2 6.47715 2 12 C 2 17.5228 6.47715 22 12 22 C 17.5228 22 22 17.5228 22 12 C 22 6.47715 17.5228 2 12 2 z M 11.880859 5.5039062 C 12.720859 5.4439063 13.470547 6.0746875 13.560547 6.9296875 L 13.560547 7.1699219 L 13.080078 13.169922 C 13.035078 13.724922 12.570625 14.144531 12.015625 14.144531 L 11.925781 14.144531 C 11.400781 14.099531 10.996172 13.694922 10.951172 13.169922 L 10.470703 7.1699219 C 10.395703 6.3149219 11.025859 5.5639064 11.880859 5.5039062 z M 12 15.763672 C 12.729 15.763672 13.320312 16.354884 13.320312 17.083984 C 13.320313 17.812984 12.729 18.404297 12 18.404297 C 11.271 18.404297 10.679688 17.812984 10.679688 17.083984 C 10.679688 16.354884 11.271 15.763672 12 15.763672 z "
style="fill:#ff4b55;fill-opacity:1" />
</svg>

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -5,4 +5,4 @@ FROM node:14-buster
RUN apt-get update
RUN apt-get -y install jq build-essential python3-dev libffi-dev python-pip python-setuptools sqlite3 libssl-dev python-virtualenv libjpeg-dev libxslt1-dev uuid-runtime
# dependencies for chrome (installed by puppeteer)
RUN apt-get -y install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
RUN apt-get -y install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm-dev libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

View File

@ -307,7 +307,7 @@ function readFileAsArrayBuffer(file: File | Blob): Promise<ArrayBuffer> {
* If the file is unencrypted then the object will have a "url" key.
* If the file is encrypted then the object will have a "file" key.
*/
function uploadFile(
export function uploadFile(
matrixClient: MatrixClient,
roomId: string,
file: File | Blob,

View File

@ -68,7 +68,7 @@ export const Notifier = {
// or not
pendingEncryptedEventIds: [],
notificationMessageForEvent: function(ev: MatrixEvent) {
notificationMessageForEvent: function(ev: MatrixEvent): string {
if (typehandlers.hasOwnProperty(ev.getContent().msgtype)) {
return typehandlers[ev.getContent().msgtype](ev);
}

View File

@ -13,6 +13,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import {MatrixClientPeg} from './MatrixClientPeg';
import { _t } from './languageHandler';
import * as Roles from './Roles';
@ -20,6 +22,11 @@ import {isValid3pidInvite} from "./RoomInvite";
import SettingsStore from "./settings/SettingsStore";
import {ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES} from "./mjolnir/BanList";
import {WIDGET_LAYOUT_EVENT_TYPE} from "./stores/widgets/WidgetLayoutStore";
import { RightPanelPhases } from './stores/RightPanelStorePhases';
import { Action } from './dispatcher/actions';
import defaultDispatcher from './dispatcher/dispatcher';
import { SetRightPanelPhasePayload } from './dispatcher/payloads/SetRightPanelPhasePayload';
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
// These functions are frequently used just to check whether an event has
// any text to display at all. For this reason they return deferred values
@ -479,9 +486,33 @@ function textForPowerEvent(event): () => string | null {
});
}
function textForPinnedEvent(event): () => string | null {
const onPinnedMessagesClick = (): void => {
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.PinnedMessages,
allowClose: false,
});
}
function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null {
if (!SettingsStore.getValue("feature_pinning")) return null;
const senderName = event.sender ? event.sender.name : event.getSender();
return () => _t("%(senderName)s changed the pinned messages for the room.", {senderName});
if (allowJSX) {
return () => (
<span>
{
_t(
"%(senderName)s changed the <a>pinned messages</a> for the room.",
{ senderName },
{ "a": (sub) => <a onClick={onPinnedMessagesClick}> { sub } </a> },
)
}
</span>
);
}
return () => _t("%(senderName)s changed the pinned messages for the room.", { senderName });
}
function textForWidgetEvent(event): () => string | null {
@ -607,7 +638,7 @@ function textForMjolnirEvent(event): () => string | null {
}
interface IHandlers {
[type: string]: (ev: any) => (() => string | null);
[type: string]: (ev: MatrixEvent, allowJSX?: boolean) => (() => string | JSX.Element | null);
}
const handlers: IHandlers = {
@ -648,7 +679,9 @@ export function hasText(ev): boolean {
return Boolean(handler?.(ev));
}
export function textForEvent(ev): string {
export function textForEvent(ev: MatrixEvent): string;
export function textForEvent(ev: MatrixEvent, allowJSX: true): string | JSX.Element;
export function textForEvent(ev: MatrixEvent, allowJSX = false): string | JSX.Element {
const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()];
return handler?.(ev)?.() || '';
return handler?.(ev, allowJSX)?.() || '';
}

View File

@ -16,7 +16,7 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { MatrixClientPeg } from "./MatrixClientPeg";
import shouldHideEvent from './shouldHideEvent';
@ -43,12 +43,6 @@ export function eventTriggersUnreadCount(ev: MatrixEvent): boolean {
case EventType.RoomCanonicalAlias:
case EventType.RoomServerAcl:
return false;
case EventType.RoomMessage:
if (ev.getContent().msgtype === MsgType.Notice) {
return false;
}
break;
}
if (ev.isRedacted()) return false;

View File

@ -16,37 +16,49 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import {Filter} from 'matrix-js-sdk/src/filter';
import { Filter } from 'matrix-js-sdk/src/filter';
import { EventTimelineSet } from "matrix-js-sdk/src/models/event-timeline-set";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from 'matrix-js-sdk/src/models/room';
import { TimelineWindow } from 'matrix-js-sdk/src/timeline-window';
import * as sdk from '../../index';
import {MatrixClientPeg} from '../../MatrixClientPeg';
import { MatrixClientPeg } from '../../MatrixClientPeg';
import EventIndexPeg from "../../indexing/EventIndexPeg";
import { _t } from '../../languageHandler';
import BaseCard from "../views/right_panel/BaseCard";
import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
import DesktopBuildsNotice, {WarningKind} from "../views/elements/DesktopBuildsNotice";
import {replaceableComponent} from "../../utils/replaceableComponent";
import DesktopBuildsNotice, { WarningKind } from "../views/elements/DesktopBuildsNotice";
import { replaceableComponent } from "../../utils/replaceableComponent";
import ResizeNotifier from '../../utils/ResizeNotifier';
interface IProps {
roomId: string;
onClose: () => void;
resizeNotifier: ResizeNotifier
}
interface IState {
timelineSet: EventTimelineSet;
}
/*
* Component which shows the filtered file using a TimelinePanel
*/
@replaceableComponent("structures.FilePanel")
class FilePanel extends React.Component {
static propTypes = {
roomId: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
};
class FilePanel extends React.Component<IProps, IState> {
// This is used to track if a decrypted event was a live event and should be
// added to the timeline.
decryptingEvents = new Set();
private decryptingEvents = new Set<string>();
public noRoom: boolean;
state = {
timelineSet: null,
};
onRoomTimeline = (ev, room, toStartOfTimeline, removed, data) => {
private onRoomTimeline = (ev: MatrixEvent, room: Room, toStartOfTimeline: true, removed: true, data: any): void => {
if (room?.roomId !== this.props?.roomId) return;
if (toStartOfTimeline || !data || !data.liveEvent || ev.isRedacted()) return;
@ -60,7 +72,7 @@ class FilePanel extends React.Component {
}
};
onEventDecrypted = (ev, err) => {
private onEventDecrypted = (ev: MatrixEvent, err?: any): void => {
if (ev.getRoomId() !== this.props.roomId) return;
const eventId = ev.getId();
@ -70,7 +82,7 @@ class FilePanel extends React.Component {
this.addEncryptedLiveEvent(ev);
};
addEncryptedLiveEvent(ev, toStartOfTimeline) {
public addEncryptedLiveEvent(ev: MatrixEvent): void {
if (!this.state.timelineSet) return;
const timeline = this.state.timelineSet.getLiveTimeline();
@ -84,7 +96,7 @@ class FilePanel extends React.Component {
}
}
async componentDidMount() {
public async componentDidMount(): Promise<void> {
const client = MatrixClientPeg.get();
await this.updateTimelineSet(this.props.roomId);
@ -105,7 +117,7 @@ class FilePanel extends React.Component {
}
}
componentWillUnmount() {
public componentWillUnmount(): void {
const client = MatrixClientPeg.get();
if (client === null) return;
@ -117,7 +129,7 @@ class FilePanel extends React.Component {
}
}
async fetchFileEventsServer(room) {
public async fetchFileEventsServer(room: Room): Promise<void> {
const client = MatrixClientPeg.get();
const filter = new Filter(client.credentials.userId);
@ -141,7 +153,7 @@ class FilePanel extends React.Component {
return timelineSet;
}
onPaginationRequest = (timelineWindow, direction, limit) => {
private onPaginationRequest = (timelineWindow: TimelineWindow, direction: string, limit: number): void => {
const client = MatrixClientPeg.get();
const eventIndex = EventIndexPeg.get();
const roomId = this.props.roomId;
@ -159,7 +171,7 @@ class FilePanel extends React.Component {
}
};
async updateTimelineSet(roomId: string) {
public async updateTimelineSet(roomId: string): Promise<void> {
const client = MatrixClientPeg.get();
const room = client.getRoom(roomId);
const eventIndex = EventIndexPeg.get();
@ -195,7 +207,7 @@ class FilePanel extends React.Component {
}
}
render() {
public render() {
if (MatrixClientPeg.get().isGuest()) {
return <BaseCard
className="mx_FilePanel mx_RoomView_messageListWrapper"

View File

@ -24,6 +24,7 @@ import CustomRoomTagPanel from "./CustomRoomTagPanel";
import dis from "../../dispatcher/dispatcher";
import { _t } from "../../languageHandler";
import RoomList from "../views/rooms/RoomList";
import CallHandler from "../../CallHandler";
import { HEADER_HEIGHT } from "../views/rooms/RoomSublist";
import { Action } from "../../dispatcher/actions";
import UserMenu from "./UserMenu";
@ -124,6 +125,10 @@ export default class LeftPanel extends React.Component<IProps, IState> {
this.setState({ activeSpace });
};
private onDialPad = () => {
dis.fire(Action.OpenDialPad);
}
private onExplore = () => {
dis.fire(Action.ViewRoomDirectory);
};
@ -397,7 +402,20 @@ export default class LeftPanel extends React.Component<IProps, IState> {
}
}
private renderSearchExplore(): React.ReactNode {
private renderSearchDialExplore(): React.ReactNode {
let dialPadButton = null;
// If we have dialer support, show a button to bring up the dial pad
// to start a new call
if (CallHandler.sharedInstance().getSupportsPstnProtocol()) {
dialPadButton =
<AccessibleTooltipButton
className={classNames("mx_LeftPanel_dialPadButton", {})}
onClick={this.onDialPad}
title={_t("Open dial pad")}
/>;
}
return (
<div
className="mx_LeftPanel_filterContainer"
@ -410,6 +428,9 @@ export default class LeftPanel extends React.Component<IProps, IState> {
onKeyDown={this.onKeyDown}
onSelectRoom={this.selectRoom}
/>
{dialPadButton}
<AccessibleTooltipButton
className={classNames("mx_LeftPanel_exploreButton", {
mx_LeftPanel_exploreButton_space: !!this.state.activeSpace,
@ -458,7 +479,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
{leftLeftPanel}
<aside className="mx_LeftPanel_roomListContainer">
{this.renderHeader()}
{this.renderSearchExplore()}
{this.renderSearchDialExplore()}
{this.renderBreadcrumbs()}
<RoomListNumResults onVisibilityChange={this.refreshStickyHeaders} />
<div className="mx_LeftPanel_roomListWrapper">

View File

@ -50,6 +50,7 @@ import EditorStateTransfer from "../../utils/EditorStateTransfer";
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
const continuedTypes = [EventType.Sticker, EventType.RoomMessage];
const membershipTypes = [EventType.RoomMember, EventType.RoomThirdPartyInvite, EventType.RoomServerAcl];
// check if there is a previous event and it has the same sender as this event
// and the types are the same/is in continuedTypes and the time between them is <= CONTINUATION_MAX_INTERVAL
@ -78,10 +79,6 @@ function shouldFormContinuation(prevEvent: MatrixEvent, mxEvent: MatrixEvent): b
return true;
}
const isMembershipChange = (e: MatrixEvent): boolean => {
return e.getType() === EventType.RoomMember || e.getType() === EventType.RoomThirdPartyInvite;
}
interface IProps {
// the list of MatrixEvents to display
events: MatrixEvent[];
@ -1183,7 +1180,7 @@ class RedactionGrouper extends BaseGrouper {
// Wrap consecutive member events in a ListSummary, ignore if redacted
class MemberGrouper extends BaseGrouper {
static canStartGroup = function(panel: MessagePanel, ev: MatrixEvent): boolean {
return panel.shouldShowEvent(ev) && isMembershipChange(ev);
return panel.shouldShowEvent(ev) && membershipTypes.includes(ev.getType() as EventType);
}
constructor(
@ -1200,7 +1197,7 @@ class MemberGrouper extends BaseGrouper {
if (this.panel.wantsDateSeparator(this.events[0], ev.getDate())) {
return false;
}
return isMembershipChange(ev);
return membershipTypes.includes(ev.getType() as EventType);
}
public add(ev: MatrixEvent): void {

View File

@ -82,6 +82,7 @@ import SpaceRoomView from "./SpaceRoomView";
import { IOpts } from "../../createRoom";
import { replaceableComponent } from "../../utils/replaceableComponent";
import UIStore from "../../stores/UIStore";
import EditorStateTransfer from "../../utils/EditorStateTransfer";
const DEBUG = false;
let debuglog = function(msg: string) {};
@ -192,6 +193,7 @@ export interface IState {
// whether or not a spaces context switch brought us here,
// if it did we don't want the room to be marked as read as soon as it is loaded.
wasContextSwitch?: boolean;
editState?: EditorStateTransfer;
}
@replaceableComponent("structures.RoomView")
@ -815,6 +817,36 @@ export default class RoomView extends React.Component<IProps, IState> {
case 'focus_search':
this.onSearchClick();
break;
case "edit_event": {
const editState = payload.event ? new EditorStateTransfer(payload.event) : null;
this.setState({ editState }, () => {
if (payload.event) {
this.messagePanel?.scrollToEventIfNeeded(payload.event.getId());
}
});
break;
}
case Action.ComposerInsert: {
// re-dispatch to the correct composer
if (this.state.editState) {
dis.dispatch({
...payload,
action: "edit_composer_insert",
});
} else {
dis.dispatch({
...payload,
action: "send_composer_insert",
});
}
break;
}
case "scroll_to_bottom":
this.messagePanel?.jumpToLiveTimeline();
break;
}
};
@ -2040,6 +2072,7 @@ export default class RoomView extends React.Component<IProps, IState> {
resizeNotifier={this.props.resizeNotifier}
showReactions={true}
layout={this.state.layout}
editState={this.state.editState}
/>);
let topUnreadMessagesBar = null;

View File

@ -14,58 +14,60 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {RefObject, useContext, useRef, useState} from "react";
import {EventType} from "matrix-js-sdk/src/@types/event";
import {Room} from "matrix-js-sdk/src/models/room";
import {EventSubscription} from "fbemitter";
import React, { RefObject, useContext, useRef, useState } from "react";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { Preset } from "matrix-js-sdk/src/@types/partials";
import { Room } from "matrix-js-sdk/src/models/room";
import { EventSubscription } from "fbemitter";
import MatrixClientContext from "../../contexts/MatrixClientContext";
import RoomAvatar from "../views/avatars/RoomAvatar";
import {_t} from "../../languageHandler";
import { _t } from "../../languageHandler";
import AccessibleButton from "../views/elements/AccessibleButton";
import RoomName from "../views/elements/RoomName";
import RoomTopic from "../views/elements/RoomTopic";
import InlineSpinner from "../views/elements/InlineSpinner";
import {inviteMultipleToRoom, showRoomInviteDialog} from "../../RoomInvite";
import {useRoomMembers} from "../../hooks/useRoomMembers";
import createRoom, {IOpts} from "../../createRoom";
import { inviteMultipleToRoom, showRoomInviteDialog } from "../../RoomInvite";
import { useRoomMembers } from "../../hooks/useRoomMembers";
import createRoom, { IOpts } from "../../createRoom";
import Field from "../views/elements/Field";
import {useEventEmitter} from "../../hooks/useEventEmitter";
import { useEventEmitter } from "../../hooks/useEventEmitter";
import withValidation from "../views/elements/Validation";
import * as Email from "../../email";
import defaultDispatcher from "../../dispatcher/dispatcher";
import {Action} from "../../dispatcher/actions";
import dis from "../../dispatcher/dispatcher";
import { Action } from "../../dispatcher/actions";
import ResizeNotifier from "../../utils/ResizeNotifier"
import MainSplit from './MainSplit';
import ErrorBoundary from "../views/elements/ErrorBoundary";
import {ActionPayload} from "../../dispatcher/payloads";
import { ActionPayload } from "../../dispatcher/payloads";
import RightPanel from "./RightPanel";
import RightPanelStore from "../../stores/RightPanelStore";
import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
import {SetRightPanelPhasePayload} from "../../dispatcher/payloads/SetRightPanelPhasePayload";
import {useStateArray} from "../../hooks/useStateArray";
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
import { SetRightPanelPhasePayload } from "../../dispatcher/payloads/SetRightPanelPhasePayload";
import { useStateArray } from "../../hooks/useStateArray";
import SpacePublicShare from "../views/spaces/SpacePublicShare";
import {showAddExistingRooms, showCreateNewRoom, shouldShowSpaceSettings, showSpaceSettings} from "../../utils/space";
import {showRoom, SpaceHierarchy} from "./SpaceRoomDirectory";
import { shouldShowSpaceSettings, showAddExistingRooms, showCreateNewRoom, showSpaceSettings } from "../../utils/space";
import { showRoom, SpaceHierarchy } from "./SpaceRoomDirectory";
import MemberAvatar from "../views/avatars/MemberAvatar";
import {useStateToggle} from "../../hooks/useStateToggle";
import { useStateToggle } from "../../hooks/useStateToggle";
import SpaceStore from "../../stores/SpaceStore";
import FacePile from "../views/elements/FacePile";
import {AddExistingToSpace} from "../views/dialogs/AddExistingToSpaceDialog";
import {ChevronFace, ContextMenuButton, useContextMenu} from "./ContextMenu";
import { AddExistingToSpace } from "../views/dialogs/AddExistingToSpaceDialog";
import { ChevronFace, ContextMenuButton, useContextMenu } from "./ContextMenu";
import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../views/context_menus/IconizedContextMenu";
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
import {BetaPill} from "../views/beta/BetaCard";
import { BetaPill } from "../views/beta/BetaCard";
import { UserTab } from "../views/dialogs/UserSettingsDialog";
import SettingsStore from "../../settings/SettingsStore";
import dis from "../../dispatcher/dispatcher";
import Modal from "../../Modal";
import BetaFeedbackDialog from "../views/dialogs/BetaFeedbackDialog";
import SdkConfig from "../../SdkConfig";
import { Preset } from "matrix-js-sdk/src/@types/partials";
import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership";
import { JoinRule } from "../views/settings/tabs/room/SecurityRoomSettingsTab";
interface IProps {
space: Room;
@ -178,6 +180,9 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
const spacesEnabled = SettingsStore.getValue("feature_spaces");
const cannotJoin = getEffectiveMembership(myMembership) === EffectiveMembership.Leave
&& space.getJoinRule() !== JoinRule.Public;
let inviterSection;
let joinButtons;
if (myMembership === "join") {
@ -244,7 +249,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
setBusy(true);
onJoinButtonClicked();
}}
disabled={!spacesEnabled}
disabled={!spacesEnabled || cannotJoin}
>
{ _t("Join") }
</AccessibleButton>
@ -255,6 +260,30 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
joinButtons = <InlineSpinner />;
}
let footer;
if (!spacesEnabled) {
footer = <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
{ myMembership === "join"
? _t("To view %(spaceName)s, turn on the <a>Spaces beta</a>", {
spaceName: space.name,
}, {
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
})
: _t("To join %(spaceName)s, turn on the <a>Spaces beta</a>", {
spaceName: space.name,
}, {
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
})
}
</div>;
} else if (cannotJoin) {
footer = <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
{ _t("To view %(spaceName)s, you need an invite", {
spaceName: space.name,
}) }
</div>;
}
return <div className="mx_SpaceRoomView_preview">
<BetaPill onClick={onBetaClick} />
{ inviterSection }
@ -274,20 +303,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
<div className="mx_SpaceRoomView_preview_joinButtons">
{ joinButtons }
</div>
{ !spacesEnabled && <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
{ myMembership === "join"
? _t("To view %(spaceName)s, turn on the <a>Spaces beta</a>", {
spaceName: space.name,
}, {
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
})
: _t("To join %(spaceName)s, turn on the <a>Spaces beta</a>", {
spaceName: space.name,
}, {
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
})
}
</div> }
{ footer }
</div>;
};

View File

@ -34,12 +34,10 @@ import * as sdk from "../../index";
import { Key } from '../../Keyboard';
import Timer from '../../utils/Timer';
import shouldHideEvent from '../../shouldHideEvent';
import EditorStateTransfer from '../../utils/EditorStateTransfer';
import { haveTileForEvent, TileShape } from "../views/rooms/EventTile";
import { UIFeature } from "../../settings/UIFeature";
import { replaceableComponent } from "../../utils/replaceableComponent";
import { arrayFastClone } from "../../utils/arrays";
import { Action } from "../../dispatcher/actions";
import MessagePanel from "./MessagePanel";
import { SyncState } from 'matrix-js-sdk/src/sync.api';
import { IScrollState } from "./ScrollPanel";
@ -48,6 +46,7 @@ import { EventType } from 'matrix-js-sdk/src/@types/event';
import ResizeNotifier from "../../utils/ResizeNotifier";
import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
import Spinner from "../views/elements/Spinner";
import EditorStateTransfer from '../../utils/EditorStateTransfer';
const PAGINATE_SIZE = 20;
const INITIAL_SIZE = 20;
@ -494,38 +493,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
case "ignore_state_changed":
this.forceUpdate();
break;
case "edit_event": {
const editState = payload.event ? new EditorStateTransfer(payload.event) : null;
this.setState({ editState }, () => {
if (payload.event && this.messagePanel.current) {
this.messagePanel.current.scrollToEventIfNeeded(
payload.event.getId(),
);
}
});
break;
}
case Action.ComposerInsert: {
// re-dispatch to the correct composer
if (this.state.editState) {
dis.dispatch({
...payload,
action: "edit_composer_insert",
});
} else {
dis.dispatch({
...payload,
action: "send_composer_insert",
});
}
break;
}
case "scroll_to_bottom":
this.jumpToLiveTimeline();
break;
}
};
@ -925,6 +892,10 @@ class TimelinePanel extends React.Component<IProps, IState> {
}
};
public scrollToEventIfNeeded = (eventId: string): void => {
this.messagePanel.current?.scrollToEventIfNeeded(eventId);
}
/* scroll to show the read-up-to marker. We put it 1/3 of the way down
* the container.
*/
@ -1526,7 +1497,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
tileShape={this.props.tileShape}
resizeNotifier={this.props.resizeNotifier}
getRelationsForEvent={this.getRelationsForEvent}
editState={this.state.editState}
editState={this.props.editState}
showReactions={this.props.showReactions}
layout={this.props.layout}
enableFlair={SettingsStore.getValue(UIFeature.Flair)}

View File

@ -28,7 +28,7 @@ import Resend from '../../../Resend';
import SettingsStore from '../../../settings/SettingsStore';
import { isUrlPermitted } from '../../../HtmlUtils';
import { isContentActionable } from '../../../utils/EventUtils';
import { MenuItem } from "../../structures/ContextMenu";
import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu';
import { EventType } from "matrix-js-sdk/src/@types/event";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { ReadPinsEventId } from "../right_panel/PinnedMessagesCard";
@ -257,55 +257,68 @@ export default class MessageContextMenu extends React.Component {
let externalURLButton;
let quoteButton;
let collapseReplyThread;
let redactItemList;
// status is SENT before remote-echo, null after
const isSent = !eventStatus || eventStatus === EventStatus.SENT;
if (!mxEvent.isRedacted()) {
if (unsentReactionsCount !== 0) {
resendReactionsButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onResendReactionsClick}>
{ _t('Resend %(unsentCount)s reaction(s)', {unsentCount: unsentReactionsCount}) }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconResend"
label={ _t('Resend %(unsentCount)s reaction(s)', {unsentCount: unsentReactionsCount}) }
onClick={this.onResendReactionsClick}
/>
);
}
}
if (isSent && this.state.canRedact) {
redactButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onRedactClick}>
{ _t('Remove') }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconRedact"
label={_t("Remove")}
onClick={this.onRedactClick}
/>
);
}
if (isContentActionable(mxEvent)) {
forwardButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onForwardClick}>
{ _t('Forward Message') }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconForward"
label={_t("Forward")}
onClick={this.onForwardClick}
/>
);
if (this.state.canPin) {
pinButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onPinClick}>
{ this._isPinned() ? _t('Unpin Message') : _t('Pin Message') }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconPin"
label={ this._isPinned() ? _t('Unpin') : _t('Pin') }
onClick={this.onPinClick}
/>
);
}
}
const viewSourceButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onViewSourceClick}>
{ _t('View Source') }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconSource"
label={_t("View source")}
onClick={this.onViewSourceClick}
/>
);
if (this.props.eventTileOps) {
if (this.props.eventTileOps.isWidgetHidden()) {
unhidePreviewButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onUnhidePreviewClick}>
{ _t('Unhide Preview') }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconUnhidePreview"
label={_t("Show preview")}
onClick={this.onUnhidePreviewClick}
/>
);
}
}
@ -316,77 +329,97 @@ export default class MessageContextMenu extends React.Component {
}
// XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID)
const permalinkButton = (
<MenuItem
element="a"
className="mx_MessageContextMenu_field"
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconPermalink"
onClick={this.onPermalinkClick}
label= {_t('Share')}
element="a"
href={permalink}
target="_blank"
rel="noreferrer noopener"
>
{ mxEvent.isRedacted() || mxEvent.getType() !== 'm.room.message'
? _t('Share Permalink') : _t('Share Message') }
</MenuItem>
/>
);
if (this.props.eventTileOps) { // this event is rendered using TextualBody
quoteButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onQuoteClick}>
{ _t('Quote') }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconQuote"
label={_t("Quote")}
onClick={this.onQuoteClick}
/>
);
}
// Bridges can provide a 'external_url' to link back to the source.
if (
typeof(mxEvent.event.content.external_url) === "string" &&
if (typeof (mxEvent.event.content.external_url) === "string" &&
isUrlPermitted(mxEvent.event.content.external_url)
) {
externalURLButton = (
<MenuItem
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconLink"
onClick={this.closeMenu}
label={ _t('Source URL') }
element="a"
className="mx_MessageContextMenu_field"
target="_blank"
rel="noreferrer noopener"
onClick={this.closeMenu}
href={mxEvent.event.content.external_url}
>
{ _t('Source URL') }
</MenuItem>
/>
);
}
if (this.props.collapseReplyThread) {
collapseReplyThread = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onCollapseReplyThreadClick}>
{ _t('Collapse Reply Thread') }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconCollapse"
label={_t("Collapse reply thread")}
onClick={this.onCollapseReplyThreadClick}
/>
);
}
let reportEventButton;
if (mxEvent.getSender() !== me) {
reportEventButton = (
<MenuItem className="mx_MessageContextMenu_field" onClick={this.onReportEventClick}>
{ _t('Report Content') }
</MenuItem>
<IconizedContextMenuOption
iconClassName="mx_MessageContextMenu_iconReport"
label={_t("Report")}
onClick={this.onReportEventClick}
/>
);
}
const commonItemsList = (
<IconizedContextMenuOptionList>
{ quoteButton }
{ forwardButton }
{ pinButton }
{ permalinkButton }
{ reportEventButton }
{ externalURLButton }
{ unhidePreviewButton }
{ viewSourceButton }
{ resendReactionsButton }
{ collapseReplyThread }
</IconizedContextMenuOptionList>
);
if (redactButton) {
redactItemList = (
<IconizedContextMenuOptionList red>
{ redactButton }
</IconizedContextMenuOptionList>
);
}
return (
<div className="mx_MessageContextMenu">
{ resendReactionsButton }
{ redactButton }
{ forwardButton }
{ pinButton }
{ viewSourceButton }
{ unhidePreviewButton }
{ permalinkButton }
{ quoteButton }
{ externalURLButton }
{ collapseReplyThread }
{ reportEventButton }
</div>
<IconizedContextMenu
{...this.props}
className="mx_MessageContextMenu"
compact={true}
>
{ commonItemsList }
{ redactItemList }
</IconizedContextMenu>
);
}
}

View File

@ -56,6 +56,7 @@ enum TransitionType {
ChangedName = "changed_name",
ChangedAvatar = "changed_avatar",
NoChange = "no_change",
ServerAcl = "server_acl",
}
const SEP = ",";
@ -288,6 +289,12 @@ export default class MemberEventListSummary extends React.Component<IProps> {
? _t("%(severalUsers)smade no changes %(count)s times", { severalUsers: "", count: repeats })
: _t("%(oneUser)smade no changes %(count)s times", { oneUser: "", count: repeats });
break;
case "server_acl":
res = (userCount > 1)
? _t("%(severalUsers)schanged the server ACLs %(count)s times",
{ severalUsers: "", count: repeats })
: _t("%(oneUser)schanged the server ACLs %(count)s times", { oneUser: "", count: repeats });
break;
}
return res;
@ -314,6 +321,10 @@ export default class MemberEventListSummary extends React.Component<IProps> {
return TransitionType.Invited;
}
if (e.mxEvent.getType() === 'm.room.server_acl') {
return TransitionType.ServerAcl;
}
switch (e.mxEvent.getContent().membership) {
case 'invite': return TransitionType.Invited;
case 'ban': return TransitionType.Banned;
@ -400,19 +411,23 @@ export default class MemberEventListSummary extends React.Component<IProps> {
// Object mapping user IDs to an array of IUserEvents
const userEvents: Record<string, IUserEvents[]> = {};
eventsToRender.forEach((e, index) => {
const userId = e.getStateKey();
const userId = e.getType() === 'm.room.server_acl' ? e.getSender() : e.getStateKey();
// Initialise a user's events
if (!userEvents[userId]) {
userEvents[userId] = [];
}
if (e.target) {
if (e.getType() === 'm.room.server_acl') {
latestUserAvatarMember.set(userId, e.sender);
} else if (e.target) {
latestUserAvatarMember.set(userId, e.target);
}
let displayName = userId;
if (e.getType() === 'm.room.third_party_invite') {
displayName = e.getContent().display_name;
} else if (e.getType() === 'm.room.server_acl') {
displayName = e.sender.name;
} else if (e.target) {
displayName = e.target.name;
}

View File

@ -48,15 +48,14 @@ const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFo
const replyThread = getReplyThread && getReplyThread();
const buttonRect = button.current.getBoundingClientRect();
contextMenu = <ContextMenu {...aboveLeftOf(buttonRect)} onFinished={closeMenu}>
<MessageContextMenu
mxEvent={mxEvent}
permalinkCreator={permalinkCreator}
eventTileOps={tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined}
collapseReplyThread={replyThread && replyThread.canCollapse() ? replyThread.collapse : undefined}
onFinished={closeMenu}
/>
</ContextMenu>;
contextMenu = <MessageContextMenu
{...aboveLeftOf(buttonRect)}
mxEvent={mxEvent}
permalinkCreator={permalinkCreator}
eventTileOps={tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined}
collapseReplyThread={replyThread && replyThread.canCollapse() ? replyThread.collapse : undefined}
onFinished={closeMenu}
/>;
}
return <React.Fragment>

View File

@ -140,7 +140,7 @@ export default class SenderProfile extends React.Component<IProps, IState> {
}
return (
<div className="mx_SenderProfile mx_SenderProfile_hover" dir="auto" onClick={this.props.onClick}>
<div className="mx_SenderProfile" dir="auto" onClick={this.props.onClick}>
<span className={`mx_SenderProfile_displayName ${colorClass}`}>
{ displayName }
</span>

View File

@ -28,7 +28,7 @@ export default class TextualEvent extends React.Component {
};
render() {
const text = TextForEvent.textForEvent(this.props.mxEvent);
const text = TextForEvent.textForEvent(this.props.mxEvent, true);
if (text == null || text.length === 0) return null;
return (
<div className="mx_TextualEvent">{ text }</div>

View File

@ -17,13 +17,23 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import AccessibleButton from '../elements/AccessibleButton';
import { _t } from '../../../languageHandler';
import { _td } from '../../../languageHandler';
import classNames from "classnames";
import E2EIcon from './E2EIcon';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import BaseAvatar from '../avatars/BaseAvatar';
import PresenceLabel from "./PresenceLabel";
export enum PowerStatus {
Admin = "admin",
Moderator = "moderator",
}
const PowerLabel: Record<PowerStatus, string> = {
[PowerStatus.Admin]: _td("Admin"),
[PowerStatus.Moderator]: _td("Mod"),
}
const PRESENCE_CLASS = {
"offline": "mx_EntityTile_offline",
@ -31,14 +41,14 @@ const PRESENCE_CLASS = {
"unavailable": "mx_EntityTile_unavailable",
};
function presenceClassForMember(presenceState, lastActiveAgo, showPresence) {
function presenceClassForMember(presenceState: string, lastActiveAgo: number, showPresence: boolean): string {
if (showPresence === false) {
return 'mx_EntityTile_online_beenactive';
}
// offline is split into two categories depending on whether we have
// a last_active_ago for them.
if (presenceState == 'offline') {
if (presenceState === 'offline') {
if (lastActiveAgo) {
return PRESENCE_CLASS['offline'] + '_beenactive';
} else {
@ -51,29 +61,32 @@ function presenceClassForMember(presenceState, lastActiveAgo, showPresence) {
}
}
@replaceableComponent("views.rooms.EntityTile")
class EntityTile extends React.Component {
static propTypes = {
name: PropTypes.string,
title: PropTypes.string,
avatarJsx: PropTypes.any, // <BaseAvatar />
className: PropTypes.string,
presenceState: PropTypes.string,
presenceLastActiveAgo: PropTypes.number,
presenceLastTs: PropTypes.number,
presenceCurrentlyActive: PropTypes.bool,
showInviteButton: PropTypes.bool,
shouldComponentUpdate: PropTypes.func,
onClick: PropTypes.func,
suppressOnHover: PropTypes.bool,
showPresence: PropTypes.bool,
subtextLabel: PropTypes.string,
e2eStatus: PropTypes.string,
};
interface IProps {
name?: string;
title?: string;
avatarJsx?: JSX.Element; // <BaseAvatar />
className?: string;
presenceState?: string;
presenceLastActiveAgo?: number;
presenceLastTs?: number;
presenceCurrentlyActive?: boolean;
showInviteButton?: boolean;
onClick?(): void;
suppressOnHover?: boolean;
showPresence?: boolean;
subtextLabel?: string;
e2eStatus?: string;
powerStatus?: PowerStatus;
}
interface IState {
hover: boolean;
}
@replaceableComponent("views.rooms.EntityTile")
export default class EntityTile extends React.PureComponent<IProps, IState> {
static defaultProps = {
shouldComponentUpdate: function(nextProps, nextState) { return true; },
onClick: function() {},
onClick: () => {},
presenceState: "offline",
presenceLastActiveAgo: 0,
presenceLastTs: 0,
@ -82,13 +95,12 @@ class EntityTile extends React.Component {
showPresence: true,
};
state = {
hover: false,
};
constructor(props: IProps) {
super(props);
shouldComponentUpdate(nextProps, nextState) {
if (this.state.hover !== nextState.hover) return true;
return this.props.shouldComponentUpdate(nextProps, nextState);
this.state = {
hover: false,
};
}
render() {
@ -110,7 +122,6 @@ class EntityTile extends React.Component {
const activeAgo = this.props.presenceLastActiveAgo ?
(Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)) : -1;
const PresenceLabel = sdk.getComponent("rooms.PresenceLabel");
let presenceLabel = null;
if (this.props.showPresence) {
presenceLabel = <PresenceLabel activeAgo={activeAgo}
@ -155,10 +166,7 @@ class EntityTile extends React.Component {
let powerLabel;
const powerStatus = this.props.powerStatus;
if (powerStatus) {
const powerText = {
[EntityTile.POWER_STATUS_MODERATOR]: _t("Mod"),
[EntityTile.POWER_STATUS_ADMIN]: _t("Admin"),
}[powerStatus];
const powerText = PowerLabel[powerStatus];
powerLabel = <div className="mx_EntityTile_power">{powerText}</div>;
}
@ -168,14 +176,12 @@ class EntityTile extends React.Component {
e2eIcon = <E2EIcon status={e2eStatus} isUser={true} bordered={true} />;
}
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const av = this.props.avatarJsx ||
<BaseAvatar name={this.props.name} width={36} height={36} aria-hidden="true" />;
// The wrapping div is required to make the magic mouse listener work, for some reason.
return (
<div ref={(c) => this.container = c} >
<div>
<AccessibleButton
className={classNames(mainClassNames)}
title={this.props.title}
@ -193,8 +199,3 @@ class EntityTile extends React.Component {
);
}
}
EntityTile.POWER_STATUS_MODERATOR = "moderator";
EntityTile.POWER_STATUS_ADMIN = "admin";
export default EntityTile;

View File

@ -853,7 +853,7 @@ export default class EventTile extends React.Component<IProps, IState> {
let tileHandler = getHandlerTile(this.props.mxEvent);
// Info messages are basically information about commands processed on a room
const isBubbleMessage = eventType.startsWith("m.key.verification") ||
let isBubbleMessage = eventType.startsWith("m.key.verification") ||
(eventType === EventType.RoomMessage && msgtype && msgtype.startsWith("m.key.verification")) ||
(eventType === EventType.RoomCreate) ||
(eventType === EventType.RoomEncryption) ||
@ -869,6 +869,7 @@ export default class EventTile extends React.Component<IProps, IState> {
// duplicate of the thing they are replacing).
if (SettingsStore.getValue("showHiddenEventsInTimeline") && !haveTileForEvent(this.props.mxEvent)) {
tileHandler = "messages.ViewSourceEvent";
isBubbleMessage = false;
// Reuse info message avatar and sender profile styling
isInfoMessage = true;
}

View File

@ -17,20 +17,33 @@ limitations under the License.
import SettingsStore from "../../../settings/SettingsStore";
import React from 'react';
import PropTypes from 'prop-types';
import * as sdk from "../../../index";
import dis from "../../../dispatcher/dispatcher";
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import {Action} from "../../../dispatcher/actions";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
import EntityTile, { PowerStatus } from "./EntityTile";
import MemberAvatar from "./../avatars/MemberAvatar";
interface IProps {
member: RoomMember;
showPresence?: boolean;
}
interface IState {
statusMessage: string;
isRoomEncrypted: boolean;
e2eStatus: string;
}
@replaceableComponent("views.rooms.MemberTile")
export default class MemberTile extends React.Component {
static propTypes = {
member: PropTypes.any.isRequired, // RoomMember
showPresence: PropTypes.bool,
};
export default class MemberTile extends React.Component<IProps, IState> {
private userLastModifiedTime: number;
private memberLastModifiedTime: number;
static defaultProps = {
showPresence: true,
@ -52,7 +65,7 @@ export default class MemberTile extends React.Component {
if (SettingsStore.getValue("feature_custom_status")) {
const { user } = this.props.member;
if (user) {
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
user.on("User._unstable_statusMessage", this.onStatusMessageCommitted);
}
}
@ -80,7 +93,7 @@ export default class MemberTile extends React.Component {
if (user) {
user.removeListener(
"User._unstable_statusMessage",
this._onStatusMessageCommitted,
this.onStatusMessageCommitted,
);
}
@ -91,8 +104,8 @@ export default class MemberTile extends React.Component {
}
}
onRoomStateEvents = ev => {
if (ev.getType() !== "m.room.encryption") return;
private onRoomStateEvents = (ev: MatrixEvent): void => {
if (ev.getType() !== EventType.RoomEncryption) return;
const { roomId } = this.props.member;
if (ev.getRoomId() !== roomId) return;
@ -105,17 +118,17 @@ export default class MemberTile extends React.Component {
this.updateE2EStatus();
};
onUserTrustStatusChanged = (userId, trustStatus) => {
private onUserTrustStatusChanged = (userId: string, trustStatus: string): void => {
if (userId !== this.props.member.userId) return;
this.updateE2EStatus();
};
onDeviceVerificationChanged = (userId, deviceId, deviceInfo) => {
private onDeviceVerificationChanged = (userId: string, deviceId: string, deviceInfo: DeviceInfo): void => {
if (userId !== this.props.member.userId) return;
this.updateE2EStatus();
};
async updateE2EStatus() {
private async updateE2EStatus(): Promise<void> {
const cli = MatrixClientPeg.get();
const { userId } = this.props.member;
const isMe = userId === cli.getUserId();
@ -143,32 +156,32 @@ export default class MemberTile extends React.Component {
});
}
getStatusMessage() {
private getStatusMessage(): string {
const { user } = this.props.member;
if (!user) {
return "";
}
return user._unstable_statusMessage;
return user.unstable_statusMessage;
}
_onStatusMessageCommitted = () => {
private onStatusMessageCommitted = (): void => {
// The `User` object has observed a status message change.
this.setState({
statusMessage: this.getStatusMessage(),
});
};
shouldComponentUpdate(nextProps, nextState) {
shouldComponentUpdate(nextProps: IProps, nextState: IState): boolean {
if (
this.member_last_modified_time === undefined ||
this.member_last_modified_time < nextProps.member.getLastModifiedTime()
this.memberLastModifiedTime === undefined ||
this.memberLastModifiedTime < nextProps.member.getLastModifiedTime()
) {
return true;
}
if (
nextProps.member.user &&
(this.user_last_modified_time === undefined ||
this.user_last_modified_time < nextProps.member.user.getLastModifiedTime())
(this.userLastModifiedTime === undefined ||
this.userLastModifiedTime < nextProps.member.user.getLastModifiedTime())
) {
return true;
}
@ -181,18 +194,18 @@ export default class MemberTile extends React.Component {
return false;
}
onClick = e => {
private onClick = (): void => {
dis.dispatch({
action: Action.ViewUser,
member: this.props.member,
});
};
_getDisplayName() {
private getDisplayName(): string {
return this.props.member.name;
}
getPowerLabel() {
private getPowerLabel(): string {
return _t("%(userName)s (power %(powerLevelNumber)s)", {
userName: this.props.member.userId,
powerLevelNumber: this.props.member.powerLevel,
@ -200,11 +213,8 @@ export default class MemberTile extends React.Component {
}
render() {
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
const EntityTile = sdk.getComponent('rooms.EntityTile');
const member = this.props.member;
const name = this._getDisplayName();
const name = this.getDisplayName();
const presenceState = member.user ? member.user.presence : null;
let statusMessage = null;
@ -217,13 +227,13 @@ export default class MemberTile extends React.Component {
);
if (member.user) {
this.user_last_modified_time = member.user.getLastModifiedTime();
this.userLastModifiedTime = member.user.getLastModifiedTime();
}
this.member_last_modified_time = member.getLastModifiedTime();
this.memberLastModifiedTime = member.getLastModifiedTime();
const powerStatusMap = new Map([
[100, EntityTile.POWER_STATUS_ADMIN],
[50, EntityTile.POWER_STATUS_MODERATOR],
[100, PowerStatus.Admin],
[50, PowerStatus.Moderator],
]);
// Find the nearest power level with a badge

View File

@ -15,26 +15,23 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
// number of milliseconds ago this user was last active.
// zero = unknown
activeAgo?: number;
// if true, activeAgo is an approximation and "Now" should
// be shown instead
currentlyActive?: boolean;
// offline, online, etc
presenceState?: string;
}
@replaceableComponent("views.rooms.PresenceLabel")
export default class PresenceLabel extends React.Component {
static propTypes = {
// number of milliseconds ago this user was last active.
// zero = unknown
activeAgo: PropTypes.number,
// if true, activeAgo is an approximation and "Now" should
// be shown instead
currentlyActive: PropTypes.bool,
// offline, online, etc
presenceState: PropTypes.string,
};
export default class PresenceLabel extends React.Component<IProps> {
static defaultProps = {
activeAgo: -1,
presenceState: null,
@ -42,29 +39,29 @@ export default class PresenceLabel extends React.Component {
// Return duration as a string using appropriate time units
// XXX: This would be better handled using a culture-aware library, but we don't use one yet.
getDuration(time) {
private getDuration(time: number): string {
if (!time) return;
const t = parseInt(time / 1000);
const t = Math.round(time / 1000);
const s = t % 60;
const m = parseInt(t / 60) % 60;
const h = parseInt(t / (60 * 60)) % 24;
const d = parseInt(t / (60 * 60 * 24));
const m = Math.round(t / 60) % 60;
const h = Math.round(t / (60 * 60)) % 24;
const d = Math.round(t / (60 * 60 * 24));
if (t < 60) {
if (t < 0) {
return _t("%(duration)ss", {duration: 0});
return _t("%(duration)ss", { duration: 0 });
}
return _t("%(duration)ss", {duration: s});
return _t("%(duration)ss", { duration: s });
}
if (t < 60 * 60) {
return _t("%(duration)sm", {duration: m});
return _t("%(duration)sm", { duration: m });
}
if (t < 24 * 60 * 60) {
return _t("%(duration)sh", {duration: h});
return _t("%(duration)sh", { duration: h });
}
return _t("%(duration)sd", {duration: d});
return _t("%(duration)sd", { duration: d });
}
getPrettyPresence(presence, activeAgo, currentlyActive) {
private getPrettyPresence(presence: string, activeAgo: number, currentlyActive: boolean): string {
if (!currentlyActive && activeAgo !== undefined && activeAgo > 0) {
const duration = this.getDuration(activeAgo);
if (presence === "online") return _t("Online for %(duration)s", { duration: duration });

View File

@ -45,7 +45,6 @@ import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../context_menus/IconizedContextMenu";
import AccessibleButton from "../elements/AccessibleButton";
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
import CallHandler from "../../../CallHandler";
import SpaceStore, {ISuggestedRoom, SUGGESTED_ROOMS} from "../../../stores/SpaceStore";
import {showAddExistingRooms, showCreateNewRoom, showSpaceInvite} from "../../../utils/space";
import {replaceableComponent} from "../../../utils/replaceableComponent";
@ -103,38 +102,6 @@ interface ITagAestheticsMap {
[tagId: TagID]: ITagAesthetics;
}
// If we have no dialer support, we just show the create chat dialog
const dmOnAddRoom = (dispatcher?: Dispatcher<ActionPayload>) => {
(dispatcher || defaultDispatcher).dispatch({action: 'view_create_chat'});
};
// If we have dialer support, show a context menu so the user can pick between
// the dialer and the create chat dialog
const dmAddRoomContextMenu = (onFinished: () => void) => {
return <IconizedContextMenuOptionList first>
<IconizedContextMenuOption
label={_t("Start a Conversation")}
iconClassName="mx_RoomList_iconPlus"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onFinished();
defaultDispatcher.dispatch({action: "view_create_chat"});
}}
/>
<IconizedContextMenuOption
label={_t("Open dial pad")}
iconClassName="mx_RoomList_iconDialpad"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onFinished();
defaultDispatcher.fire(Action.OpenDialPad);
}}
/>
</IconizedContextMenuOptionList>;
};
const TAG_AESTHETICS: ITagAestheticsMap = {
[DefaultTagID.Invite]: {
sectionLabel: _td("Invites"),
@ -151,8 +118,9 @@ const TAG_AESTHETICS: ITagAestheticsMap = {
isInvite: false,
defaultHidden: false,
addRoomLabel: _td("Start chat"),
// Either onAddRoom or addRoomContextMenu are set depending on whether we
// have dialer support.
onAddRoom: (dispatcher?: Dispatcher<ActionPayload>) => {
(dispatcher || defaultDispatcher).dispatch({action: 'view_create_chat'});
},
},
[DefaultTagID.Untagged]: {
sectionLabel: _td("Rooms"),
@ -271,7 +239,6 @@ function customTagAesthetics(tagId: TagID): ITagAesthetics {
export default class RoomList extends React.PureComponent<IProps, IState> {
private dispatcherRef;
private customTagStoreRef;
private tagAesthetics: ITagAestheticsMap;
private roomStoreToken: fbEmitter.EventSubscription;
constructor(props: IProps) {
@ -282,10 +249,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
isNameFiltering: !!RoomListStore.instance.getFirstNameFilterCondition(),
suggestedRooms: SpaceStore.instance.suggestedRooms,
};
// shallow-copy from the template as we need to make modifications to it
this.tagAesthetics = objectShallowClone(TAG_AESTHETICS);
this.updateDmAddRoomAction();
}
public componentDidMount(): void {
@ -311,17 +274,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
});
};
private updateDmAddRoomAction() {
const dmTagAesthetics = objectShallowClone(TAG_AESTHETICS[DefaultTagID.DM]);
if (CallHandler.sharedInstance().getSupportsPstnProtocol()) {
dmTagAesthetics.addRoomContextMenu = dmAddRoomContextMenu;
} else {
dmTagAesthetics.onAddRoom = dmOnAddRoom;
}
this.tagAesthetics[DefaultTagID.DM] = dmTagAesthetics;
}
private onAction = (payload: ActionPayload) => {
if (payload.action === Action.ViewRoomDelta) {
const viewRoomDeltaPayload = payload as ViewRoomDeltaPayload;
@ -335,7 +287,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
});
}
} else if (payload.action === Action.PstnSupportUpdated) {
this.updateDmAddRoomAction();
this.updateLists();
}
};
@ -524,7 +475,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
const aesthetics: ITagAesthetics = isCustomTag(orderedTagId)
? customTagAesthetics(orderedTagId)
: this.tagAesthetics[orderedTagId];
: TAG_AESTHETICS[orderedTagId];
if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`);
// The cost of mounting/unmounting this component offsets the cost

View File

@ -15,19 +15,26 @@ limitations under the License.
*/
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import {_t} from "../../../languageHandler";
import { _t } from "../../../languageHandler";
import React, {ReactNode} from "react";
import {RecordingState, VoiceRecording} from "../../../voice/VoiceRecording";
import {
IRecordingUpdate,
RECORDING_PLAYBACK_SAMPLES,
RecordingState,
VoiceRecording,
} from "../../../voice/VoiceRecording";
import {Room} from "matrix-js-sdk/src/models/room";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import classNames from "classnames";
import LiveRecordingWaveform from "../voice_messages/LiveRecordingWaveform";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { arrayFastResample, arraySeed } from "../../../utils/arrays";
import { percentageOf } from "../../../utils/numbers";
import LiveRecordingClock from "../voice_messages/LiveRecordingClock";
import {VoiceRecordingStore} from "../../../stores/VoiceRecordingStore";
import { VoiceRecordingStore } from "../../../stores/VoiceRecordingStore";
import {UPDATE_EVENT} from "../../../stores/AsyncStore";
import RecordingPlayback from "../voice_messages/RecordingPlayback";
import {MsgType} from "matrix-js-sdk/src/@types/event";
import { MsgType } from "matrix-js-sdk/src/@types/event";
import Modal from "../../../Modal";
import ErrorDialog from "../dialogs/ErrorDialog";
import MediaDeviceHandler from "../../../MediaDeviceHandler";
@ -39,6 +46,8 @@ interface IProps {
interface IState {
recorder?: VoiceRecording;
recordingPhase?: RecordingState;
relHeights: number[];
seconds: number;
}
/**
@ -46,18 +55,58 @@ interface IState {
*/
@replaceableComponent("views.rooms.VoiceRecordComposerTile")
export default class VoiceRecordComposerTile extends React.PureComponent<IProps, IState> {
private waveform: number[] = [];
private seconds = 0;
private scheduledAnimationFrame = false;
public constructor(props) {
super(props);
this.state = {
recorder: null, // no recording started by default
seconds: 0,
relHeights: arraySeed(0, RECORDING_PLAYBACK_SAMPLES),
};
}
public componentDidUpdate(prevProps, prevState) {
if (!prevState.recorder && this.state.recorder) {
this.state.recorder.liveData.onUpdate(this.onRecordingUpdate);
}
}
public async componentWillUnmount() {
await VoiceRecordingStore.instance.disposeRecording();
}
private onRecordingUpdate = (update: IRecordingUpdate): void => {
this.waveform = update.waveform;
this.seconds = update.timeSeconds;
if (this.scheduledAnimationFrame) {
return;
}
this.scheduledAnimationFrame = true;
// The audio recorder flushes data faster than the screen refresh rate
// Using requestAnimationFrame makes sure that we only flush the data
// to react once per tick to avoid unneeded work.
requestAnimationFrame(() => {
// The waveform and the downsample target are pretty close, so we should be fine to
// do this, despite the docs on arrayFastResample.
const bars = arrayFastResample(Array.from(this.waveform), RECORDING_PLAYBACK_SAMPLES);
this.setState({
// The incoming data is between zero and one, but typically even screaming into a
// microphone won't send you over 0.6, so we artificially adjust the gain for the
// waveform. This results in a slightly more cinematic/animated waveform for the
// user.
relHeights: bars.map(b => percentageOf(b, 0, 0.50)),
seconds: this.seconds,
});
this.scheduledAnimationFrame = false;
});
}
// called by composer
public async send() {
if (!this.state.recorder) {
@ -65,12 +114,13 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
}
await this.state.recorder.stop();
const mxc = await this.state.recorder.upload();
const upload = await this.state.recorder.upload(this.props.room.roomId);
MatrixClientPeg.get().sendMessage(this.props.room.roomId, {
"body": "Voice message",
//"msgtype": "org.matrix.msc2516.voice",
"msgtype": MsgType.Audio,
"url": mxc,
"url": upload.mxc,
"file": upload.encrypted,
"info": {
duration: Math.round(this.state.recorder.durationSeconds * 1000),
mimetype: this.state.recorder.contentType,
@ -81,7 +131,8 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
// https://github.com/matrix-org/matrix-doc/pull/3245
"org.matrix.msc1767.text": "Voice message",
"org.matrix.msc1767.file": {
url: mxc,
url: upload.mxc,
file: upload.encrypted,
name: "Voice message.ogg",
mimetype: this.state.recorder.contentType,
size: this.state.recorder.contentLength,

View File

@ -33,6 +33,9 @@ export enum JoinRule {
Public = "public",
Knock = "knock",
Invite = "invite",
/**
* @deprecated Reserved. Should not be used.
*/
Private = "private",
}

View File

@ -129,7 +129,9 @@ const SpaceCreateMenu = ({ onFinished }) => {
events_default: 100,
...Visibility.Public ? { invite: 0 } : {},
},
room_alias_name: alias ? alias.substr(1, alias.indexOf(":") - 1) : undefined,
room_alias_name: visibility === Visibility.Public && alias
? alias.substr(1, alias.indexOf(":") - 1)
: undefined,
topic,
},
spinner: false,

View File

@ -62,9 +62,9 @@ const SpaceSettingsVisibilityTab = ({ matrixClient: cli, space }: IProps) => {
const userId = cli.getUserId();
const [visibility, setVisibility] = useLocalEcho<SpaceVisibility>(
() => space.getJoinRule() === JoinRule.Private ? SpaceVisibility.Private : SpaceVisibility.Unlisted,
() => space.getJoinRule() === JoinRule.Invite ? SpaceVisibility.Private : SpaceVisibility.Unlisted,
visibility => cli.sendStateEvent(space.roomId, EventType.RoomJoinRules, {
join_rule: visibility === SpaceVisibility.Unlisted ? JoinRule.Public : JoinRule.Private,
join_rule: visibility === SpaceVisibility.Unlisted ? JoinRule.Public : JoinRule.Invite,
}, ""),
() => setError(_t("Failed to update the visibility of this space")),
);

View File

@ -50,7 +50,7 @@ const GenericToast: React.FC<XOR<IPropsExtended, IProps>> = ({
{detailContent}
</div>
<div className="mx_Toast_buttons" aria-live="off">
{onReject && rejectLabel && <AccessibleButton kind="danger" onClick={onReject}>
{onReject && rejectLabel && <AccessibleButton kind="danger_outline" onClick={onReject}>
{ rejectLabel }
</AccessibleButton> }
<AccessibleButton onClick={onAccept} kind="primary">

View File

@ -15,9 +15,9 @@ limitations under the License.
*/
import React from "react";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
export interface IProps {
seconds: number;
}

View File

@ -1,12 +1,9 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,12 +12,16 @@ limitations under the License.
*/
import React from "react";
import {IRecordingUpdate, VoiceRecording} from "../../../voice/VoiceRecording";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import Clock from "./Clock";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { MarkedExecution } from "../../../utils/MarkedExecution";
import {
IRecordingUpdate,
VoiceRecording,
} from "../../../voice/VoiceRecording";
interface IProps {
recorder: VoiceRecording;
recorder?: VoiceRecording;
}
interface IState {
@ -32,16 +33,31 @@ interface IState {
*/
@replaceableComponent("views.voice_messages.LiveRecordingClock")
export default class LiveRecordingClock extends React.PureComponent<IProps, IState> {
public constructor(props) {
super(props);
private seconds = 0;
private scheduledUpdate = new MarkedExecution(
() => this.updateClock(),
() => requestAnimationFrame(() => this.scheduledUpdate.trigger()),
);
this.state = {seconds: 0};
this.props.recorder.liveData.onUpdate(this.onRecordingUpdate);
constructor(props) {
super(props);
this.state = {
seconds: 0,
};
}
private onRecordingUpdate = (update: IRecordingUpdate) => {
this.setState({seconds: update.timeSeconds});
};
componentDidMount() {
this.props.recorder.liveData.onUpdate((update: IRecordingUpdate) => {
this.seconds = update.timeSeconds;
this.scheduledUpdate.mark();
});
}
private updateClock() {
this.setState({
seconds: this.seconds,
});
}
public render() {
return <Clock seconds={this.state.seconds} />;

View File

@ -1,12 +1,9 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,18 +12,20 @@ limitations under the License.
*/
import React from "react";
import {IRecordingUpdate, RECORDING_PLAYBACK_SAMPLES, VoiceRecording} from "../../../voice/VoiceRecording";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import {arrayFastResample, arraySeed} from "../../../utils/arrays";
import {percentageOf} from "../../../utils/numbers";
import Waveform from "./Waveform";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { MarkedExecution } from "../../../utils/MarkedExecution";
import {
IRecordingUpdate,
VoiceRecording,
} from "../../../voice/VoiceRecording";
interface IProps {
recorder: VoiceRecording;
recorder?: VoiceRecording;
}
interface IState {
heights: number[];
waveform: number[];
}
/**
@ -34,27 +33,37 @@ interface IState {
*/
@replaceableComponent("views.voice_messages.LiveRecordingWaveform")
export default class LiveRecordingWaveform extends React.PureComponent<IProps, IState> {
public constructor(props) {
super(props);
this.state = {heights: arraySeed(0, RECORDING_PLAYBACK_SAMPLES)};
this.props.recorder.liveData.onUpdate(this.onRecordingUpdate);
}
private onRecordingUpdate = (update: IRecordingUpdate) => {
// The waveform and the downsample target are pretty close, so we should be fine to
// do this, despite the docs on arrayFastResample.
const bars = arrayFastResample(Array.from(update.waveform), RECORDING_PLAYBACK_SAMPLES);
this.setState({
// The incoming data is between zero and one, but typically even screaming into a
// microphone won't send you over 0.6, so we artificially adjust the gain for the
// waveform. This results in a slightly more cinematic/animated waveform for the
// user.
heights: bars.map(b => percentageOf(b, 0, 0.50)),
});
public static defaultProps = {
progress: 1,
};
private waveform: number[] = [];
private scheduledUpdate = new MarkedExecution(
() => this.updateWaveform(),
() => requestAnimationFrame(() => this.scheduledUpdate.trigger()),
);
constructor(props) {
super(props);
this.state = {
waveform: [],
};
}
componentDidMount() {
this.props.recorder.liveData.onUpdate((update: IRecordingUpdate) => {
this.waveform = update.waveform;
this.scheduledUpdate.mark();
});
}
private updateWaveform() {
this.setState({
waveform: this.waveform,
})
}
public render() {
return <Waveform relHeights={this.state.heights} />;
return <Waveform relHeights={this.state.waveform} />;
}
}

View File

@ -15,10 +15,10 @@ limitations under the License.
*/
import React from "react";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import classNames from "classnames";
interface IProps {
export interface IProps {
relHeights: number[]; // relative heights (0-1)
progress: number; // percent complete, 0-1, default 100%
}
@ -34,16 +34,19 @@ interface IState {
* For CSS purposes, a mx_Waveform_bar_100pct class is added when the bar should be
* "filled", as a demonstration of the progress property.
*/
import { CSSProperties } from "react";
export interface WaveformCSSProperties extends CSSProperties {
'--barHeight': number;
}
@replaceableComponent("views.voice_messages.Waveform")
export default class Waveform extends React.PureComponent<IProps, IState> {
public static defaultProps = {
progress: 1,
};
public constructor(props) {
super(props);
}
public render() {
return <div className='mx_Waveform'>
{this.props.relHeights.map((h, i) => {
@ -53,7 +56,9 @@ export default class Waveform extends React.PureComponent<IProps, IState> {
'mx_Waveform_bar': true,
'mx_Waveform_bar_100pct': isCompleteBar,
});
return <span key={i} style={{height: (h * 100) + '%'}} className={classes} />;
return <span key={i} style={{
"--barHeight": h,
} as WaveformCSSProperties} className={classes} />;
})}
</div>;
}

View File

@ -27,6 +27,11 @@ export interface SetRightPanelPhasePayload extends ActionPayload {
phase: RightPanelPhases;
refireParams?: SetRightPanelPhaseRefireParams;
/**
* By default SetRightPanelPhase can close the panel, this allows overriding that behaviour
*/
allowClose?: boolean;
}
export interface SetRightPanelPhaseRefireParams {

View File

@ -3298,5 +3298,23 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Vyzkoušejte jiná slova nebo zkontrolujte překlepy. Některé výsledky nemusí být viditelné, protože jsou soukromé a potřebujete k nim pozvánku.",
"No results for \"%(query)s\"": "Žádné výsledky pro \"%(query)s\"",
"The user you called is busy.": "Volaný uživatel je zaneprázdněn.",
"User Busy": "Uživatel zaneprázdněn"
"User Busy": "Uživatel zaneprázdněn",
"We're working on this as part of the beta, but just want to let you know.": "Pracujeme na tom v rámci beta verze, ale jen vás o tom chceme informovat.",
"Teammates might not be able to view or join any private rooms you make.": "Je možné, že spolupracovníci nebudou moci zobrazit soukromé místnosti, které jste vytvořili, nebo se k nim připojit.",
"Or send invite link": "Nebo pošlete pozvánku",
"If you can't see who youre looking for, send them your invite link below.": "Pokud jste nenašli, koho hledáte, pošlete mu odkaz na pozvánku níže.",
"Some suggestions may be hidden for privacy.": "Některé návrhy mohou být z důvodu ochrany soukromí skryty.",
"Search for rooms or people": "Hledat místnosti nebo osoby",
"Message preview": "Náhled zprávy",
"Forward message": "Přeposlat zprávu",
"Open link": "Otevřít odkaz",
"Sent": "Odesláno",
"You don't have permission to do this": "K tomu nemáte povolení",
"Error - Mixed content": "Chyba - Smíšený obsah",
"Error loading Widget": "Chyba při načítání widgetu",
"Pinned messages": "Připnuté zprávy",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Pokud máte oprávnění, otevřete nabídku na libovolné zprávě a výběrem možnosti <b>Připnout</b> je sem vložte.",
"Nothing pinned, yet": "Zatím není nic připnuto",
"End-to-end encryption isn't enabled": "Není povoleno koncové šifrování",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "Vaše soukromé zprávy jsou obvykle šifrované, ale tato místnost není. Obvykle je to způsobeno nepodporovaným zařízením nebo použitou metodou, například emailovými pozvánkami. <a>Zapněte šifrování v nastavení.</a>"
}

View File

@ -709,7 +709,7 @@
"Error saving email notification preferences": "Fehler beim Speichern der E-Mail-Benachrichtigungseinstellungen",
"Tuesday": "Dienstag",
"Enter keywords separated by a comma:": "Gib die Schlüsselwörter durch einen Beistrich getrennt ein:",
"Forward Message": "Nachricht weiterleiten",
"Forward Message": "Weiterleiten",
"You have successfully set a password and an email address!": "Du hast erfolgreich ein Passwort und eine E-Mail-Adresse gesetzt!",
"Remove %(name)s from the directory?": "Soll der Raum %(name)s aus dem Verzeichnis entfernt werden?",
"%(brand)s uses many advanced browser features, some of which are not available or experimental in your current browser.": "%(brand)s nutzt zahlreiche fortgeschrittene Browser-Funktionen, die teilweise in deinem aktuell verwendeten Browser noch nicht verfügbar sind oder sich noch im experimentellen Status befinden.",
@ -1107,7 +1107,7 @@
"Security & Privacy": "Sicherheit",
"Encryption": "Verschlüsselung",
"Once enabled, encryption cannot be disabled.": "Sobald du die Verschlüsselung aktivierst, kann du sie nicht mehr deaktivieren.",
"Encrypted": "Verschlüsselt",
"Encrypted": "Verschlüsseln",
"Ignored users": "Blockierte Benutzer",
"Key backup": "Schlüsselsicherung",
"Gets or sets the room topic": "Raumthema anzeigen oder ändern",
@ -1211,7 +1211,7 @@
"Send messages": "Nachrichten senden",
"Invite users": "Benutzer einladen",
"Change settings": "Einstellungen ändern",
"Kick users": "Benutzer rauswerfen",
"Kick users": "Benutzer kicken",
"Ban users": "Benutzer verbannen",
"Remove messages": "Nachrichten löschen",
"Notify everyone": "Jeden benachrichtigen",
@ -1321,7 +1321,7 @@
"Disconnect from the identity server <idserver />?": "Verbindung zum Identitätsserver <idserver /> trennen?",
"Add Email Address": "E-Mail-Adresse hinzufügen",
"Add Phone Number": "Telefonnummer hinzufügen",
"Changes the avatar of the current room": "Ändert den Avatar für diesen Raum",
"Changes the avatar of the current room": "Ändert den Avatar des Raums",
"Deactivate account": "Benutzerkonto deaktivieren",
"Show previews/thumbnails for images": "Vorschauen für Bilder",
"View": "Vorschau",
@ -1388,7 +1388,7 @@
"Backup key stored: ": "Backup Schlüssel gespeichert: ",
"Clear notifications": "Benachrichtigungen löschen",
"Disconnect from the identity server <current /> and connect to <new /> instead?": "Vom Identitätsserver <current /> trennen, und stattdessen eine Verbindung zu <new /> aufbauen?",
"The identity server you have chosen does not have any terms of service.": "Der von dir gewählte Identitätsserver hat keine Nutzungsbedingungen.",
"The identity server you have chosen does not have any terms of service.": "Der von dir gewählte Identitätsserver gibt keine Nutzungsbedingungen an.",
"Disconnect identity server": "Verbindung zum Identitätsserver trennen",
"contact the administrators of identity server <idserver />": "Administration des Identitätsservers <idserver /> kontaktieren",
"wait and try again later": "warte und versuche es später erneut",
@ -1634,8 +1634,8 @@
"Show rooms with unread notifications first": "Räume mit ungelesenen Benachrichtigungen zuerst zeigen",
"Show shortcuts to recently viewed rooms above the room list": "Kürzlich besuchte Räume anzeigen",
"Use Single Sign On to continue": "Einmalanmeldung zum Fortfahren nutzen",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Bestätige das Hinzufügen dieser E-Mail-Adresse durch Single Sign-on, um deine Identität nachzuweisen.",
"Single Sign On": "Einmalanmeldung",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Bestätige die neue E-Mail-Adresse mit Single-Sign-On, um deine Identität nachzuweisen.",
"Single Sign On": "Single Sign-on",
"Confirm adding email": "Hinzugefügte E-Mail-Addresse bestätigen",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Bestätige die hinzugefügte Telefonnummer, indem du deine Identität mittels der Einmalanmeldung nachweist.",
"Click the button below to confirm adding this phone number.": "Klicke unten die Schaltfläche, um die hinzugefügte Telefonnummer zu bestätigen.",
@ -1723,7 +1723,7 @@
"Uploaded sound": "Hochgeladener Ton",
"Upgrade this room to the recommended room version": "Aktualisiere diesen Raum auf die empfohlene Raumversion",
"this room": "Dieser Raum",
"View older messages in %(roomName)s.": "Zeige alte Nachrichten in %(roomName)s.",
"View older messages in %(roomName)s.": "Alte Nachrichten in %(roomName)s anzeigen.",
"Send a bug report with logs": "Einen Fehlerbericht mit der Protokolldatei senden",
"Verify all your sessions to ensure your account & messages are safe": "Verifiziere alle deine Sitzungen, um dein Konto und deine Nachrichten zu schützen",
"Verify your other session using one of the options below.": "Verifiziere deine andere Sitzung mit einer der folgenden Optionen.",
@ -3102,7 +3102,7 @@
"Your public space": "Dein öffentlicher Space",
"You can change this later": "Du kannst die Sichtbarkeit später ändern",
"Invite only, best for yourself or teams": "Nur Eingeladene können beitreten - am besten für dich selbst oder Teams",
"Open space for anyone, best for communities": "Öffne den Space für alle - am Besten für Communities",
"Open space for anyone, best for communities": "Öffne den Space für alle - am besten für Communities",
"Private": "Privat",
"Public": "Öffentlich",
"Spaces are new ways to group rooms and people. To join an existing space youll need an invite": "Spaces sind ein neuer Weg Räume und Leute zu gruppieren. Um einen bestehenden Space zu betreten brauchst du eine Einladung",
@ -3219,7 +3219,7 @@
"Warn before quitting": "Vor Beenden warnen",
"Spell check dictionaries": "Wörterbücher für Rechtschreibprüfung",
"Space options": "Matrix-Space-Optionen",
"Manage & explore rooms": "Räume entdecken und verwalten",
"Manage & explore rooms": "Räume erkunden und verwalten",
"unknown person": "unbekannte Person",
"Send and receive voice messages (in development)": "Sprachnachrichten senden und empfangen (in der Entwicklung)",
"Check your devices": "Überprüfe deine Sitzungen",
@ -3242,7 +3242,7 @@
"Confirm abort of host creation": "Bestätige das Beenden der Host-Erstellung",
"Are you sure you wish to abort creation of the host? The process cannot be continued.": "Soll die Host-Erstellung wirklich beendet werden? Dieser Prozess kann nicht wieder fortgesetzt werden.",
"Invite to just this room": "Nur in diesen Raum einladen",
"Consult first": "Konsultiere zuerst",
"Consult first": "Zuerst Anfragen",
"Reset event store?": "Ereignisspeicher zurück setzen?",
"You most likely do not want to reset your event index store": "Es ist wahrscheinlich, dass du den Ereignis-Indexspeicher nicht zurück setzen möchtest",
"If you do, please note that none of your messages will be deleted, but the search experience might be degraded for a few momentswhilst the index is recreated": "Falls du dies tust, werden keine deiner Nachrichten gelöscht. Allerdings wird die Such-Funktion eine Weile lang schlecht funktionieren, bis der Index wieder hergestellt ist",
@ -3256,7 +3256,7 @@
"You are the only person here. If you leave, no one will be able to join in the future, including you.": "Du bist die einzige Person hier. Wenn du ihn jetzt verlässt, ist er für immer verloren (eine lange Zeit).",
"Edit settings relating to your space.": "Einstellungen vom Space bearbeiten.",
"Please choose a strong password": "Bitte gib ein sicheres Passwort ein",
"If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.": "Wenn du alles zurücksetzt, gehen alle verifizierten Anmeldungen, Benutzer und verschlüsselte Nachrichten verloren.",
"If you reset everything, you will restart with no trusted sessions, no trusted users, and might not be able to see past messages.": "Wenn du alles zurücksetzt, gehen alle verifizierten Anmeldungen, Benutzer und vergangenen Nachrichten verloren.",
"Only do this if you have no other device to complete verification with.": "Verwende es nur, wenn du kein Gerät, mit dem du dich verifizieren, kannst bei dir hast.",
"Reset everything": "Alles zurücksetzen",
"Forgotten or lost all recovery methods? <a>Reset all</a>": "Hast du alle Wiederherstellungsmethoden vergessen? <a>Setze sie hier zurück</a>",
@ -3282,12 +3282,12 @@
"If you do, please note that none of your messages will be deleted, but the search experience might be degraded for a few moments whilst the index is recreated": "Falls du es wirklich willst: Es werden keine Nachrichten gelöscht. Außerdem wird die Suche, während der Index erstellt wird, etwas langsamer sein",
"%(count)s members including %(commaSeparatedMembers)s|other": "%(count)s Mitglieder inklusive %(commaSeparatedMembers)s",
"Including %(commaSeparatedMembers)s": "Inklusive%(commaSeparatedMembers)s",
"Consulting with %(transferTarget)s. <a>Transfer to %(transferee)s</a>": "Beratung mit %(transferTarget)s. <a>Übertragung zu %(transferee)s</a>",
"Consulting with %(transferTarget)s. <a>Transfer to %(transferee)s</a>": "%(transferTarget)s wird angefragt. <a>Übertragung zu %(transferee)s</a>",
"Play": "Abspielen",
"Pause": "Pause",
"What do you want to organise?": "Was willst du organisieren?",
"Enter your Security Phrase a second time to confirm it.": "Gib dein Kennwort ein zweites Mal zur Bestätigung ein.",
"Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "Wähle Räume oder Konversationen die Du hinzufügen möchtest. Dieser Bereich ist nur für Dich, niemand wird informiert. Du kannst später mehr hinzufügen.",
"Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "Wähle Räume oder Konversationen die du hinzufügen willst. Dieser Space ist nur für dich, niemand wird informiert. Du kannst später mehr hinzufügen.",
"Filter all spaces": "Alle Spaces durchsuchen",
"Delete recording": "Aufnahme löschen",
"Stop the recording": "Aufnahme stoppen",
@ -3302,7 +3302,7 @@
"Join the beta": "Beta beitreten",
"Leave the beta": "Beta verlassen",
"Beta": "Beta",
"Tap for more info": "Klicke für mehr Infos",
"Tap for more info": "Für mehr Infos hier klicken",
"Spaces is a beta feature": "Spaces sind noch in der Entwicklung und möglicherweise instabil",
"Want to add a new room instead?": "Willst du einen neuen Raum hinzufügen?",
"Adding rooms... (%(progress)s out of %(count)s)|one": "Raum wird hinzugefügt...",
@ -3349,8 +3349,28 @@
"Currently joining %(count)s rooms|other": "Betrete %(count)s Räume",
"Go to my space": "Zu meinem Space",
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Überprüfe auf Tippfehler oder verwende andere Suchbegriffe. Beachte, dass Ergebnisse aus privaten Räumen, in die du nicht eingeladen wurdest, nicht angezeigt werden.",
"See when people join, leave, or are invited to this room": "Anzeigen, wenn Leute eingeladen werden oder den Raum betreten und verlassen",
"See when people join, leave, or are invited to this room": "Anzeigen, wenn Leute eingeladen werden, den Raum betreten oder verlassen",
"The user you called is busy.": "Der angerufene Benutzer ist momentan beschäftigt.",
"User Busy": "Benutzer beschäftigt",
"No results for \"%(query)s\"": "Keine Ergebnisse für \"%(query)s\""
"No results for \"%(query)s\"": "Keine Ergebnisse für \"%(query)s\"",
"Some suggestions may be hidden for privacy.": "Um deine Privatsphäre zu schützen, werden einige Vorschläge möglicherweise ausgeblendet.",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "Dieser Raum ist offenbar nicht verschlüsselt. Das kann an einem veralteten Gerät oder an manchen Verfahren wie E-Mail-Einladungen liegen. <a>Verschlüsselung aktivieren.</a>",
"We're working on this as part of the beta, but just want to let you know.": "Dies ist noch Teil der Beta, wir wollten dir es aber schon jetzt zeigen.",
"Or send invite link": "Oder versende einen Einladungslink",
"If you can't see who youre looking for, send them your invite link below.": "Niemanden gefunden? Sende ihnen stattdessen einen Einladungslink.",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Du kannst, sofern du die Berechtigung dazu hast, Nachrichten in ihrem Menü <b>hier anpinnen</b>.",
"Search for rooms or people": "Räume oder Leute suchen",
"Forward message": "Nachricht weiterleiten",
"Open link": "Link öffnen",
"Sent": "Gesendet",
"You don't have permission to do this": "Du bist dazu nicht berechtigt",
"Error loading Widget": "Fehler beim Laden des Widgets",
"Pinned messages": "Angeheftete Nachrichten",
"Nothing pinned, yet": "Es ist nichts angepinnt. Noch nicht.",
"End-to-end encryption isn't enabled": "Ende-zu-Ende-Verschlüsselung ist deaktiviert",
"See when people join, leave, or are invited to your active room": "Anzeigen, wenn Leute den aktuellen Raum betreten, verlassen oder in ihn eingeladen werden",
"Teammates might not be able to view or join any private rooms you make.": "Mitglieder werden private Räume möglicherweise weder sehen noch betreten können.",
"Error - Mixed content": "Fehler - Uneinheitlicher Inhalt",
"Kick, ban, or invite people to your active room, and make you leave": "Den aktiven Raum verlassen, Leute einladen, kicken oder bannen",
"Kick, ban, or invite people to this room, and make you leave": "Diesen Raum verlassen, Leute einladen, kicken oder bannen"
}

View File

@ -562,6 +562,7 @@
"%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s made future room history visible to unknown (%(visibility)s).",
"%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s changed the power level of %(powerLevelDiffText)s.",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s",
"%(senderName)s changed the <a>pinned messages</a> for the room.": "%(senderName)s changed the <a>pinned messages</a> for the room.",
"%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.",
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
"%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s",
@ -1581,8 +1582,6 @@
"Search": "Search",
"Voice call": "Voice call",
"Video call": "Video call",
"Start a Conversation": "Start a Conversation",
"Open dial pad": "Open dial pad",
"Invites": "Invites",
"Favourites": "Favourites",
"People": "People",
@ -2051,6 +2050,10 @@
"%(severalUsers)smade no changes %(count)s times|one": "%(severalUsers)smade no changes",
"%(oneUser)smade no changes %(count)s times|other": "%(oneUser)smade no changes %(count)s times",
"%(oneUser)smade no changes %(count)s times|one": "%(oneUser)smade no changes",
"%(severalUsers)schanged the server ACLs %(count)s times|other": "%(severalUsers)schanged the server ACLs %(count)s times",
"%(severalUsers)schanged the server ACLs %(count)s times|one": "%(severalUsers)schanged the server ACLs",
"%(oneUser)schanged the server ACLs %(count)s times|other": "%(oneUser)schanged the server ACLs %(count)s times",
"%(oneUser)schanged the server ACLs %(count)s times|one": "%(oneUser)schanged the server ACLs",
"Power level": "Power level",
"Custom level": "Custom level",
"QR Code": "QR Code",
@ -2525,14 +2528,12 @@
"Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?",
"Unable to reject invite": "Unable to reject invite",
"Resend %(unsentCount)s reaction(s)": "Resend %(unsentCount)s reaction(s)",
"Forward Message": "Forward Message",
"Unpin Message": "Unpin Message",
"Pin Message": "Pin Message",
"Unhide Preview": "Unhide Preview",
"Share Permalink": "Share Permalink",
"Share Message": "Share Message",
"Forward": "Forward",
"View source": "View source",
"Show preview": "Show preview",
"Source URL": "Source URL",
"Collapse Reply Thread": "Collapse Reply Thread",
"Collapse reply thread": "Collapse reply thread",
"Report": "Report",
"Clear status": "Clear status",
"Update status": "Update status",
"Set status": "Set status",
@ -2661,6 +2662,7 @@
"Explore Public Rooms": "Explore Public Rooms",
"Create a Group Chat": "Create a Group Chat",
"Upgrade to %(hostSignupBrand)s": "Upgrade to %(hostSignupBrand)s",
"Open dial pad": "Open dial pad",
"Failed to reject invitation": "Failed to reject invitation",
"Cannot create rooms in this community": "Cannot create rooms in this community",
"You do not have permission to create rooms in this community.": "You do not have permission to create rooms in this community.",
@ -2767,6 +2769,7 @@
"<inviter/> invites you": "<inviter/> invites you",
"To view %(spaceName)s, turn on the <a>Spaces beta</a>": "To view %(spaceName)s, turn on the <a>Spaces beta</a>",
"To join %(spaceName)s, turn on the <a>Spaces beta</a>": "To join %(spaceName)s, turn on the <a>Spaces beta</a>",
"To view %(spaceName)s, you need an invite": "To view %(spaceName)s, you need an invite",
"Welcome to <name/>": "Welcome to <name/>",
"Random": "Random",
"Support": "Support",

View File

@ -82,7 +82,7 @@
"Fill screen": "Llenar pantalla",
"Filter room members": "Filtrar miembros de la sala",
"Forget room": "Olvidar sala",
"For security, this session has been signed out. Please sign in again.": "Por seguridad, esta sesión ha sido cerrada. Por favor inicia sesión nuevamente.",
"For security, this session has been signed out. Please sign in again.": "Esta sesión ha sido cerrada. Por favor, inicia sesión de nuevo.",
"%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s de %(fromPowerLevel)s a %(toPowerLevel)s",
"Guests cannot join this room even if explicitly invited.": "Los invitados no pueden unirse a esta sala incluso si se les invita explícitamente.",
"Hangup": "Colgar",
@ -168,7 +168,7 @@
"Search": "Buscar",
"Search failed": "Falló la búsqueda",
"Seen by %(userName)s at %(dateTime)s": "Visto por %(userName)s el %(dateTime)s",
"Send Reset Email": "Enviar correo electrónico de restauración",
"Send Reset Email": "Enviar correo de restauración",
"%(senderDisplayName)s sent an image.": "%(senderDisplayName)s envió una imagen.",
"%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s invitó a %(targetDisplayName)s a unirse a la sala.",
"Server error": "Error del servidor",
@ -2021,7 +2021,7 @@
"Your Matrix account on <underlinedServerName />": "Su cuenta de Matrix en <underlinedServerName />",
"No identity server is configured: add one in server settings to reset your password.": "No hay ningún servidor de identidad configurado: añada uno en la configuración del servidor para poder restablecer su contraseña.",
"Sign in instead": "Iniciar sesión",
"A verification email will be sent to your inbox to confirm setting your new password.": "Se enviará un correo electrónico de verificación a su bandeja de entrada para confirmar la configuración de su nueva contraseña.",
"A verification email will be sent to your inbox to confirm setting your new password.": "Te enviaremos un correo electrónico de verificación para cambiar tu contraseña.",
"Your password has been reset.": "Su contraseña ha sido restablecida.",
"You have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, sign in again on each device.": "Ha cerrado todas las sesiones y ya no recibirá más notificaciones push. Para volver a activar las notificaciones, inicie sesión de nuevo en cada dispositivo.",
"Set a new password": "Elegir una nueva contraseña",
@ -3321,5 +3321,23 @@
"Currently joining %(count)s rooms|other": "Entrando en %(count)s salas",
"No results for \"%(query)s\"": "Ningún resultado para «%(query)s»",
"The user you called is busy.": "La persona a la que has llamado está ocupada.",
"User Busy": "Persona ocupada"
"User Busy": "Persona ocupada",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "Normalmente tus mensajes privados están cifrados, pero esta sala no lo está. Esto puede ser debido a un dispositivo o método no soportado, como las invitaciones por correo. <a>Activa el cifrado en ajustes</a>.",
"End-to-end encryption isn't enabled": "El cifrado de extremo a extremo no está activado",
"If you can't see who youre looking for, send them your invite link below.": "Si no encuentras abajo a quien buscas, envíale tu enlace de invitación.",
"Teammates might not be able to view or join any private rooms you make.": "Las personas de tu equipo no podrán ver o unirse a ninguna sala privada que crees.",
"We're working on this as part of the beta, but just want to let you know.": "Estamos trabajando en ello como parte de la beta, pero te lo queríamos contar.",
"Or send invite link": "O envía un enlace de invitación",
"Some suggestions may be hidden for privacy.": "Puede que se hayan ocultado algunas sugerencias por motivos de privacidad.",
"Search for rooms or people": "Busca salas o gente",
"Message preview": "Vista previa del mensaje",
"Forward message": "Reenviar mensaje",
"Open link": "Abrir enlace",
"Sent": "Enviado",
"You don't have permission to do this": "No tienes permisos para hacer eso",
"Error - Mixed content": "Error - Contenido mezclado",
"Error loading Widget": "Error al cargar el widget",
"Pinned messages": "Mensajes fijados",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Si tienes permisos, abre el menú de cualquier mensaje y selecciona <b>Fijar</b> para colocarlo aquí.",
"Nothing pinned, yet": "Nada fijado, todavía"
}

View File

@ -126,7 +126,7 @@
"Explore Public Rooms": "Sirvi avalikke jututubasid",
"Explore": "Uuri",
"Filter rooms…": "Filtreeri jututubasid…",
"Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Liites kokku kasutajaid ja jututubasid loo oma kogukond! Loo kogukonna koduleht, et märkida oma koht Matrix'i universumis.",
"Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Liites kokku kasutajaid ja jututubasid loo oma kogukond! Kogukonna kodulehega tähistad oma koha Matrix'i universumis.",
"Explore rooms": "Uuri jututubasid",
"If you've joined lots of rooms, this might take a while": "Kui oled liitunud paljude jututubadega, siis see võib natuke aega võtta",
"If disabled, messages from encrypted rooms won't appear in search results.": "Kui see seadistus pole kasutusel, siis krüptitud jututubade sõnumeid otsing ei vaata.",
@ -679,7 +679,7 @@
"%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s muutis oma kuvatava nime %(displayName)s-ks.",
"%(senderName)s set their display name to %(displayName)s.": "%(senderName)s määras oma kuvatava nime %(displayName)s-ks.",
"%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s eemaldas oma kuvatava nime (%(oldDisplayName)s).",
"%(senderName)s removed their profile picture.": "%(senderName)s eemaldas om profiilipildi.",
"%(senderName)s removed their profile picture.": "%(senderName)s eemaldas oma profiilipildi.",
"%(senderName)s changed their profile picture.": "%(senderName)s muutis oma profiilipilti.",
"%(senderName)s set a profile picture.": "%(senderName)s määras oma profiilipildi.",
"%(name)s (%(userId)s)": "%(name)s (%(userId)s)",
@ -2218,7 +2218,7 @@
"%(brand)s can't securely cache encrypted messages locally while running in a web browser. Use <desktopLink>%(brand)s Desktop</desktopLink> for encrypted messages to appear in search results.": "%(brand)s ei võimalda veebibrauseris töötades krüptitud sõnumeid turvaliselt puhverdada. Selleks, et krüptitud sõnumeid saaks otsida, kasuta <desktopLink>%(brand)s Desktop</desktopLink> rakendust Matrix'i kliendina.",
"Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Krüptitud sõnumid kasutavad läbivat krüptimist. Ainult sinul ja saaja(te)l on võtmed selliste sõnumite lugemiseks.",
"Unable to load key backup status": "Võtmete varunduse oleku laadimine ei õnnestunud",
"Restore from Backup": "Taasta varundusest",
"Restore from Backup": "Taasta varukoopiast",
"This session is backing up your keys. ": "See sessioon varundab sinu krüptovõtmeid. ",
"This session is <b>not backing up your keys</b>, but you do have an existing backup you can restore from and add to going forward.": "See sessioon <b>ei varunda sinu krüptovõtmeid</b>, aga sul on olemas varundus, millest saad taastada ning millele saad võtmeid lisada.",
"Success": "Õnnestus",
@ -2229,7 +2229,7 @@
"Deactivate Account": "Deaktiveeri konto",
"Discovery": "Leia kasutajaid",
"Deactivate account": "Deaktiveeri kasutajakonto",
"For help with using %(brand)s, click <a>here</a>.": "Kui otsid lisateavet %(brand)s kasutamise kohta, palun vaata <a>siia</a>.",
"For help with using %(brand)s, click <a>here</a>.": "Kui otsid lisateavet %(brand)s'i kasutamise kohta, palun vaata <a>siia</a>.",
"Add users and servers you want to ignore here. Use asterisks to have %(brand)s match any characters. For example, <code>@bot:*</code> would ignore all users that have the name 'bot' on any server.": "Lisa siia kasutajad ja serverid, mida sa soovid eirata. Kui soovid, et %(brand)s kasutaks üldist asendamist, siis kasuta tärni. Näiteks <code>@bot:*</code> eirab kõikide serverite kasutajat 'bot'.",
"Use default": "Kasuta vaikimisi väärtusi",
"Mentions & Keywords": "Mainimised ja võtmesõnad",
@ -3298,7 +3298,7 @@
"You have no ignored users.": "Sa ei ole veel kedagi eiranud.",
"Play": "Esita",
"Pause": "Peata",
"Feeling experimental? Labs are the best way to get things early, test out new features and help shape them before they actually launch. <a>Learn more</a>.": "Kas sa tahaksid katsetada? Sa tutvud meie rakenduse uuendustega teistest varem ja võib-olla isegi saad mõjutada arenduse lõpptulemust. <a>Lisateavet liad siit</a>.",
"Feeling experimental? Labs are the best way to get things early, test out new features and help shape them before they actually launch. <a>Learn more</a>.": "Kas sa tahaksid katsetada? Sa tutvud meie rakenduse uuendustega teistest varem ja võib-olla isegi saad mõjutada arenduse lõpptulemust. <a>Lisateavet leiad siit</a>.",
"<b>This is an experimental feature.</b> For now, new users receiving an invite will have to open the invite on <link/> to actually join.": "<b>See on katseline funktsionaalsus.</b> Seetõttu uued kutse saanud kasutajad peavad tegelikuks liitumiseks avama kutse siin <link/>.",
"To join %(spaceName)s, turn on the <a>Spaces beta</a>": "%(spaceName)s kogukonnakeskusega liitumiseks lülita sisse <a>vastav katseline funktsionaalsus</a>",
"To view %(spaceName)s, turn on the <a>Spaces beta</a>": "%(spaceName)s kogukonnakeskuse vaatamiseks lülita sisse <a>vastav katseline funktsionaalsus</a>",
@ -3327,9 +3327,9 @@
"Please enter a name for the space": "Palun sisesta kogukonnakeskuse nimi",
"Connecting": "Kõne on ühendamisel",
"Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Kasuta võrdõigusvõrku 1:1 kõnede jaoks (kui sa P2P-võrgu sisse lülitad, siis teine osapool ilmselt näeb sinu IP-aadressi)",
"Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Rakenduse beetaversioon on saadaval veebirakendusena, töölauarakendusena ja Androidi jaoks. Kõik funtsionaalsused ei pruugi sinu koduserveri poolt olla toetatud.",
"Beta available for web, desktop and Android. Some features may be unavailable on your homeserver.": "Rakenduse beetaversioon on saadaval veebirakendusena, töölauarakendusena ja Androidi jaoks. Kõik funktsionaalsused ei pruugi sinu koduserveri poolt olla toetatud.",
"You can leave the beta any time from settings or tapping on a beta badge, like the one above.": "Sa võid beetaversiooni kasutamise lõpetada niipea, kui tahad. Selleks klõpsi beeta-silti, mida näed siin samas ülal.",
"%(brand)s will reload with Spaces enabled. Communities and custom tags will be hidden.": "Käivitame %(brand)s uuesti nii, et kogukonnakeskused on kasutusel. Vana tüüpi kogukonnad ja kohandatud sildid on siis välja lülitatud.",
"%(brand)s will reload with Spaces enabled. Communities and custom tags will be hidden.": "Käivitame %(brand)s'i uuesti nii, et kogukonnakeskused on kasutusel. Vana tüüpi kogukonnad ja kohandatud sildid on siis välja lülitatud.",
"%(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Käivitame %(brand)s uuesti nii, et kogukonnakeskused ei ole kasutusel. Vana tüüpi kogukonnad ja kohandatud sildid saavad jälle olema kasutusel.",
"Beta available for web, desktop and Android. Thank you for trying the beta.": "Rakenduse beetaversioon on saadaval veebirakendusena, töölauarakendusena ja Androidi jaoks. Tänud, et oled huviline katsetama meie rakendust.",
"Spaces are a new way to group rooms and people.": "Kogukonnakeskused on uus viis jututubade ja inimeste ühendamiseks.",
@ -3344,7 +3344,7 @@
"Add reaction": "Lisa reaktsioon",
"Send and receive voice messages": "Saada ja võta vastu häälsõnumeid",
"Your feedback will help make spaces better. The more detail you can go into, the better.": "Sinu tagasiside aitab teha kogukonnakeskuseid paremaks. Mida detailsemalt sa oma arvamust kirjeldad, seda parem.",
"If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Kui sa lahkud, siis käivitame %(brand)s uuesti nii, et kogukonnakeskused ei ole kasutusel. Vana tüüpi kogukonnad ja kohandatud sildid saavad jälle olema kasutusel.",
"If you leave, %(brand)s will reload with Spaces disabled. Communities and custom tags will be visible again.": "Kui sa lahkud, siis käivitame %(brand)s'i uuesti nii, et kogukonnakeskused ei ole kasutusel. Vana tüüpi kogukonnad ja kohandatud sildid saavad jälle olema kasutusel.",
"Message search initialisation failed": "Sõnumite otsingu alustamine ei õnnestunud",
"sends space invaders": "korraldab ühe pisikese tulnukate vallutusretke",
"Sends the given message with a space themed effect": "Saadab antud sõnumi kosmoseteemalise efektiga",
@ -3354,5 +3354,22 @@
"No results for \"%(query)s\"": "Päringule „%(query)s“ pole vastuseid",
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Proovi muid otsingusõnu või kontrolli, et neis polnud trükivigu. Kuna mõned otsingutulemused on privaatsed ja sa vajad kutset nende nägemiseks, siis kõiki tulemusi siin ei pruugi näha olla.",
"Currently joining %(count)s rooms|other": "Parasjagu liitun %(count)s jututoaga",
"Currently joining %(count)s rooms|one": "Parasjagu liitun %(count)s jututoaga"
"Currently joining %(count)s rooms|one": "Parasjagu liitun %(count)s jututoaga",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "Sinu isiklikud sõnumid on tavaliselt läbivalt krüptitud, aga see jututuba ei ole. Tavaliselt on põhjuseks, et kasutusel on mõni seade või meetod nagu e-posti põhised kutsed, mis krüptimist veel ei toeta. <a>Läbiva krüptimise saad sisse lülitada seadistustes.</a>",
"We're working on this as part of the beta, but just want to let you know.": "Me küll alles arendame seda beetafunktsionaalsust, aga soovime, et sa sellest juba teaksid.",
"Teammates might not be able to view or join any private rooms you make.": "Kui muudad jututoa privaatseks, siis sinu kaaslased ei pruugi seda näha ega temaga liituda.",
"If you can't see who youre looking for, send them your invite link below.": "Kui sa ei leia otsitavaid, siis saada neile kutse.",
"Or send invite link": "Või saada kutse link",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Kui sul on vastavad õigused olemas, siis ava sõnumi juuresolev menüü ning püsisõnumi tekitamiseks vali <b>Klammerda</b>.",
"Pinned messages": "Klammerdatud sõnumid",
"Nothing pinned, yet": "Klammerdatud sõnumeid veel pole",
"End-to-end encryption isn't enabled": "Läbiv krüptimine pole kasutusel",
"Some suggestions may be hidden for privacy.": "Mõned soovitused võivad privaatsusseadistuste tõttu olla peidetud.",
"Search for rooms or people": "Otsi jututubasid või inimesi",
"Forward message": "Edasta sõnum",
"Open link": "Ava link",
"Sent": "Saadetud",
"You don't have permission to do this": "Sul puuduvad selleks toiminguks õigused",
"Error - Mixed content": "Viga - erinev sisu",
"Error loading Widget": "Viga vidina laadimisel"
}

View File

@ -3358,5 +3358,22 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Essayez d'autres mots ou vérifiez les fautes de frappe. Certains salons peuvent ne pas être visibles car ils sont privés et vous devez être invité pour les rejoindre.",
"No results for \"%(query)s\"": "Aucun résultat pour « %(query)s »",
"The user you called is busy.": "Lutilisateur que vous avez appelé est indisponible.",
"User Busy": "Utilisateur indisponible"
"User Busy": "Utilisateur indisponible",
"We're working on this as part of the beta, but just want to let you know.": "Nous travaillons sur cette partie en bêta, mais nous voulions vous en faire part.",
"Teammates might not be able to view or join any private rooms you make.": "Votre équipe pourrait ne pas voir ou rejoindre les salons privés que vous créez.",
"Or send invite link": "Ou envoyer le lien dinvitation",
"If you can't see who youre looking for, send them your invite link below.": "Si vous ne trouvez pas la personne que vous cherchez, envoyez leur le lien dinvitation ci-dessous.",
"Some suggestions may be hidden for privacy.": "Certaines suggestions pourraient être masquées pour votre confidentialité.",
"Search for rooms or people": "Rechercher des salons ou des gens",
"Forward message": "Transférer le message",
"Open link": "Ouvrir le lien",
"Sent": "Envoyé",
"You don't have permission to do this": "Vous navez pas les permissions nécessaires pour effectuer cette action",
"Error - Mixed content": "Erreur - Contenu mixte",
"Error loading Widget": "Erreur lors du chargement du widget",
"Pinned messages": "Messages épinglés",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Si vous avez les permissions, ouvrez le menu de nimporte quel message et sélectionnez <b>Épingler</b> pour les afficher ici.",
"Nothing pinned, yet": "Rien dépinglé, pour linstant",
"End-to-end encryption isn't enabled": "Le chiffrement de bout en bout nest pas activé",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "Vous messages privés sont normalement chiffrés, mais ce salon ne lest pas. Ceci est souvent du à un appareil ou une méthode qui ne le prend pas en charge, comme les invitations par e-mail. <a>Activer le chiffrement dans les paramètres.</a>"
}

View File

@ -3381,5 +3381,22 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Intentao con outras palabras e fíxate nos erros de escritura. Algúns resultados poderían non ser visibles porque son privados e precisas un convite.",
"No results for \"%(query)s\"": "Sen resultados para \"%(query)s\"",
"The user you called is busy.": "A persoa á que chamas está ocupada.",
"User Busy": "Usuaria ocupada"
"User Busy": "Usuaria ocupada",
"We're working on this as part of the beta, but just want to let you know.": "Estamos traballando nesto como parte da beta, só queriamos que o soubeses.",
"Teammates might not be able to view or join any private rooms you make.": "As outras compañeiras de grupo poderían non ver ou unirse ás salas privadas que creas.",
"Or send invite link": "Ou envía ligazón de convite",
"If you can't see who youre looking for, send them your invite link below.": "Se non podes a quen estás a buscar, envíalle ti esta ligazón de convite.",
"Some suggestions may be hidden for privacy.": "Algunhas suxestións poderían estar agochadas por privacidade.",
"Search for rooms or people": "Busca salas ou persoas",
"Forward message": "Reenviar mensaxe",
"Open link": "Abrir ligazón",
"Sent": "Enviado",
"You don't have permission to do this": "Non tes permiso para facer isto",
"Error - Mixed content": "Erro - Contido variado",
"Error loading Widget": "Erro ao cargar o Widget",
"Pinned messages": "Mensaxes fixadas",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Se tes permisos, abre o menú en calquera mensaxe e elixe <b>Fixar</b> para pegalos aquí.",
"Nothing pinned, yet": "Nada fixado, por agora",
"End-to-end encryption isn't enabled": "Non está activado o cifrado de extremo-a-extremo",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "As túas mensaxes privadas normalmente están cifradas, pero esta sala non. Habitualmente esto é debido a que se utiliza un dispositivo ou métodos no soportados, como convites por email. <a>Activa o cifrado nos axustes.</a>"
}

View File

@ -3376,5 +3376,22 @@
"No results for \"%(query)s\"": "Nincs találat ehhez: %(query)s",
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Próbáljon ki más szavakat vagy keressen elgépelést. Néhány találat azért nem látszik, mert privát és meghívóra van szüksége, hogy csatlakozhasson.",
"The user you called is busy.": "A hívott felhasználó foglalt.",
"User Busy": "Felhasználó foglalt"
"User Busy": "Felhasználó foglalt",
"If you can't see who youre looking for, send them your invite link below.": "Ha nem található a keresett személy, küldje el az alábbi hivatkozást neki.",
"Some suggestions may be hidden for privacy.": "Adatvédelem miatt néhány javaslat esetleg rejtve van.",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Ha van hozzá jogosultsága, nyissa meg a menüt bármelyik üzenetben és válassza a <b>Kitűz</b> menüpontot a kitűzéshez.",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "A személyes beszélgetések általában titkosítottak, de ez a szoba nem az. Ez azért lehet, mert nem támogatott eszköz vagy mód használt mint például e-mail meghívók. <a>Titkosítás engedélyezése a beállításokban.</a>",
"We're working on this as part of the beta, but just want to let you know.": "A béta funkció ezen részén dolgozunk, csak tudatni szerettük volna.",
"Teammates might not be able to view or join any private rooms you make.": "Csapattagok lehet, hogy nem láthatják vagy léphetnek be az ön által készített privát szobákba.",
"Or send invite link": "Vagy meghívó link küldése",
"Search for rooms or people": "Szobák vagy emberek keresése",
"Forward message": "Üzenet továbbítása",
"Open link": "Hivatkozás megnyitása",
"Sent": "Elküldve",
"You don't have permission to do this": "Nincs jogosultsága ehhez",
"Error - Mixed content": "Hiba - Vegyes tartalom",
"Error loading Widget": "Kisalkalmazás betöltési hiba",
"Pinned messages": "Kitűzött üzenetek",
"Nothing pinned, yet": "Semmi sincs kitűzve egyenlőre",
"End-to-end encryption isn't enabled": "Végpontok közötti titkosítás nincs engedélyezve"
}

View File

@ -3381,5 +3381,22 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Prova parole diverse o controlla errori di battitura. Alcuni risultati potrebbero non essere visibili dato che sono privati e ti servirebbe un invito per unirti.",
"No results for \"%(query)s\"": "Nessun risultato per \"%(query)s\"",
"The user you called is busy.": "L'utente che hai chiamato è occupato.",
"User Busy": "Utente occupato"
"User Busy": "Utente occupato",
"We're working on this as part of the beta, but just want to let you know.": "Stiamo lavorando a questo come parte della beta, ma vogliamo almeno fartelo sapere.",
"Teammates might not be able to view or join any private rooms you make.": "I tuoi compagni potrebbero non riuscire a vedere o unirsi a qualsiasi stanza privata che crei.",
"Or send invite link": "O manda un collegamento di invito",
"If you can't see who youre looking for, send them your invite link below.": "Se non vedi chi stai cercando, mandagli il collegamento di invito sottostante.",
"Some suggestions may be hidden for privacy.": "Alcuni suggerimenti potrebbero essere nascosti per privacy.",
"Search for rooms or people": "Cerca stanze o persone",
"Forward message": "Inoltra messaggio",
"Open link": "Apri collegamento",
"Sent": "Inviato",
"You don't have permission to do this": "Non hai il permesso per farlo",
"Error - Mixed content": "Errore - Contenuto misto",
"Error loading Widget": "Errore di caricamento del widget",
"Nothing pinned, yet": "Non c'è ancora nulla di ancorato",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Se ne hai il permesso, apri il menu di qualsiasi messaggio e seleziona <b>Fissa</b> per ancorarlo qui.",
"Pinned messages": "Messaggi ancorati",
"End-to-end encryption isn't enabled": "La crittografia end-to-end non è attiva",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "I tuoi messaggi privati normalmente sono cifrati, ma questa stanza non lo è. Di solito ciò è dovuto ad un dispositivo non supportato o dal metodo usato, come gli inviti per email. <a>Attiva la crittografia nelle impostazioni.</a>"
}

View File

@ -2502,5 +2502,6 @@
"Pick rooms or conversations to add. This is just a space for you, no one will be informed. You can add more later.": "部屋や会話を追加できます。これはあなた専用のスペースで、他の人からは見えません。後から部屋や会話を追加することもできます。",
"Support": "サポート",
"You can change these anytime.": "ここで入力した情報はいつでも編集できます。",
"Add some details to help people recognise it.": "情報を入力してください。"
"Add some details to help people recognise it.": "情報を入力してください。",
"View dev tools": "開発者ツールを表示"
}

View File

@ -260,7 +260,7 @@
"Do you want to set an email address?": "Ar norite nustatyti el. pašto adresą?",
"Current password": "Dabartinis slaptažodis",
"Password": "Slaptažodis",
"New Password": "Naujas Slaptažodis",
"New Password": "Naujas slaptažodis",
"Failed to set display name": "Nepavyko nustatyti rodomo vardo",
"Cannot add any more widgets": "Nepavyksta pridėti daugiau valdiklių",
"Add a widget": "Pridėti valdiklį",
@ -2102,5 +2102,88 @@
"You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Element with an existing Matrix account on a different homeserver.": "Jūs galite naudoti serverio parinktis, norėdami prisijungti prie kitų Matrix serverių, nurodydami kitą serverio URL. Tai leidžia jums naudoti Element su egzistuojančia paskyra kitame serveryje.",
"Server Options": "Serverio Parinktys",
"Your homeserver": "Jūsų serveris",
"Download logs": "Parsisiųsti žurnalus"
"Download logs": "Parsisiųsti žurnalus",
"edited": "pakeista",
"Edited at %(date)s. Click to view edits.": "Keista %(date)s. Spustelėkite kad peržiūrėti pakeitimus.",
"Edited at %(date)s": "Keista %(date)s",
"Click to view edits": "Spustelėkite kad peržiūrėti pakeitimus",
"Add an Integration": "Pridėti Integraciją",
"Message deleted on %(date)s": "Žinutė buvo ištrinta %(date)s",
"<reactors/><reactedWith>reacted with %(shortName)s</reactedWith>": "<reactors/><reactedWith>reagavo su %(shortName)s</reactedWith>",
"<reactors/><reactedWith> reacted with %(content)s</reactedWith>": "<reactors/><reactedWith> reagavo su %(content)s</reactedWith>",
"Reactions": "Reakcijos",
"Add reaction": "Pridėti reakciją",
"Error processing voice message": "Klaida apdorojant balso pranešimą",
"Declining …": "Atmetama …",
"Ignored attempt to disable encryption": "Bandymas išjungti šifravimą buvo ignoruotas",
"Verification timed out.": "Pasibaigė laikas patikrinimui.",
"Ask %(displayName)s to scan your code:": "Paprašykite %(displayName)s nuskaityti jūsų kodą:",
"Failed to withdraw invitation": "Nepavyko atšaukti pakvietimo",
"Disinvite this user from community?": "Atšaukti pakvietimą šiam vartotojui iš šios bendruomenės?",
"Unmute": "Atšaukti nutildymą",
"For a large amount of messages, this might take some time. Please don't refresh your client in the meantime.": "Dideliam žinučių kiekiui tai gali užtrukti kurį laiką. Prašome neperkrauti savo kliento.",
"No recent messages by %(user)s found": "Nerasta jokių naujesnių %(user)s žinučių",
"Accepting …": "Priimame …",
"You cancelled": "Jūs atšaukėte",
"You declined": "Jūs atsisakėte",
"You accepted": "Jūs priėmėte",
"Message Actions": "Žinutės Veiksmai",
"React": "Reaguoti",
"Edit devices": "Redaguoti įrenginius",
"Not encrypted": "Neužšifruota",
"Pinned messages": "Prisegtos žinutės",
"Nothing pinned, yet": "Kol kas nieko neprisegta",
"Mexico": "Meksika",
"Malaysia": "Malaizija",
"Iraq": "Irakas",
"Iran": "Iranas",
"Indonesia": "Indonezija",
"India": "Indija",
"Iceland": "Islandija",
"Greenland": "Grenlandija",
"Greece": "Graikija",
"Germany": "Vokietija",
"France": "Prancūzija",
"Finland": "Suomija",
"Estonia": "Estija",
"Egypt": "Egiptas",
"Denmark": "Danija",
"Croatia": "Kroatija",
"Colombia": "Kolumbija",
"China": "Kinija",
"Chile": "Čilė",
"Canada": "Kanada",
"Bulgaria": "Bulgarija",
"Brazil": "Brazilija",
"Belgium": "Belgija",
"Bangladesh": "Bangladešas",
"Try again": "Bandykite vėl",
"We couldn't log you in": "Mes negalėjome jūsų prijungti",
"You're already in a call with this person.": "Jūs jau esate pokalbyje su šiuo asmeniu.",
"Already in call": "Jau pokalbyje",
"Your Security Key": "Jūsų Saugumo Raktas",
"Confirm your Security Phrase": "Patvirtinkite savo Saugumo Frazę",
"Make a copy of your Security Key": "Sukurkite savo Saugumo Rakto kopiją",
"Generate a Security Key": "Generuoti Saugumo Raktą",
"Save your Security Key": "Išsaugoti savo Saugumo Raktą",
"Go to Settings": "Eiti į Nustatymus",
"Disable": "Išjungti",
"Search (must be enabled)": "Paieška (turi būti įjungta)",
"The user you called is busy.": "Vartotojas kuriam skambinate yra užsiėmęs.",
"User Busy": "Vartotojas Užsiėmęs",
"Any of the following data may be shared:": "Gali būti dalijamasi bet kuriais toliau nurodytais duomenimis:",
"Cancel search": "Atšaukti paiešką",
"Quick Reactions": "Greitos Reakcijos",
"Categories": "Kategorijos",
"Flags": "Vėliavos",
"Symbols": "Simboliai",
"Objects": "Objektai",
"Travel & Places": "Kelionės & Vietovės",
"Activities": "Veikla",
"Food & Drink": "Maistas & Gėrimai",
"Animals & Nature": "Gyvūnai & Gamta",
"Frequently Used": "Dažnai Naudojama",
"Something went wrong when trying to get your communities.": "Kažkas nepavyko bandant gauti jūsų bendruomenes.",
"Can't load this message": "Nepavyko įkelti šios žinutės",
"Submit logs": "Pateikti žurnalus"
}

View File

@ -1177,7 +1177,7 @@
"Homeserver URL": "Thuisserver-URL",
"Identity Server URL": "Identiteitsserver-URL",
"Free": "Gratis",
"Join millions for free on the largest public server": "Doe mee met miljoenen anderen op de grootste openbare server",
"Join millions for free on the largest public server": "Neem deel aan de grootste openbare server met miljoenen anderen",
"Premium": "Premium",
"Premium hosting for organisations <a>Learn more</a>": "Premium hosting voor organisaties <a>Lees meer</a>",
"Other": "Overige",
@ -1513,7 +1513,7 @@
"View": "Bekijken",
"Find a room…": "Zoek een gesprek…",
"Find a room… (e.g. %(exampleRoom)s)": "Zoek een gesprek… (bv. %(exampleRoom)s)",
"If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.": "Als u het gesprek dat u zoekt niet kunt vinden, vraag dan een uitnodiging, of <a>Maak een nieuw gesprek aan</a>.",
"If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.": "Als u het gesprek dat u zoekt niet kunt vinden, vraag dan een uitnodiging of <a>maak een nieuw gesprek aan</a>.",
"Explore rooms": "Gesprekken ontdekken",
"Show previews/thumbnails for images": "Miniaturen voor afbeeldingen tonen",
"Clear cache and reload": "Cache wissen en herladen",
@ -1932,7 +1932,7 @@
"Jump to first unread room.": "Ga naar het eerste ongelezen gesprek.",
"Jump to first invite.": "Ga naar de eerste uitnodiging.",
"Session verified": "Sessie geverifieerd",
"Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Uw nieuwe sessie is nu geverifieerd. U heeft nu toegang tot uw versleutelde berichten, en deze sessie zal voor andere gebruikers als vertrouwd gemarkeerd worden.",
"Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Uw nieuwe sessie is nu geverifieerd. U heeft nu toegang tot uw versleutelde berichten en deze sessie zal voor andere gebruikers als vertrouwd gemarkeerd worden.",
"Your new session is now verified. Other users will see it as trusted.": "Uw nieuwe sessie is nu geverifieerd. Ze zal voor andere gebruikers als vertrouwd gemarkeerd worden.",
"Without completing security on this session, it wont have access to encrypted messages.": "Als u de beveiliging van deze sessie niet vervolledigt, zal ze geen toegang hebben tot uw versleutelde berichten.",
"Go Back": "Terugkeren",
@ -3267,5 +3267,23 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Probeer andere woorden of controleer op typefouten. Sommige resultaten zijn mogelijk niet zichtbaar omdat ze privé zijn of u een uitnodiging nodig heeft om deel te nemen.",
"No results for \"%(query)s\"": "Geen resultaten voor \"%(query)s\"",
"The user you called is busy.": "De gebruiker die u belde is bezet.",
"User Busy": "Gebruiker Bezet"
"User Busy": "Gebruiker Bezet",
"We're working on this as part of the beta, but just want to let you know.": "We werken hieraan als onderdeel van de beta, maar we willen het u gewoon laten weten.",
"Teammates might not be able to view or join any private rooms you make.": "Teamgenoten zijn mogelijk niet in staat zijn om privégesprekken die u maakt te bekijken of er lid van te worden.",
"Or send invite link": "Of verstuur uw uitnodigingslink",
"If you can't see who youre looking for, send them your invite link below.": "Als u niet kunt vinden wie u zoekt, stuur ze dan uw uitnodigingslink hieronder.",
"Some suggestions may be hidden for privacy.": "Sommige suggesties kunnen om privacyredenen verborgen zijn.",
"Search for rooms or people": "Zoek naar gesprekken of personen",
"Message preview": "Voorbeeld van bericht",
"Forward message": "Bericht doorsturen",
"Open link": "Koppeling openen",
"Sent": "Verstuurd",
"You don't have permission to do this": "U heeft geen rechten om dit te doen",
"Error - Mixed content": "Fout - Gemengde inhoud",
"Error loading Widget": "Fout bij laden Widget",
"Pinned messages": "Vastgeprikte berichten",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Als u de rechten heeft, open dan het menu op elk bericht en selecteer <b>Vastprikken</b> om ze hier te zetten.",
"Nothing pinned, yet": "Nog niks vastgeprikt",
"End-to-end encryption isn't enabled": "Eind-tot-eind-versleuteling is uitgeschakeld",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "Uw privéberichten zijn normaal gesproken versleuteld, maar dit gesprek niet. Meestal is dit te wijten aan een niet-ondersteund apparaat of methode die wordt gebruikt, zoals e-mailuitnodigingen. <a>Versleuting inschakelen in instellingen.</a>"
}

View File

@ -2352,5 +2352,21 @@
"Converts the room to a DM": "Zmienia pokój w wiadomość bezpośrednią",
"Sends the given message as a spoiler": "Wysyła podaną wiadomość jako spoiler",
"User Busy": "Użytkownik zajęty",
"The user you called is busy.": "Użytkownik do którego zadzwoniłeś(-aś) jest zajęty."
"The user you called is busy.": "Użytkownik do którego zadzwoniłeś(-aś) jest zajęty.",
"End-to-end encryption isn't enabled": "Szyfrowanie end-to-end nie jest włączone",
"Nothing pinned, yet": "Nie przypięto tu jeszcze niczego",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Jeżeli masz uprawnienia, przejdź do menu dowolnej wiadomości i wybierz <b>Przypnij</b>, aby przyczepić ją tutaj.",
"Pinned messages": "Przypięte wiadomości",
"Error loading Widget": "Błąd ładowania widżetu",
"Error - Mixed content": "Błąd — zawartość mieszana",
"You don't have permission to do this": "Nie masz uprawnień aby to zrobić",
"Sent": "Wysłano",
"Open link": "Otwórz odnośnik",
"Forward message": "Przekaż wiadomość",
"Message preview": "Podgląd wiadomości",
"Search for rooms or people": "Szukaj pokojów i ludzi",
"Some suggestions may be hidden for privacy.": "Niektóre propozycje mogą być ukryte z uwagi na prywatność.",
"If you can't see who youre looking for, send them your invite link below.": "Jeżeli nie możesz zobaczyć osób, których szukasz, wyślij im poniższy odnośnik z zaproszeniem.",
"Or send invite link": "Lub wyślij odnośnik z zaproszeniem",
"We're working on this as part of the beta, but just want to let you know.": "Pracujemy nad tym w ramach bety, ale chcemy, żebyś wiedział(a)."
}

View File

@ -74,5 +74,43 @@
"Explore rooms": "Explorează camerele",
"Sign In": "Autentificare",
"Create Account": "Înregistare",
"Dismiss": "Închide"
"Dismiss": "Închide",
"You've reached the maximum number of simultaneous calls.": "Ați atins numărul maxim de apeluri simultane.",
"Too Many Calls": "Prea multe apeluri",
"No other application is using the webcam": "Nicio altă aplicație nu folosește camera web",
"Permission is granted to use the webcam": "Permisiunea de a utiliza camera web este acordată",
"A microphone and webcam are plugged in and set up correctly": "Microfonul și camera web sunt conectate și configurate corect",
"Call failed because webcam or microphone could not be accessed. Check that:": "Apelul nu a reușit deoarece camera web sau microfonul nu au putut fi accesate. Verifică:",
"Unable to access webcam / microphone": "Imposibil de accesat camera web / microfonul",
"Call failed because microphone could not be accessed. Check that a microphone is plugged in and set up correctly.": "Apelul nu a reușit deoarece microfonul nu a putut fi accesat. Verificați dacă un microfon este conectat și configurați corect.",
"Unable to access microphone": "Nu se poate accesa microfonul",
"OK": "OK",
"Try using turn.matrix.org": "Încercați să utilizați turn.matrix.org",
"Alternatively, you can try to use the public server at <code>turn.matrix.org</code>, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "Alternativ, puteți încerca să utilizați serverul public la <code>turn.matrix.org</code>, dar acest lucru nu va fi la fel de fiabil și va partaja adresa dvs. IP cu acel server. Puteți gestiona acest lucru și în Setări.",
"Please ask the administrator of your homeserver (<code>%(homeserverDomain)s</code>) to configure a TURN server in order for calls to work reliably.": "Vă rugăm să cereți administratorului serverului dvs. (<code>%(homeserverDomain)s</code>) să configureze un server TURN pentru ca apelurile să funcționeze în mod fiabil.",
"Call failed due to misconfigured server": "Apelul nu a reușit din cauza serverului configurat greșit",
"The call was answered on another device.": "Apelul a primit răspuns pe un alt dispozitiv.",
"Answered Elsewhere": "A răspuns în altă parte",
"The call could not be established": "Apelul nu a putut fi stabilit",
"The user you called is busy.": "Utilizatorul pe care l-ați sunat este ocupat.",
"User Busy": "Utilizator ocupat",
"The other party declined the call.": "Cealaltă parte a refuzat apelul.",
"Call Declined": "Apel refuzat",
"Unable to load! Check your network connectivity and try again.": "Imposibil de incarcat! Verificați conectivitatea rețelei și încercați din nou.",
"Error": "Eroare",
"Your user agent": "Agentul dvs. de utilizator",
"Whether you're using %(brand)s as an installed Progressive Web App": "Dacă utilizați %(brand)s ca aplicație web progresivă instalată",
"Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "Dacă utilizați sau nu funcția „breadcrumbs” (avatare deasupra listei de camere)",
"Whether you're using %(brand)s on a device where touch is the primary input mechanism": "Dacă utilizați %(brand)s pe un dispozitiv în care atingerea este principalul mecanism de intrare",
"Add Phone Number": "Adaugă numărul de telefon",
"Click the button below to confirm adding this phone number.": "Faceți clic pe butonul de mai jos pentru a confirma adăugarea acestui număr de telefon.",
"Confirm adding phone number": "Confirmați adăugarea numărului de telefon",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "Confirmați adăugarea acestui număr de telefon utilizând Single Sign On pentru a vă dovedi identitatea.",
"Add Email Address": "Adăugați o adresă de e-mail",
"Confirm": "Confirmă",
"Click the button below to confirm adding this email address.": "Faceți clic pe butonul de mai jos pentru a confirma adăugarea acestei adrese de e-mail.",
"Confirm adding email": "Confirmați adăugarea e-mailului",
"Single Sign On": "Single Sign On",
"Confirm adding this email address by using Single Sign On to prove your identity.": "Confirmați adăugarea acestei adrese de e-mail utilizând Single Sign On pentru a vă dovedi identitatea.",
"Use Single Sign On to continue": "Utilizați Single Sign On pentru a continua"
}

View File

@ -272,7 +272,7 @@
"Server may be unavailable, overloaded, or you hit a bug.": "Возможно, сервер недоступен, перегружен или случилась ошибка.",
"Server unavailable, overloaded, or something else went wrong.": "Возможно, сервер недоступен, перегружен или что-то еще пошло не так.",
"Session ID": "ID сессии",
"%(senderName)s set a profile picture.": "%(senderName)s установил себе аватар.",
"%(senderName)s set a profile picture.": "%(senderName)s установил(а) себе аватар.",
"%(senderName)s set their display name to %(displayName)s.": "%(senderName)s изменил(а) отображаемое имя на %(displayName)s.",
"Signed Out": "Выполнен выход",
"This room is not accessible by remote Matrix servers": "Это комната недоступна из других серверов Matrix",
@ -853,7 +853,7 @@
"Sets the room name": "Устанавливает название комнаты",
"Forces the current outbound group session in an encrypted room to be discarded": "Принудительно отбрасывает текущую групповую сессию для отправки сообщений в зашифрованную комнату",
"%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s модернизировал эту комнату.",
"%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s установил %(address)s в качестве главного адреса комнаты.",
"%(senderName)s set the main address for this room to %(address)s.": "%(senderName)s установил(а) %(address)s в качестве главного адреса комнаты.",
"%(senderName)s removed the main address for this room.": "%(senderName)s удалил главный адрес комнаты.",
"%(displayName)s is typing …": "%(displayName)s печатает…",
"%(names)s and %(count)s others are typing …|other": "%(names)s и %(count)s других печатают…",
@ -3211,5 +3211,13 @@
"Failed to remove some rooms. Try again later": "Не удалось удалить несколько комнат. Попробуйте позже",
"%(count)s rooms and 1 space|one": "%(count)s комната и одно пространство",
"%(count)s rooms and 1 space|other": "%(count)s комнат и одно пространство",
"Sends the given message as a spoiler": "Отправить данное сообщение под спойлером"
"Sends the given message as a spoiler": "Отправить данное сообщение под спойлером",
"Play": "Воспроизведение",
"Pause": "Пауза",
"Connecting": "Подключение",
"Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Разрешить прямые соединения для вызовов 1:1 (при включении данной опции другая сторона может узнать ваш IP адрес)",
"Send and receive voice messages": "Отправлять и получать голосовые сообщения",
"%(deviceId)s from %(ip)s": "%(deviceId)s с %(ip)s",
"The user you called is busy.": "Вызываемый пользователь занят.",
"User Busy": "Пользователь занят"
}

View File

@ -3370,5 +3370,21 @@
"The user you called is busy.": "Përdoruesi që thirrët është i zënë.",
"User Busy": "Përdoruesi Është i Zënë",
"Kick, ban, or invite people to your active room, and make you leave": "Përzini, dëboni, ose ftoni persona te dhoma juaj aktive, dhe bëni largimin tuaj",
"Kick, ban, or invite people to this room, and make you leave": "Përzini, dëboni, ose ftoni persona në këtë dhomë, dhe bëni largimin tuaj"
"Kick, ban, or invite people to this room, and make you leave": "Përzini, dëboni, ose ftoni persona në këtë dhomë, dhe bëni largimin tuaj",
"We're working on this as part of the beta, but just want to let you know.": "Po merremi me këtë, si pjesë e versionit beta, thjesht duam ta dini.",
"Teammates might not be able to view or join any private rooms you make.": "Anëtarët e ekipit mund të mos jenë në gjendje të shohin ose hyjnë në çfarëdo dhome private që krijoni.",
"Or send invite link": "Ose dërgoni një lidhje ftese",
"If you can't see who youre looking for, send them your invite link below.": "Nëse se shihni atë që po kërkoni, dërgojini nga më poshtë një lidhje ftese.",
"Some suggestions may be hidden for privacy.": "Disa sugjerime mund të jenë fshehur, për arsye privatësie.",
"Search for rooms or people": "Kërkoni për dhoma ose persona",
"Forward message": "Përcille mesazhin",
"Open link": "Hape lidhjen",
"You don't have permission to do this": "Skeni leje ta bëni këtë",
"Error - Mixed content": "Gabim - Lëndë e përzierë",
"Error loading Widget": "Gabim në ngarkim Widget-i",
"Pinned messages": "Mesazhe të fiksuar",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Nëse keni leje, hapni menunë për çfarëdo mesazhi dhe përzgjidhni <b>Fiksoje</b>, për ta ngjitur këtu.",
"Nothing pinned, yet": "Ende pa fiksuar gjë",
"End-to-end encryption isn't enabled": "Fshehtëzimi skaj-më-skaj sështë i aktivizuar",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "Mesazhet tuaja private normalisht fshehtëzohen, por kjo dhomë nuk fshehtëzohet. Zakonisht kjo vjen si pasojë e përdorimit të një pajisjeje apo metode të pambuluar, bie fjala, ftesa me email. <a>Aktivizoni fshehtëzimin që nga rregullimet.</a>"
}

View File

@ -3311,5 +3311,23 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "Testa andra ord eller kolla efter felskrivningar. Vissa resultat kanske inte visas för att de är privata och du behöver en inbjudan för att gå med i dem.",
"No results for \"%(query)s\"": "Inga resultat för \"%(query)s\"",
"The user you called is busy.": "Användaren du ringde är upptagen.",
"User Busy": "Användare upptagen"
"User Busy": "Användare upptagen",
"We're working on this as part of the beta, but just want to let you know.": "Vi jobbar på detta som en del av betan, men vi ville låta dig veta.",
"Teammates might not be able to view or join any private rooms you make.": "Teammedlemmar kanske inte kan se eller gå med i privata rum du skapar.",
"Or send invite link": "Eller skicka inbjudningslänk",
"If you can't see who youre looking for, send them your invite link below.": "Om du inte kan se den du letar efter, skicka dem din inbjudningslänk nedan.",
"Some suggestions may be hidden for privacy.": "Vissa förslag kan vara dolda av sekretesskäl.",
"Search for rooms or people": "Sök efter rum eller personer",
"Message preview": "Meddelandeförhandsvisning",
"Forward message": "Vidarebefordra meddelande",
"Open link": "Öppna länk",
"Sent": "Skickat",
"You don't have permission to do this": "Du har inte behörighet att göra detta",
"Error - Mixed content": "Fel - blandat innehåll",
"Error loading Widget": "Fel vid laddning av widget",
"Pinned messages": "Fästa meddelanden",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "Om du har behörighet, öppna menyn på ett meddelande och välj <b>Fäst</b> för att fösta dem här.",
"Nothing pinned, yet": "Inget fäst än",
"End-to-end encryption isn't enabled": "Totalsträckskryptering är inte aktiverat",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "Dina privata meddelanden är normalt krypterade, men det här rummet är inte det. Oftast så beror detta på att en enhet eller metod som används ej stöds, som e-postinbjudningar. <a>Aktivera kryptering i inställningarna.</a>"
}

View File

@ -21,7 +21,7 @@
"Enable email notifications": "மின்னஞ்சல் அறிவிப்புகளை ஏதுவாக்கு",
"Enable notifications for this account": "இந்த கணக்கிற்கான அறிவிப்புகளை ஏதுவாக்கு",
"Enable them now": "இப்போது அவற்றை ஏதுவாக்கு",
"Error": "கோளாறு",
"Error": "பிழை",
"Failed to add tag %(tagName)s to room": "%(tagName)s எனும் குறிச்சொல்லை அறையில் சேர்ப்பதில் தோல்வி",
"Failed to change settings": "அமைப்புகள் மாற்றத்தில் தோல்வி",
"Failed to forget room %(errCode)s": "அறையை மறப்பதில் தோல்வி %(errCode)s",
@ -125,17 +125,17 @@
"Register": "பதிவு செய்",
"Rooms": "அறைகள்",
"Add rooms to this community": "அறைகளை இந்த சமூகத்தில் சேர்க்கவும்",
"This email address is already in use": "இந்த மின் அஞ்சல் முகவரி ஏற்கனவே பயன்பாட்டில் உள்ளது",
"This phone number is already in use": "இந்த தொலைபேசி எண் ஏற்கனவே பயன்பாட்டில் உள்ளது",
"Failed to verify email address: make sure you clicked the link in the email": "மின்னஞ்சல் முகவரியைச் சரிபார்க்கத் தவறிவிட்டது: மின்னஞ்சலில் உள்ள இணைப்பைக் கிளிக் செய்துள்ளீர்கள் என்பதை உறுதிப்படுத்திக் கொள்ளுங்கள்",
"This email address is already in use": "இந்த மின்னஞ்சல் முகவரி முன்னதாகவே பயன்பாட்டில் உள்ளது",
"This phone number is already in use": "இந்த தொலைபேசி எண் முன்னதாகவே பயன்பாட்டில் உள்ளது",
"Failed to verify email address: make sure you clicked the link in the email": "மின்னஞ்சல் முகவரியை சரிபார்க்க முடியவில்லை: மின்னஞ்சலில் உள்ள இணைப்பை அழுத்தியுள்ளீர்களா என்பதை உறுதிப்படுத்தவும்",
"The platform you're on": "நீங்கள் இருக்கும் தளம்",
"The version of %(brand)s": "%(brand)s இன் பதிப்பு",
"Whether or not you're logged in (we don't record your username)": "நீங்கள் உள்நுழைந்திருந்தாலும் இல்லாவிட்டாலும் (உங்கள் பயனர்பெயரை நாங்கள் பதிவு செய்ய மாட்டோம்)",
"Your language of choice": "நீங்கள் விரும்பும் மொழி",
"Which officially provided instance you are using, if any": "நீங்கள் பயன்படுத்தும் அதிகாரப்பூர்வமாக வழங்கப்பட்ட உதாரணம் ஏதேனும் இருந்தால்",
"Whether or not you're using the Richtext mode of the Rich Text Editor": "பணக்கார உரை எடிட்டரின் ரிச்ச்டெக்ஸ்ட் பயன்முறையைப் பயன்படுத்துகிறீர்களா இல்லையா",
"Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "நீங்கள் 'breadcrumbs' அம்சத்தைப் பயன்படுத்துகிறீர்களோ இல்லையோ (அறை பட்டியலுக்கு மேலே உள்ள அவதாரங்கள்)",
"Your homeserver's URL": "உங்கள் வீட்டு சேவையகத்தின் URL",
"Which officially provided instance you are using, if any": "நீங்கள் பயன்படுத்தும் அதிகாரப்பூர்வமாக வழங்கப்பட்ட நிகழ்வு ஏதேனும் இருந்தால்",
"Whether or not you're using the Richtext mode of the Rich Text Editor": "நீங்கள் ரிச்டெக்ஸ்ட் உரைத்திருத்தியின் ரிச்டெக்ஸ்ட் பயன்முறையைப் பயன்படுத்துகிறீர்களா இல்லையா",
"Whether or not you're using the 'breadcrumbs' feature (avatars above the room list)": "நீங்கள் 'breadcrumbs' அம்சத்தைப் பயன்படுத்துகிறீர்களோ இல்லையோ (அறை பட்டியலுக்கு மேலே உள்ள பயனர் படங்கள்)",
"Your homeserver's URL": "உங்கள் வீட்டுச்சேவையகத்தின் URL",
"e.g. %(exampleValue)s": "உதாரணமாக %(exampleValue)s",
"Every page you use in the app": "பயன்பாட்டில் நீங்கள் பயன்படுத்தும் ஒவ்வொரு பக்கமும்",
"Your %(brand)s is misconfigured": "உங்கள் %(brand)s தவறாக உள்ளமைக்கப்பட்டுள்ளது",
@ -143,7 +143,7 @@
"e.g. <CurrentPageURL>": "உதாரணமாக <CurrentPageURL>",
"Your device resolution": "உங்கள் சாதனத் தீர்மானம்",
"Analytics": "பகுப்பாய்வு",
"The information being sent to us to help make %(brand)s better includes:": "%(brand)s ஐ சிறப்பாகச் செய்ய எங்களுக்கு அனுப்பப்படும் தகவல்களில் பின்வருவன அடங்கும்:",
"The information being sent to us to help make %(brand)s better includes:": "%(brand)s ஐ சிறப்பாக்க எங்களுக்கு அனுப்பப்படும் தகவல்களில் பின்வருவன அடங்கும்:",
"Where this page includes identifiable information, such as a room, user or group ID, that data is removed before being sent to the server.": "இந்த பக்கம் ஒரு அறை, பயனர் அல்லது குழு ஐடி போன்ற அடையாளம் காணக்கூடிய தகவல்களை உள்ளடக்கியது, அந்த தரவு சேவையகத்திற்கு அனுப்பப்படுவதற்கு முன்பு அகற்றப்படும்.",
"Call Failed": "அழைப்பு தோல்வியுற்றது",
"Call Timeout": "அழைப்பு நேரம் முடிந்தது",
@ -152,19 +152,19 @@
"Existing Call": "இருக்கும் அழைப்பு",
"You are already in a call.": "நீங்கள் ஏற்கனவே அழைப்பில் உள்ளீர்கள்.",
"VoIP is unsupported": "VoIP ஆதரிக்கப்படவில்லை",
"You cannot place VoIP calls in this browser.": "இந்த உலாவியில் நீங்கள் VoIP அழைப்புகளை வைக்க முடியாது.",
"You cannot place a call with yourself.": "உங்களுடன் அழைப்பை மேற்கொள்ள முடியாது.",
"Call in Progress": "அழைப்பு முன்னேற்றத்தில் உள்ளது",
"A call is currently being placed!": "தற்போது அழைப்பு வைக்கப்பட்டுள்ளது!",
"You cannot place VoIP calls in this browser.": "இந்த உலாவியில் நீங்கள் VoIP அழைப்புகளை மேற்கொள்ள முடியாது.",
"You cannot place a call with yourself.": "நீங்கள் உங்களுடனே அழைப்பை மேற்கொள்ள முடியாது.",
"Call in Progress": "அழைப்பு நடந்துகொண்டிருக்கிறது",
"A call is currently being placed!": "தற்போது ஒரு அழைப்பு செயல்படுத்தப்பட்டுள்ளது!",
"A call is already in progress!": "அழைப்பு ஏற்கனவே செயலில் உள்ளது!",
"Permission Required": "அனுமதி தேவை",
"You do not have permission to start a conference call in this room": "இந்த அறையில் ஒரு மாநாட்டு அழைப்பைத் தொடங்க உங்களுக்கு அனுமதி இல்லை",
"You do not have permission to start a conference call in this room": "இந்த அறையில் ஒரு கூட்டு அழைப்பைத் தொடங்க உங்களுக்கு அனுமதி இல்லை",
"Replying With Files": "கோப்புகளுடன் பதிலளித்தல்",
"At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "இந்த நேரத்தில் ஒரு கோப்புடன் பதிலளிக்க முடியாது. பதிலளிக்காமல் இந்த கோப்பை பதிவேற்ற விரும்புகிறீர்களா?",
"The file '%(fileName)s' failed to upload.": "'%(fileName)s' கோப்பு பதிவேற்றத் தவறிவிட்டது.",
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "'%(fileName)s' கோப்பு பதிவேற்றங்களுக்கான இந்த ஹோம்சர்வரின் அளவு வரம்பை மீறுகிறது",
"The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "'%(fileName)s' கோப்பு இந்த வீட்டுச்சேவையகத்தின் பதிவேற்றங்களுக்கான அளவு வரம்பை மீறுகிறது",
"Upload Failed": "பதிவேற்றம் தோல்வியுற்றது",
"Server may be unavailable, overloaded, or you hit a bug.": "சேவையகம் கிடைக்காமல் போகலாம், அதிக சுமை அல்லது பிழையைத் தாக்கலாம்.",
"Server may be unavailable, overloaded, or you hit a bug.": "",
"The server does not support the room version specified.": "குறிப்பிடப்பட்ட அறை பதிப்பை சேவையகம் ஆதரிக்கவில்லை.",
"Failure to create room": "அறையை உருவாக்கத் தவறியது",
"Sun": "ஞாயிறு",
@ -181,5 +181,57 @@
"May": "மே",
"Jun": "ஜூன்",
"Explore rooms": "அறைகளை ஆராயுங்கள்",
"Create Account": "உங்கள் கணக்கை துவங்குங்கள்"
"Create Account": "உங்கள் கணக்கை துவங்குங்கள்",
"Who would you like to add to this community?": "இந்த சமூகத்தில் யாரைச் சேர்க்க விரும்புகிறீர்கள்?",
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s",
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s",
"%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(time)s",
"%(weekDayName)s %(time)s": "%(weekDayName)s %(time)s",
"AM": "காலை",
"PM": "மாலை",
"Dec": "டிசம்பர்",
"Nov": "நவம்பர்",
"Oct": "அக்டோபர்",
"Sep": "செப்டம்பர்",
"Aug": "ஆகஸ்ட்",
"Jul": "ஜூலை",
"This will end the conference for everyone. Continue?": "இது அனைவருக்கும் கூட்டு அழைப்பை நிறுத்திவிடும். தொடரவா?",
"End conference": "கூட்டு அழைப்பை நிறுத்து",
"There was an error looking up the phone number": "தொலைபேசி எண்ணைத் தேடுவதில் பிழை ஏற்பட்டது",
"Unable to look up phone number": "தொலைபேசி எண்ணைத் தேட முடியவில்லை",
"You're already in a call with this person.": "நீங்கள் முன்னதாகவே இந்த நபருடன் அழைப்பில் உள்ளீர்கள்.",
"Already in call": "முன்னதாகவே அழைப்பில் உள்ளது",
"You've reached the maximum number of simultaneous calls.": "ஒரே நேரத்தில் அழைக்கக்கூடிய அதிகபட்ச அழைப்புகளை நீங்கள் அடைந்துவிட்டீர்கள்.",
"Too Many Calls": "மிக அதிக அழைப்புகள்",
"No other application is using the webcam": "வேறு எந்த பயன்பாடும் புகைப்படக்கருவியைப் பயன்படுத்துவதில்லை",
"Permission is granted to use the webcam": "புகைப்படக்கருவியைப் பயன்படுத்த அனுமதி வழங்கப்பட்டுள்ளது",
"A microphone and webcam are plugged in and set up correctly": "ஒரு ஒலிவாங்கி மற்றும் புகைப்படக்கருவி செருகப்பட்டு சரியாக அமைக்கப்பட்டுள்ளது",
"Call failed because webcam or microphone could not be accessed. Check that:": "புகைப்படக்கருவி அல்லது ஒலிவாங்கியை அணுக முடியாததால் அழைப்பு தோல்வியடைந்தது. அதை சரிபார்க்கவும்:",
"Unable to access webcam / microphone": "புகைப்படக்கருவி / ஒலிவாங்கியை அணுக முடியவில்லை",
"Call failed because microphone could not be accessed. Check that a microphone is plugged in and set up correctly.": "ஒலிவாங்கியை அணுக முடியாததால் அழைப்பு தோல்வியடைந்தது. ஒலிவாங்கி செருகப்பட்டுள்ளதா, சரியாக அமைக்கவும் என சரிபார்க்கவும்.",
"Unable to access microphone": "ஒலிவாங்கியை அணுக முடியவில்லை",
"Try using turn.matrix.org": "turn.matrix.org ஐப் பயன்படுத்த முயற்சிக்கவும்",
"Alternatively, you can try to use the public server at <code>turn.matrix.org</code>, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "மாற்றாக, நீங்கள் பொது சேவையகத்தை <code>turn.matrix.org</code> பயன்படுத்தி முயற்சி செய்யலாம், ஆனால் இது அவ்வளவு நம்பகமானதாக இருக்காது, மேலும் அது உங்கள் ஐபி முகவரியை அந்த சேவையகத்துடன் பகிர்ந்து கொள்ளும். இதை அமைப்புகளிலும் நிர்வகிக்கலாம்.",
"Please ask the administrator of your homeserver (<code>%(homeserverDomain)s</code>) to configure a TURN server in order for calls to work reliably.": "அழைப்புகள் நம்பத்தகுந்த வகையில் இயங்குவதற்காக, TURN சேவையகத்தை உள்ளமைக்க உங்கள் வீட்டுசேவையகத்தின் (<code>%(homeserverDomain)s</code>) நிர்வாகியிடம் கேளுங்கள்.",
"Call failed due to misconfigured server": "தவறாக உள்ளமைக்கப்பட்ட சேவையகம் காரணமாக அழைப்பு தோல்வியடைந்தது",
"The call was answered on another device.": "அழைப்பு மற்றொரு சாதனத்தில் பதிலளிக்கப்பட்டது.",
"Answered Elsewhere": "வேறு எங்கோ பதிலளிக்கப்பட்டது",
"The call could not be established": "அழைப்பை நிறுவ முடியவில்லை",
"The other party declined the call.": "மற்றவர் அழைப்பை மறுத்துவிட்டார்.",
"Call Declined": "அழைப்பு மறுக்கப்பட்டது",
"Unable to load! Check your network connectivity and try again.": "ஏற்ற முடியவில்லை! உங்கள் பிணைய இணைப்பைச் சரிபார்த்து மீண்டும் முயற்சிக்கவும்.",
"Your user agent": "உங்கள் பயனர் முகவர்",
"Whether you're using %(brand)s as an installed Progressive Web App": "நிறுவப்பட்ட முற்போக்கான வலை பயன்பாடாக %(brand)s ஐப் பயன்படுத்துகிறீர்களா",
"Whether you're using %(brand)s on a device where touch is the primary input mechanism": "தொடுதல் உள்ளீட்டு பொறிமுறை முதன்மையாக இருக்கும் சாதனத்தில் நீங்கள் %(brand)s ஐப் பயன்படுத்துகிறீர்களா",
"Add Phone Number": "தொலைபேசி எண்ணை சேர்க்கவும்",
"Click the button below to confirm adding this phone number.": "இந்த தொலைபேசி எண்ணைச் சேர்ப்பதை உறுதிப்படுத்த கீழே உள்ள பொத்தானை அழுத்தவும்.",
"Confirm adding phone number": "தொலைபேசி எண்ணைச் சேர்ப்பதை உறுதிப்படுத்தவும்",
"Confirm adding this phone number by using Single Sign On to prove your identity.": "உங்கள் அடையாளத்தை நிரூபிக்க ஒற்றை உள்நுழைவைப் பயன்படுத்தி இந்த தொலைபேசி எண்ணைச் சேர்ப்பதை உறுதிப்படுத்தவும்.",
"Add Email Address": "மின்னஞ்சல் முகவரியை சேர்க்கவும்",
"Confirm": "உறுதிப்படுத்தவும்",
"Click the button below to confirm adding this email address.": "இந்த மின்னஞ்சல் முகவரியை சேர்ப்பதை உறுதிப்படுத்த கீழே உள்ள பொத்தானை அழுத்தவும்.",
"Confirm adding email": "மின்னஞ்சலை சேர்ப்பதை உறுதிப்படுத்தவும்",
"Single Sign On": "ஒற்றை உள்நுழைவு",
"Confirm adding this email address by using Single Sign On to prove your identity.": "உங்கள் அடையாளத்தை நிரூபிக்க ஒற்றை உள்நுழைவைப் பயன்படுத்தி இந்த மின்னஞ்சல் முகவரியை சேர்ப்பதை உறுதிப்படுத்தவும்.",
"Use Single Sign On to continue": "தொடர ஒற்றை உள்நுழைவைப் பயன்படுத்தவும்"
}

View File

@ -510,8 +510,8 @@
"Restricted": "受限用户",
"To use it, just wait for autocomplete results to load and tab through them.": "若要使用自动补全,只要等待自动补全结果加载完成,按 Tab 键切换即可。",
"%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s 将他们的昵称修改成了 %(displayName)s 。",
"Stickerpack": "贴图集",
"You don't currently have any stickerpacks enabled": "你目前没有启用任何贴图集",
"Stickerpack": "贴纸包",
"You don't currently have any stickerpacks enabled": "你目前未启用任何贴纸包",
"Key request sent.": "已发送密钥共享请求。",
"You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "如果你是房间中最后一位有权限的用户,在你降低自己的权限等级后将无法撤回此修改,因为你将无法重新获得权限。",
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "你将无法撤回此修改,因为你正在将此用户的滥权等级提升至与你相同。",
@ -1071,10 +1071,10 @@
"Ignored users": "已忽略的用户",
"Bulk options": "批量选择",
"Key backup": "密钥备份",
"Security & Privacy": "安全与隐私",
"Security & Privacy": "隐私安全",
"Missing media permissions, click the button below to request.": "缺少媒体权限,点击下面的按钮以请求权限。",
"Request media permissions": "请求媒体权限",
"Voice & Video": "语音视频",
"Voice & Video": "语音视频",
"Room information": "聊天室信息",
"Internal room ID:": "内部聊天室 ID",
"Room version": "聊天室版本",
@ -1566,7 +1566,7 @@
"If you don't want to use <server /> to discover and be discoverable by existing contacts you know, enter another identity server below.": "如果你不想使用 <server /> 以发现你认识的现存联系人并被其发现,请在下方输入另一个身份服务器。",
"Identity Server": "身份服务器",
"You are not currently using an identity server. To discover and be discoverable by existing contacts you know, add one below.": "你现在没有使用身份服务器。若想发现你认识的现存联系人并被其发现,请在下方添加一个身份服务器。",
"Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.": "从你的身份服务器断开连接意味着你将不可被别的用户发现,同时你也将不能用邮箱或电话邀请别人。",
"Disconnecting from your identity server will mean you won't be discoverable by other users and you won't be able to invite others by email or phone.": "断开身份服务器连接意味着你将无法被其他用户发现,同时你也将无法使用电子邮件或电话邀请别人。",
"Using an identity server is optional. If you choose not to use an identity server, you won't be discoverable by other users and you won't be able to invite others by email or phone.": "使用身份服务器是可选的。如果你选择不使用身份服务器,你将不能被别的用户发现,也不能用邮箱或电话邀请别人。",
"Do not use an identity server": "不使用身份服务器",
"Enter a new identity server": "输入一个新的身份服务器",
@ -1686,9 +1686,9 @@
"Cannot connect to integration manager": "不能连接到集成管理器",
"The integration manager is offline or it cannot reach your homeserver.": "此集成管理器为离线状态或者其不能访问你的主服务器。",
"check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "检查你的浏览器是否安装有可能屏蔽身份服务器的插件(例如 Privacy Badger",
"Use an Integration Manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "使用集成管理器 <b>%(serverName)s</b> 以管理机器人、挂件和贴图集。",
"Use an Integration Manager to manage bots, widgets, and sticker packs.": "使用集成管理器以管理机器人、挂件和贴图集。",
"Manage integrations": "管理集成",
"Use an Integration Manager <b>(%(serverName)s)</b> to manage bots, widgets, and sticker packs.": "使用集成管理器 <b>%(serverName)s</b> 以管理机器人、挂件和贴纸包。",
"Use an Integration Manager to manage bots, widgets, and sticker packs.": "使用集成管理器以管理机器人、挂件和贴纸包。",
"Manage integrations": "集成管理",
"Integration Managers receive configuration data, and can modify widgets, send room invites, and set power levels on your behalf.": "集成管理器接收配置数据,并可以以你的名义修改挂件、发送聊天室邀请及设置权限级别。",
"Use between %(min)s pt and %(max)s pt": "请使用介于 %(min)s pt 和 %(max)s pt 之间的大小",
"Deactivate account": "停用账号",
@ -1995,7 +1995,7 @@
"Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "验证此设备以将其标记为已信任。在收发端对端加密消息时,信任设备可让你与其他用户更加放心。",
"Verifying this device will mark it as trusted, and users who have verified with you will trust this device.": "验证此设备会将其标记为已信任,与此同时,其他验证了你的用户也会信任此设备。",
"Integrations are disabled": "集成已禁用",
"Enable 'Manage Integrations' in Settings to do this.": "在设置中启用「管理集成」以执行此操作。",
"Enable 'Manage Integrations' in Settings to do this.": "在设置中启用「管理管理」以执行此操作。",
"Integrations not allowed": "集成未被允许",
"Your %(brand)s doesn't allow you to use an Integration Manager to do this. Please contact an admin.": "你的 %(brand)s 不允许你使用集成管理器来完成此操作。请联系管理员。",
"To continue, use Single Sign On to prove your identity.": "要继续,请使用单点登录证明你的身份。",
@ -2077,7 +2077,7 @@
"Integration Manager": "集成管理器",
"Find others by phone or email": "通过电话或邮箱寻找别人",
"Be found by phone or email": "通过电话或邮箱被寻找",
"Use bots, bridges, widgets and sticker packs": "使用机器人、桥接、挂件和贴图集",
"Use bots, bridges, widgets and sticker packs": "使用机器人、桥接、挂件和贴纸包",
"Terms of Service": "服务协议",
"To continue you need to accept the terms of this service.": "要继续,你需要接受此服务协议。",
"Service": "服务",
@ -3280,5 +3280,23 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "尝试不同的单词或检查拼写错误。某些结果可能不可见,因为它们属于私有的,你需要一个邀请才能加入。",
"No results for \"%(query)s\"": "「%(query)s」没有结果",
"The user you called is busy.": "你所拨打的用户正在忙碌中。",
"User Busy": "用户正在忙"
"User Busy": "用户正在忙",
"We're working on this as part of the beta, but just want to let you know.": "我们正在研究让它成为测试版的一部分,但只想让你找到。",
"Teammates might not be able to view or join any private rooms you make.": "队友可能无法查看或加入你所创建的任何一个私有聊天室。",
"Or send invite link": "或发送邀请链接",
"If you can't see who youre looking for, send them your invite link below.": "如果你找不到你正在寻找的人,请在下方向他们发送你的邀请链接。",
"Some suggestions may be hidden for privacy.": "出于隐私考虑,部分建议可能会被隐藏。",
"Search for rooms or people": "搜索聊天室或用户",
"Message preview": "消息预览",
"Forward message": "转发消息",
"Open link": "打开链接",
"Sent": "已发送",
"You don't have permission to do this": "你无权执行此操作",
"Error - Mixed content": "错误 - 混合内容",
"Error loading Widget": "加载挂件时发生错误",
"Pinned messages": "已置顶的消息",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "如果你拥有权限,请打开任何消息的菜单并选择<b>置顶</b>将它们粘贴至此。",
"Nothing pinned, yet": "没有置顶",
"End-to-end encryption isn't enabled": "未启用端对端加密",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "你的私人信息通常是被加密的,但此聊天室并未加密。一般而言,这可能是因为使用了不受支持的设备或方法,如电子邮件邀请。<a>在设置中启用加密。</a>"
}

View File

@ -3384,5 +3384,22 @@
"Try different words or check for typos. Some results may not be visible as they're private and you need an invite to join them.": "嘗試不同的詞或是檢查拼字。某些結果可能不可見,因為其為私人的,您必須要有邀請才能加入。",
"No results for \"%(query)s\"": "「%(query)s」沒有結果",
"The user you called is busy.": "您想要通話的使用者目前忙碌中。",
"User Busy": "使用者忙碌"
"User Busy": "使用者忙碌",
"We're working on this as part of the beta, but just want to let you know.": "我們正將此作為測試版的一部分來處理,但只是想讓您知道。",
"Teammates might not be able to view or join any private rooms you make.": "隊友可能無法檢視或加入您建立的任何私人聊天室。",
"Or send invite link": "或傳送邀請連結",
"If you can't see who youre looking for, send them your invite link below.": "如果您看不到您要找的人,請在下方向他們傳送您的邀請連結。",
"Some suggestions may be hidden for privacy.": "出於隱私考量,可能會隱藏一些建議。",
"Search for rooms or people": "搜尋聊天室或夥伴",
"Forward message": "轉寄訊息",
"Open link": "開啟連結",
"Sent": "已傳送",
"You don't have permission to do this": "您無權執行此動作",
"Error - Mixed content": "錯誤 - 混合內容",
"Error loading Widget": "載入小工具時發生錯誤",
"Pinned messages": "已釘選的訊息",
"If you have permissions, open the menu on any message and select <b>Pin</b> to stick them here.": "如果您有權限,請開啟任何訊息的選單,並選取<b>釘選</b>以將它們貼到這裡。",
"Nothing pinned, yet": "尚未釘選任何東西",
"End-to-end encryption isn't enabled": "端到端加密未啟用",
"Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. <a>Enable encryption in settings.</a>": "您的私人訊息通常是被加密的,但此聊天室不是。一般來說,這可能是因為使用了不支援的裝置或方法,例如電子郵件邀請。<a>在設定中啟用加密。</a>"
}

View File

@ -22,6 +22,7 @@ import {RightPanelPhases, RIGHT_PANEL_PHASES_NO_ARGS} from "./RightPanelStorePha
import {ActionPayload} from "../dispatcher/payloads";
import {Action} from '../dispatcher/actions';
import { SettingLevel } from "../settings/SettingLevel";
import RoomViewStore from './RoomViewStore';
interface RightPanelStoreState {
// Whether or not to show the right panel at all. We split out rooms and groups
@ -147,6 +148,8 @@ export default class RightPanelStore extends Store<ActionPayload> {
switch (payload.action) {
case 'view_room':
case 'view_group':
if (payload.room_id === RoomViewStore.getRoomId()) break; // skip this transition, probably a permalink
// Reset to the member list if we're viewing member info
if (MEMBER_INFO_PHASES.includes(this.state.lastRoomPhase)) {
this.setState({lastRoomPhase: RightPanelPhases.RoomMemberList, lastRoomPhaseParams: {}});
@ -161,6 +164,7 @@ export default class RightPanelStore extends Store<ActionPayload> {
case Action.SetRightPanelPhase: {
let targetPhase = payload.phase;
let refireParams = payload.refireParams;
const allowClose = payload.allowClose ?? true;
// redirect to EncryptionPanel if there is an ongoing verification request
if (targetPhase === RightPanelPhases.RoomMemberInfo && payload.refireParams) {
const {member} = payload.refireParams;
@ -192,7 +196,7 @@ export default class RightPanelStore extends Store<ActionPayload> {
});
}
} else {
if (targetPhase === this.state.lastRoomPhase && !refireParams) {
if (targetPhase === this.state.lastRoomPhase && !refireParams && allowClose) {
this.setState({
showRoomPanel: !this.state.showRoomPanel,
previousPhase: null,

View File

@ -26,9 +26,11 @@ export class MarkedExecution {
/**
* Creates a MarkedExecution for the provided function.
* @param fn The function to be called upon trigger if marked.
* @param {Function} fn The function to be called upon trigger if marked.
* @param {Function} onMarkCallback A function that is called when a new mark is made. Not
* called if a mark is already flagged.
*/
constructor(private fn: () => void) {
constructor(private fn: () => void, private onMarkCallback?: () => void) {
}
/**
@ -42,6 +44,7 @@ export class MarkedExecution {
* Marks the function to be called upon trigger().
*/
public mark() {
if (!this.marked) this.onMarkCallback?.();
this.marked = true;
}

View File

@ -27,6 +27,8 @@ import {PayloadEvent, WORKLET_NAME} from "./consts";
import {UPDATE_EVENT} from "../stores/AsyncStore";
import {Playback} from "./Playback";
import {createAudioContext} from "./compat";
import { IEncryptedFile } from "matrix-js-sdk/src/@types/event";
import { uploadFile } from "../ContentMessages";
const CHANNELS = 1; // stereo isn't important
export const SAMPLE_RATE = 48000; // 48khz is what WebRTC uses. 12khz is where we lose quality.
@ -49,6 +51,11 @@ export enum RecordingState {
Uploaded = "uploaded",
}
export interface IUpload {
mxc?: string; // for unencrypted uploads
encrypted?: IEncryptedFile;
}
export class VoiceRecording extends EventEmitter implements IDestroyable {
private recorder: Recorder;
private recorderContext: AudioContext;
@ -58,7 +65,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
private recorderWorklet: AudioWorkletNode;
private recorderProcessor: ScriptProcessorNode;
private buffer = new Uint8Array(0); // use this.audioBuffer to access
private mxc: string;
private lastUpload: IUpload;
private recording = false;
private observable: SimpleObservable<IRecordingUpdate>;
private amplitudes: number[] = []; // at each second mark, generated
@ -214,13 +221,6 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
return this.buffer.length > 0;
}
public get mxcUri(): string {
if (!this.mxc) {
throw new Error("Recording has not been uploaded yet");
}
return this.mxc;
}
private onAudioProcess = (ev: AudioProcessingEvent) => {
this.processAudioUpdate(ev.playbackTime);
@ -290,7 +290,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
};
public async start(): Promise<void> {
if (this.mxc || this.hasRecording) {
if (this.lastUpload || this.hasRecording) {
throw new Error("Recording already prepared");
}
if (this.recording) {
@ -362,20 +362,19 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
this.observable.close();
}
public async upload(): Promise<string> {
public async upload(inRoomId: string): Promise<IUpload> {
if (!this.hasRecording) {
throw new Error("No recording available to upload");
}
if (this.mxc) return this.mxc;
if (this.lastUpload) return this.lastUpload;
this.emit(RecordingState.Uploading);
this.mxc = await this.client.uploadContent(new Blob([this.audioBuffer], {
const { url: mxc, file: encrypted } = await uploadFile(this.client, inRoomId, new Blob([this.audioBuffer], {
type: this.contentType,
}), {
onlyContentUri: false, // to stop the warnings in the console
}).then(r => r['content_uri']);
}));
this.lastUpload = { mxc, encrypted };
this.emit(RecordingState.Uploaded);
return this.mxc;
return this.lastUpload;
}
}

View File

@ -11,7 +11,7 @@
"dependencies": {
"cheerio": "^1.0.0-rc.2",
"commander": "^2.19.0",
"puppeteer": "^1.14.0",
"puppeteer": "10.0.0",
"request": "^2.88.0",
"request-promise-native": "^1.0.7",
"uuid": "^3.3.2"

View File

@ -32,7 +32,11 @@ module.exports.goBackToRoomSummaryCard = async function(session) {
// Sometimes our tests have this opened to MemberInfo
await backButton.click();
} catch (e) {
break; // stop trying to go further back
// explicitly check for TimeoutError as this sometimes returned
// `Error: Node is detached from document` due to a re-render race or similar
if (e.name === "TimeoutError") {
break; // stop trying to go further back
}
}
}
};

View File

@ -40,7 +40,7 @@ async function acceptToast(session, expectedTitle) {
async function rejectToast(session, expectedTitle) {
await assertToast(session, expectedTitle);
const btn = await session.query('.mx_Toast_buttons .mx_AccessibleButton_kind_danger');
const btn = await session.query('.mx_Toast_buttons .mx_AccessibleButton_kind_danger_outline');
await btn.click();
}

View File

@ -7,12 +7,19 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.12.1.tgz#d90123f6c61fdf2f7cddd286ddae891586dd3488"
integrity sha512-sKDlqv6COJrR7ar0+GqqhrXQDzQlMcqMnF2iEU6m9hLo8kxozoAGUazwPyELHlRVmjsbvlnGXjnzyptSXVmceA==
agent-base@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
"@types/yauzl@^2.9.1":
version "2.9.1"
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af"
integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==
dependencies:
es6-promisify "^5.0.0"
"@types/node" "*"
agent-base@6:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
dependencies:
debug "4"
ajv@^6.5.5:
version "6.10.0"
@ -36,11 +43,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@ -61,6 +63,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
@ -68,6 +75,15 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
bl@^4.0.3:
version "4.1.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
dependencies:
buffer "^5.5.0"
inherits "^2.0.4"
readable-stream "^3.4.0"
boolbase@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
@ -86,10 +102,13 @@ buffer-crc32@~0.2.3:
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
buffer@^5.2.1, buffer@^5.5.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
dependencies:
base64-js "^1.3.1"
ieee754 "^1.1.13"
caseless@~0.12.0:
version "0.12.0"
@ -108,6 +127,11 @@ cheerio@^1.0.0-rc.2:
lodash "^4.15.0"
parse5 "^3.0.1"
chownr@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
@ -125,17 +149,7 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
concat-stream@^1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
dependencies:
buffer-from "^1.0.0"
inherits "^2.0.3"
readable-stream "^2.2.2"
typedarray "^0.0.6"
core-util-is@1.0.2, core-util-is@~1.0.0:
core-util-is@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
@ -162,21 +176,7 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
debug@^3.1.0:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
debug@^4.1.0:
debug@4, debug@4.3.1, debug@^4.1.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
@ -188,6 +188,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
devtools-protocol@0.0.883894:
version "0.0.883894"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.883894.tgz#d403f2c75cd6d71c916aee8dde9258da988a4da9"
integrity sha512-33idhm54QJzf3Q7QofMgCvIVSd2o9H3kQPWaKT/fhoZh+digc+WSiMhbkeG3iN79WY4Hwr9G05NpbhEVrsOYAg==
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
@ -232,37 +237,33 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
entities@^1.1.1, entities@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
es6-promise@^4.0.3:
version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
es6-promisify@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
dependencies:
es6-promise "^4.0.3"
extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extract-zip@^1.6.6:
version "1.7.0"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927"
integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==
extract-zip@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
dependencies:
concat-stream "^1.6.2"
debug "^2.6.9"
mkdirp "^0.5.4"
debug "^4.1.1"
get-stream "^5.1.0"
yauzl "^2.10.0"
optionalDependencies:
"@types/yauzl" "^2.9.1"
extsprintf@1.3.0:
version "1.3.0"
@ -291,6 +292,14 @@ fd-slicer@~1.1.0:
dependencies:
pend "~1.2.0"
find-up@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
dependencies:
locate-path "^5.0.0"
path-exists "^4.0.0"
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@ -305,11 +314,23 @@ form-data@~2.3.2:
combined-stream "^1.0.6"
mime-types "^2.1.12"
fs-constants@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
@ -363,13 +384,18 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
https-proxy-agent@^2.2.1:
version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
https-proxy-agent@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
dependencies:
agent-base "^4.3.0"
debug "^3.1.0"
agent-base "6"
debug "4"
ieee754@^1.1.13:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
inflight@^1.0.4:
version "1.0.6"
@ -379,7 +405,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.3, inherits@~2.0.3:
inherits@2, inherits@^2.0.3, inherits@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -394,11 +420,6 @@ is-typedarray@~1.0.0:
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
@ -434,6 +455,13 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
dependencies:
p-locate "^4.1.0"
lodash@^4.15.0, lodash@^4.17.11:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
@ -451,11 +479,6 @@ mime-types@^2.1.12, mime-types@~2.1.19:
dependencies:
mime-db "~1.38.0"
mime@^2.0.3:
version "2.5.2"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@ -468,27 +491,22 @@ minimist@^1.2.5:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
mkdirp@^0.5.4:
mkdirp@^0.5.1:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
minimist "^1.2.5"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@^2.1.1:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
node-fetch@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
nth-check@~1.0.1:
version "1.0.2"
@ -502,13 +520,32 @@ oauth-sign@~0.9.0:
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
once@^1.3.0:
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
p-locate@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
dependencies:
p-limit "^2.2.0"
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
parse5@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
@ -516,6 +553,11 @@ parse5@^3.0.1:
dependencies:
"@types/node" "*"
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@ -531,17 +573,19 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
process-nextick-args@~2.0.0:
pkg-dir@4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
dependencies:
find-up "^4.0.0"
progress@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.1.tgz#c9242169342b1c29d275889c95734621b1952e31"
integrity sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==
progress@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
proxy-from-env@^1.0.0:
proxy-from-env@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
@ -551,6 +595,14 @@ psl@^1.1.24, psl@^1.1.28:
resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184"
integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
@ -561,38 +613,29 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
puppeteer@^1.14.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.20.0.tgz#e3d267786f74e1d87cf2d15acc59177f471bbe38"
integrity sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==
puppeteer@10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-10.0.0.tgz#1b597c956103e2d989ca17f41ba4693b20a3640c"
integrity sha512-AxHvCb9IWmmP3gMW+epxdj92Gglii+6Z4sb+W+zc2hTTu10HF0yg6hGXot5O74uYkVqG3lfDRLfnRpi6WOwi5A==
dependencies:
debug "^4.1.0"
extract-zip "^1.6.6"
https-proxy-agent "^2.2.1"
mime "^2.0.3"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^2.6.1"
ws "^6.1.0"
debug "4.3.1"
devtools-protocol "0.0.883894"
extract-zip "2.0.1"
https-proxy-agent "5.0.0"
node-fetch "2.6.1"
pkg-dir "4.2.0"
progress "2.0.1"
proxy-from-env "1.1.0"
rimraf "3.0.2"
tar-fs "2.0.0"
unbzip2-stream "1.3.3"
ws "7.4.6"
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
readable-stream@^2.2.2:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.2.0.tgz#de17f229864c120a9f56945756e4f32c4045245d"
@ -602,6 +645,15 @@ readable-stream@^3.1.1:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readable-stream@^3.4.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
request-promise-core@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.2.tgz#339f6aababcafdb31c799ff158700336301d3346"
@ -644,14 +696,14 @@ request@^2.88.0:
tunnel-agent "^0.6.0"
uuid "^3.3.2"
rimraf@^2.6.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
rimraf@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
@ -688,12 +740,31 @@ string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.1.0"
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
tar-fs@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad"
integrity sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==
dependencies:
safe-buffer "~5.1.0"
chownr "^1.1.1"
mkdirp "^0.5.1"
pump "^3.0.0"
tar-stream "^2.0.0"
tar-stream@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
dependencies:
bl "^4.0.3"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.1.1"
through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
tough-cookie@^2.3.3:
version "2.5.0"
@ -723,10 +794,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
unbzip2-stream@1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a"
integrity sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==
dependencies:
buffer "^5.2.1"
through "^2.3.8"
uri-js@^4.2.2:
version "4.2.2"
@ -735,7 +809,7 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
util-deprecate@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
@ -759,12 +833,10 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^6.1.0:
version "6.2.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e"
integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==
dependencies:
async-limiter "~1.0.0"
ws@7.4.6:
version "7.4.6"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
yauzl@^2.10.0:
version "2.10.0"