Compare commits
37
Commits
ebe47b345d
...
2fe35f9ded
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fe35f9ded | ||
|
|
852a1a7c4e | ||
|
|
c15092e850 | ||
|
|
7ca827559b | ||
|
|
f7beabacf9 | ||
|
|
848bb19f76 | ||
|
|
c17118d157 | ||
|
|
95e9891825 | ||
|
|
0984c73c01 | ||
|
|
f9e7a71920 | ||
|
|
ba72fe7602 | ||
|
|
6da591beb1 | ||
|
|
16c9e2bb23 | ||
|
|
3689b5d527 | ||
|
|
c277c16a53 | ||
|
|
1bc3e15da3 | ||
|
|
3ac895ec66 | ||
|
|
08bdc7bc08 | ||
|
|
03a137da4a | ||
|
|
8df6413705 | ||
|
|
5d56c17128 | ||
|
|
87c74f9396 | ||
|
|
2b7c80ef2d | ||
|
|
823215aea6 | ||
|
|
5ad734cdea | ||
|
|
48405bcb94 | ||
|
|
0f9b88e64e | ||
|
|
10a827504b | ||
|
|
1d24e9135b | ||
|
|
a5c190f6db | ||
|
|
f61f68d2ac | ||
|
|
2c5705c3ae | ||
|
|
c4547bbeb4 | ||
|
|
e7296d5d14 | ||
|
|
364cd2c488 | ||
|
|
855f871041 | ||
|
|
8dd32a341b |
+8
-5
@@ -3043,17 +3043,20 @@ ul.tabbar li.active > a {
|
|||||||
padding: 0.15rem 0.5rem 0.25rem 0.5rem;
|
padding: 0.15rem 0.5rem 0.25rem 0.5rem;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
line-height: 1.5em;
|
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
border-radius: 0 0.25rem 0.25rem 0;
|
border-radius: 0 0.25rem 0.25rem 0;
|
||||||
color: #666;
|
color: #666;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 24rem;
|
||||||
min-width: 24rem;
|
min-width: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.4s;
|
transition: background 0.4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned > p {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pinned:hover {
|
.pinned:hover {
|
||||||
@@ -3194,7 +3197,7 @@ ul.phone-country-selector span.country {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pinned {
|
.pinned {
|
||||||
min-width: 12rem;
|
width: 16rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3236,6 +3239,6 @@ ul.phone-country-selector span.country {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pinned {
|
.pinned {
|
||||||
min-width: unset;
|
width: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Generated
+414
-394
File diff suppressed because it is too large
Load Diff
@@ -122,3 +122,7 @@ export const LINK_PRIVACY_POLICY = 'https://tinode.co/privacy.html';
|
|||||||
// Link to Terms of Service.
|
// Link to Terms of Service.
|
||||||
export const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html';
|
export const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html';
|
||||||
|
|
||||||
|
// When user starts a P2P topic, automatic subscription does not
|
||||||
|
// happen until the first message. Setting this option to true enables
|
||||||
|
// immediate subscription.
|
||||||
|
export const IMMEDIATE_P2P_SUBSCRIPTION = false;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+20
-34
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "Hinzufügen",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "Mitglieder hinzufügen",
|
"translation": "Mitglieder hinzufügen",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -1000,7 +993,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "Liste: email:lisa@beispiel.de, tel:17025550003...",
|
"translation": "Liste: email:lisa@beispiel.de, tel:17025550003...",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1222,13 +1215,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "bestätigen",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "Beschreibung (optional)",
|
"translation": "Beschreibung (optional)",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "Telefonnummer oder E-Mail",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "Erfolgreich bestätigt",
|
"translation": "Erfolgreich bestätigt",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1600,45 +1579,45 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_email": {
|
"current_email": {
|
||||||
"translation": "",
|
"translation": "Aktuelle E-Mail",
|
||||||
"defaultMessage": "Current email",
|
"defaultMessage": "Current email",
|
||||||
"description": "Label for old email",
|
"description": "Label for old email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_phone": {
|
"current_phone": {
|
||||||
"translation": "",
|
"translation": "Aktuelle Telefonnummer",
|
||||||
"defaultMessage": "Current phone number",
|
"defaultMessage": "Current phone number",
|
||||||
"description": "Label for old phone",
|
"description": "Label for old phone",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_email": {
|
"new_email": {
|
||||||
"translation": "",
|
"translation": "Neue E-Mail",
|
||||||
"defaultMessage": "New email",
|
"defaultMessage": "New email",
|
||||||
"description": "Prompt for entering a new email",
|
"description": "Prompt for entering a new email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_phone_number": {
|
"new_phone_number": {
|
||||||
"translation": "",
|
"translation": "Neue Telefonnummer",
|
||||||
"defaultMessage": "New phone number",
|
"defaultMessage": "New phone number",
|
||||||
"description": "Prompt for entering a new telephone number",
|
"description": "Prompt for entering a new telephone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_email": {
|
"change_email": {
|
||||||
"translation": "",
|
"translation": "E-Mail ändern",
|
||||||
"defaultMessage": "Change email",
|
"defaultMessage": "Change email",
|
||||||
"description": "Prompt to change current email",
|
"description": "Prompt to change current email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_phone": {
|
"change_phone": {
|
||||||
"translation": "",
|
"translation": "Telefonnummer ändern",
|
||||||
"defaultMessage": "Change phone number",
|
"defaultMessage": "Change phone number",
|
||||||
"description": "Prompt to change current phone number",
|
"description": "Prompt to change current phone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"call_busy": {
|
"call_busy": {
|
||||||
@@ -1648,6 +1627,13 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "Audioaufnahme konnte nicht initialisiert werden",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
|
},
|
||||||
"pin_message": {
|
"pin_message": {
|
||||||
"translation": "",
|
"translation": "",
|
||||||
"defaultMessage": "Pin",
|
"defaultMessage": "Pin",
|
||||||
|
|||||||
+8
-22
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "Add another",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "Add members",
|
"translation": "Add members",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -1007,7 +1000,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "List like email:alice@example.com, tel:17025550003...",
|
"translation": "List like email:alice@example.com, tel:17025550003...",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1222,13 +1215,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "confirm",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "Optional description",
|
"translation": "Optional description",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "Phone number or email",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "Confirmed successfully",
|
"translation": "Confirmed successfully",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1648,6 +1627,13 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "Failed to initialize audio recording",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
|
},
|
||||||
"pin_message": {
|
"pin_message": {
|
||||||
"translation": "Pin",
|
"translation": "Pin",
|
||||||
"defaultMessage": "Pin",
|
"defaultMessage": "Pin",
|
||||||
|
|||||||
+20
-34
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "Añadir contacto",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "Añadir miembros",
|
"translation": "Añadir miembros",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -1000,7 +993,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "Ej. email:alice@example.com, tel:17025550003...",
|
"translation": "Ej. email:alice@example.com, tel:17025550003...",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1215,13 +1208,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "confirmar",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "Descripción (opcional)",
|
"translation": "Descripción (opcional)",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "Número de teléfono o correo electrónico",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "Confirmado con éxito",
|
"translation": "Confirmado con éxito",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1600,45 +1579,45 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_email": {
|
"current_email": {
|
||||||
"translation": "",
|
"translation": "Correo electrónico actual",
|
||||||
"defaultMessage": "Current email",
|
"defaultMessage": "Current email",
|
||||||
"description": "Label for old email",
|
"description": "Label for old email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_phone": {
|
"current_phone": {
|
||||||
"translation": "",
|
"translation": "Número de teléfono actual",
|
||||||
"defaultMessage": "Current phone number",
|
"defaultMessage": "Current phone number",
|
||||||
"description": "Label for old phone",
|
"description": "Label for old phone",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_email": {
|
"new_email": {
|
||||||
"translation": "",
|
"translation": "Nuevo correo electrónico",
|
||||||
"defaultMessage": "New email",
|
"defaultMessage": "New email",
|
||||||
"description": "Prompt for entering a new email",
|
"description": "Prompt for entering a new email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_phone_number": {
|
"new_phone_number": {
|
||||||
"translation": "",
|
"translation": "Nuevo número de teléfono",
|
||||||
"defaultMessage": "New phone number",
|
"defaultMessage": "New phone number",
|
||||||
"description": "Prompt for entering a new telephone number",
|
"description": "Prompt for entering a new telephone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_email": {
|
"change_email": {
|
||||||
"translation": "",
|
"translation": "Cambiar correo electrónico",
|
||||||
"defaultMessage": "Change email",
|
"defaultMessage": "Change email",
|
||||||
"description": "Prompt to change current email",
|
"description": "Prompt to change current email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_phone": {
|
"change_phone": {
|
||||||
"translation": "",
|
"translation": "Cambiar número de teléfono",
|
||||||
"defaultMessage": "Change phone number",
|
"defaultMessage": "Change phone number",
|
||||||
"description": "Prompt to change current phone number",
|
"description": "Prompt to change current phone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"call_busy": {
|
"call_busy": {
|
||||||
@@ -1661,5 +1640,12 @@
|
|||||||
"description": "Menu item [Unpin] for un-pinning the message.",
|
"description": "Menu item [Unpin] for un-pinning the message.",
|
||||||
"missing": true,
|
"missing": true,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "Error al inicializar la grabación de audio",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -291,6 +291,10 @@
|
|||||||
"defaultMessage": "Invalid ID",
|
"defaultMessage": "Invalid ID",
|
||||||
"description": "Error message"
|
"description": "Error message"
|
||||||
},
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available"
|
||||||
|
},
|
||||||
"file_attachment_too_large": {
|
"file_attachment_too_large": {
|
||||||
"defaultMessage": "The file size {size} exceeds the {limit} limit.",
|
"defaultMessage": "The file size {size} exceeds the {limit} limit.",
|
||||||
"description": "Error message when attachment is too large"
|
"description": "Error message when attachment is too large"
|
||||||
@@ -801,7 +805,7 @@
|
|||||||
"description": "Text shown in contacts view when query returned no results."
|
"description": "Text shown in contacts view when query returned no results."
|
||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field"
|
"description": "Placeholder in contacts search field"
|
||||||
},
|
},
|
||||||
"sidepanel_title_acc_notifications": {
|
"sidepanel_title_acc_notifications": {
|
||||||
|
|||||||
+20
-34
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "Ajouter un autre",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "Ajouter des membres",
|
"translation": "Ajouter des membres",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -1007,7 +1000,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "Liste comme email:alice@exemple.com, tel:17025550003...",
|
"translation": "Liste comme email:alice@exemple.com, tel:17025550003...",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1222,13 +1215,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "confirmer",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "Description facultative",
|
"translation": "Description facultative",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "Numéro de téléphone ou email",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "Confirmé avec succès",
|
"translation": "Confirmé avec succès",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1600,45 +1579,45 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_email": {
|
"current_email": {
|
||||||
"translation": "",
|
"translation": "Courriel actuel",
|
||||||
"defaultMessage": "Current email",
|
"defaultMessage": "Current email",
|
||||||
"description": "Label for old email",
|
"description": "Label for old email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_phone": {
|
"current_phone": {
|
||||||
"translation": "",
|
"translation": "Numéro de téléphone actuel",
|
||||||
"defaultMessage": "Current phone number",
|
"defaultMessage": "Current phone number",
|
||||||
"description": "Label for old phone",
|
"description": "Label for old phone",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_email": {
|
"new_email": {
|
||||||
"translation": "",
|
"translation": "Nouvel e-mail",
|
||||||
"defaultMessage": "New email",
|
"defaultMessage": "New email",
|
||||||
"description": "Prompt for entering a new email",
|
"description": "Prompt for entering a new email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_phone_number": {
|
"new_phone_number": {
|
||||||
"translation": "",
|
"translation": "Nouveau numéro de téléphone",
|
||||||
"defaultMessage": "New phone number",
|
"defaultMessage": "New phone number",
|
||||||
"description": "Prompt for entering a new telephone number",
|
"description": "Prompt for entering a new telephone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_email": {
|
"change_email": {
|
||||||
"translation": "",
|
"translation": "Modifier l'e-mail",
|
||||||
"defaultMessage": "Change email",
|
"defaultMessage": "Change email",
|
||||||
"description": "Prompt to change current email",
|
"description": "Prompt to change current email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_phone": {
|
"change_phone": {
|
||||||
"translation": "",
|
"translation": "Modifier le numéro de téléphone",
|
||||||
"defaultMessage": "Change phone number",
|
"defaultMessage": "Change phone number",
|
||||||
"description": "Prompt to change current phone number",
|
"description": "Prompt to change current phone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"call_busy": {
|
"call_busy": {
|
||||||
@@ -1661,5 +1640,12 @@
|
|||||||
"description": "Menu item [Unpin] for un-pinning the message.",
|
"description": "Menu item [Unpin] for un-pinning the message.",
|
||||||
"missing": true,
|
"missing": true,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "Échec de l'initialisation de l'enregistrement audio",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-34
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "다른항목추가",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "회원추가",
|
"translation": "회원추가",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -1000,7 +993,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "email:alice@example.com,tel:17025550003...와같은목록",
|
"translation": "email:alice@example.com,tel:17025550003...와같은목록",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1215,13 +1208,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "확인",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "설명(선택 사항)",
|
"translation": "설명(선택 사항)",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "전화번호 또는 이메일",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "성공적으로 확인됨",
|
"translation": "성공적으로 확인됨",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1600,45 +1579,45 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_email": {
|
"current_email": {
|
||||||
"translation": "",
|
"translation": "현재 이메일",
|
||||||
"defaultMessage": "Current email",
|
"defaultMessage": "Current email",
|
||||||
"description": "Label for old email",
|
"description": "Label for old email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_phone": {
|
"current_phone": {
|
||||||
"translation": "",
|
"translation": "현재 전화번호",
|
||||||
"defaultMessage": "Current phone number",
|
"defaultMessage": "Current phone number",
|
||||||
"description": "Label for old phone",
|
"description": "Label for old phone",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_email": {
|
"new_email": {
|
||||||
"translation": "",
|
"translation": "새 이메일 주소",
|
||||||
"defaultMessage": "New email",
|
"defaultMessage": "New email",
|
||||||
"description": "Prompt for entering a new email",
|
"description": "Prompt for entering a new email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_phone_number": {
|
"new_phone_number": {
|
||||||
"translation": "",
|
"translation": "새 전화번호",
|
||||||
"defaultMessage": "New phone number",
|
"defaultMessage": "New phone number",
|
||||||
"description": "Prompt for entering a new telephone number",
|
"description": "Prompt for entering a new telephone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_email": {
|
"change_email": {
|
||||||
"translation": "",
|
"translation": "이메일 변경",
|
||||||
"defaultMessage": "Change email",
|
"defaultMessage": "Change email",
|
||||||
"description": "Prompt to change current email",
|
"description": "Prompt to change current email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_phone": {
|
"change_phone": {
|
||||||
"translation": "",
|
"translation": "전화번호 변경",
|
||||||
"defaultMessage": "Change phone number",
|
"defaultMessage": "Change phone number",
|
||||||
"description": "Prompt to change current phone number",
|
"description": "Prompt to change current phone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"call_busy": {
|
"call_busy": {
|
||||||
@@ -1661,5 +1640,12 @@
|
|||||||
"description": "Menu item [Unpin] for un-pinning the message.",
|
"description": "Menu item [Unpin] for un-pinning the message.",
|
||||||
"missing": true,
|
"missing": true,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "오디오 녹음 초기화 실패",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-34
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "Adaugă",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "Adaugă persoane",
|
"translation": "Adaugă persoane",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -1000,7 +993,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "Caută după e-mail sau număr telefon...",
|
"translation": "Caută după e-mail sau număr telefon...",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1215,13 +1208,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "confirmă",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "Descriere (opțional)",
|
"translation": "Descriere (opțional)",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "Număr de telefon sau e-mail",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "Confirmat cu succes",
|
"translation": "Confirmat cu succes",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1600,45 +1579,45 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_email": {
|
"current_email": {
|
||||||
"translation": "",
|
"translation": "E-mail curent",
|
||||||
"defaultMessage": "Current email",
|
"defaultMessage": "Current email",
|
||||||
"description": "Label for old email",
|
"description": "Label for old email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_phone": {
|
"current_phone": {
|
||||||
"translation": "",
|
"translation": "Număr de telefon actual",
|
||||||
"defaultMessage": "Current phone number",
|
"defaultMessage": "Current phone number",
|
||||||
"description": "Label for old phone",
|
"description": "Label for old phone",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_email": {
|
"new_email": {
|
||||||
"translation": "",
|
"translation": "E-mail nou",
|
||||||
"defaultMessage": "New email",
|
"defaultMessage": "New email",
|
||||||
"description": "Prompt for entering a new email",
|
"description": "Prompt for entering a new email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_phone_number": {
|
"new_phone_number": {
|
||||||
"translation": "",
|
"translation": "Număr de telefon nou",
|
||||||
"defaultMessage": "New phone number",
|
"defaultMessage": "New phone number",
|
||||||
"description": "Prompt for entering a new telephone number",
|
"description": "Prompt for entering a new telephone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_email": {
|
"change_email": {
|
||||||
"translation": "",
|
"translation": "Schimbați adresa de e-mail",
|
||||||
"defaultMessage": "Change email",
|
"defaultMessage": "Change email",
|
||||||
"description": "Prompt to change current email",
|
"description": "Prompt to change current email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_phone": {
|
"change_phone": {
|
||||||
"translation": "",
|
"translation": "Schimbați numărul de telefon",
|
||||||
"defaultMessage": "Change phone number",
|
"defaultMessage": "Change phone number",
|
||||||
"description": "Prompt to change current phone number",
|
"description": "Prompt to change current phone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"call_busy": {
|
"call_busy": {
|
||||||
@@ -1661,5 +1640,12 @@
|
|||||||
"description": "Menu item [Unpin] for un-pinning the message.",
|
"description": "Menu item [Unpin] for un-pinning the message.",
|
||||||
"missing": true,
|
"missing": true,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "Inițializarea înregistrării audio a eșuat",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-34
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "Добавить",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "Добавить",
|
"translation": "Добавить",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -1000,7 +993,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "Список, напр. email:alice@example.com, tel:+17025550003...",
|
"translation": "Список, напр. email:alice@example.com, tel:+17025550003...",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1215,13 +1208,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "подтвердить",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "Описание (не обязательно)",
|
"translation": "Описание (не обязательно)",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "Телефон или емейл",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "Подтверждено успешно",
|
"translation": "Подтверждено успешно",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1600,45 +1579,45 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_email": {
|
"current_email": {
|
||||||
"translation": "",
|
"translation": "Текущий e-mail",
|
||||||
"defaultMessage": "Current email",
|
"defaultMessage": "Current email",
|
||||||
"description": "Label for old email",
|
"description": "Label for old email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_phone": {
|
"current_phone": {
|
||||||
"translation": "",
|
"translation": "Текущий номер телефона",
|
||||||
"defaultMessage": "Current phone number",
|
"defaultMessage": "Current phone number",
|
||||||
"description": "Label for old phone",
|
"description": "Label for old phone",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_email": {
|
"new_email": {
|
||||||
"translation": "",
|
"translation": "Новый e-mail",
|
||||||
"defaultMessage": "New email",
|
"defaultMessage": "New email",
|
||||||
"description": "Prompt for entering a new email",
|
"description": "Prompt for entering a new email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_phone_number": {
|
"new_phone_number": {
|
||||||
"translation": "",
|
"translation": "Новый номер телефона",
|
||||||
"defaultMessage": "New phone number",
|
"defaultMessage": "New phone number",
|
||||||
"description": "Prompt for entering a new telephone number",
|
"description": "Prompt for entering a new telephone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_email": {
|
"change_email": {
|
||||||
"translation": "",
|
"translation": "Изменить e-mail",
|
||||||
"defaultMessage": "Change email",
|
"defaultMessage": "Change email",
|
||||||
"description": "Prompt to change current email",
|
"description": "Prompt to change current email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_phone": {
|
"change_phone": {
|
||||||
"translation": "",
|
"translation": "Изменить номер телефона",
|
||||||
"defaultMessage": "Change phone number",
|
"defaultMessage": "Change phone number",
|
||||||
"description": "Prompt to change current phone number",
|
"description": "Prompt to change current phone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"call_busy": {
|
"call_busy": {
|
||||||
@@ -1661,5 +1640,12 @@
|
|||||||
"description": "Menu item [Unpin] for un-pinning the message.",
|
"description": "Menu item [Unpin] for un-pinning the message.",
|
||||||
"missing": true,
|
"missing": true,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "Не удалось инициализировать аудиозапись",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-36
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "新增其他人",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "新增成員",
|
"translation": "新增成員",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -593,10 +586,10 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"label_wire_transport": {
|
"label_wire_transport": {
|
||||||
"translation": "",
|
"translation": "線路傳輸:",
|
||||||
"defaultMessage": "Wire transport:",
|
"defaultMessage": "Wire transport:",
|
||||||
"description": "Label for wire transport selection in SettingsView",
|
"description": "Label for wire transport selection in SettingsView",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"label_you": {
|
"label_you": {
|
||||||
@@ -1000,7 +993,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "例如 email:alice@example.com, tel:17025550003... 的清單",
|
"translation": "例如 email:alice@example.com, tel:17025550003... 的清單",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1215,13 +1208,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "確認",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "說明(可選)",
|
"translation": "說明(可選)",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "電話號碼或電子郵件",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "確認成功",
|
"translation": "確認成功",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1600,45 +1579,45 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_email": {
|
"current_email": {
|
||||||
"translation": "",
|
"translation": "當前郵箱",
|
||||||
"defaultMessage": "Current email",
|
"defaultMessage": "Current email",
|
||||||
"description": "Label for old email",
|
"description": "Label for old email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_phone": {
|
"current_phone": {
|
||||||
"translation": "",
|
"translation": "當前電話號碼",
|
||||||
"defaultMessage": "Current phone number",
|
"defaultMessage": "Current phone number",
|
||||||
"description": "Label for old phone",
|
"description": "Label for old phone",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_email": {
|
"new_email": {
|
||||||
"translation": "",
|
"translation": "新電子郵件地址",
|
||||||
"defaultMessage": "New email",
|
"defaultMessage": "New email",
|
||||||
"description": "Prompt for entering a new email",
|
"description": "Prompt for entering a new email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_phone_number": {
|
"new_phone_number": {
|
||||||
"translation": "",
|
"translation": "新電話號碼",
|
||||||
"defaultMessage": "New phone number",
|
"defaultMessage": "New phone number",
|
||||||
"description": "Prompt for entering a new telephone number",
|
"description": "Prompt for entering a new telephone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_email": {
|
"change_email": {
|
||||||
"translation": "",
|
"translation": "更改郵箱",
|
||||||
"defaultMessage": "Change email",
|
"defaultMessage": "Change email",
|
||||||
"description": "Prompt to change current email",
|
"description": "Prompt to change current email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_phone": {
|
"change_phone": {
|
||||||
"translation": "",
|
"translation": "更改電話號碼",
|
||||||
"defaultMessage": "Change phone number",
|
"defaultMessage": "Change phone number",
|
||||||
"description": "Prompt to change current phone number",
|
"description": "Prompt to change current phone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"call_busy": {
|
"call_busy": {
|
||||||
@@ -1661,5 +1640,12 @@
|
|||||||
"description": "Menu item [Unpin] for un-pinning the message.",
|
"description": "Menu item [Unpin] for un-pinning the message.",
|
||||||
"missing": true,
|
"missing": true,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "初始化錄音失敗",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-34
@@ -97,13 +97,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"button_add_another": {
|
|
||||||
"translation": "加上另一个",
|
|
||||||
"defaultMessage": "Add another",
|
|
||||||
"description": "Call to action [+ add another]",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"button_add_members": {
|
"button_add_members": {
|
||||||
"translation": "添加成员",
|
"translation": "添加成员",
|
||||||
"defaultMessage": "Add members",
|
"defaultMessage": "Add members",
|
||||||
@@ -1000,7 +993,7 @@
|
|||||||
},
|
},
|
||||||
"search_placeholder": {
|
"search_placeholder": {
|
||||||
"translation": "列表如 email:alice@example.com, tel:+17025550003...",
|
"translation": "列表如 email:alice@example.com, tel:+17025550003...",
|
||||||
"defaultMessage": "List like email:alice@example.com, tel:17025550003...",
|
"defaultMessage": "List like alice@example.com, +17025550003...",
|
||||||
"description": "Placeholder in contacts search field",
|
"description": "Placeholder in contacts search field",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
@@ -1215,13 +1208,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"validate_credential_action": {
|
|
||||||
"translation": "确认",
|
|
||||||
"defaultMessage": "confirm",
|
|
||||||
"description": "Validate credentail call to action",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"description_editing_placeholder": {
|
"description_editing_placeholder": {
|
||||||
"translation": "说明(可选)",
|
"translation": "说明(可选)",
|
||||||
"defaultMessage": "Description (optional)",
|
"defaultMessage": "Description (optional)",
|
||||||
@@ -1431,13 +1417,6 @@
|
|||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"phone_or_email_prompt": {
|
|
||||||
"translation": "电话号码或电子邮件",
|
|
||||||
"defaultMessage": "Phone number or email",
|
|
||||||
"description": "Placeholer for phone or email",
|
|
||||||
"missing": false,
|
|
||||||
"obsolete": true
|
|
||||||
},
|
|
||||||
"cred_confirmed_successfully": {
|
"cred_confirmed_successfully": {
|
||||||
"translation": "确认成功",
|
"translation": "确认成功",
|
||||||
"defaultMessage": "Confirmed successfully",
|
"defaultMessage": "Confirmed successfully",
|
||||||
@@ -1600,45 +1579,45 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_email": {
|
"current_email": {
|
||||||
"translation": "",
|
"translation": "当前邮箱",
|
||||||
"defaultMessage": "Current email",
|
"defaultMessage": "Current email",
|
||||||
"description": "Label for old email",
|
"description": "Label for old email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"current_phone": {
|
"current_phone": {
|
||||||
"translation": "",
|
"translation": "当前电话号码",
|
||||||
"defaultMessage": "Current phone number",
|
"defaultMessage": "Current phone number",
|
||||||
"description": "Label for old phone",
|
"description": "Label for old phone",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_email": {
|
"new_email": {
|
||||||
"translation": "",
|
"translation": "新电子邮件地址",
|
||||||
"defaultMessage": "New email",
|
"defaultMessage": "New email",
|
||||||
"description": "Prompt for entering a new email",
|
"description": "Prompt for entering a new email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"new_phone_number": {
|
"new_phone_number": {
|
||||||
"translation": "",
|
"translation": "新电话号码",
|
||||||
"defaultMessage": "New phone number",
|
"defaultMessage": "New phone number",
|
||||||
"description": "Prompt for entering a new telephone number",
|
"description": "Prompt for entering a new telephone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_email": {
|
"change_email": {
|
||||||
"translation": "",
|
"translation": "更改邮箱",
|
||||||
"defaultMessage": "Change email",
|
"defaultMessage": "Change email",
|
||||||
"description": "Prompt to change current email",
|
"description": "Prompt to change current email",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"change_phone": {
|
"change_phone": {
|
||||||
"translation": "",
|
"translation": "更改电话号码",
|
||||||
"defaultMessage": "Change phone number",
|
"defaultMessage": "Change phone number",
|
||||||
"description": "Prompt to change current phone number",
|
"description": "Prompt to change current phone number",
|
||||||
"missing": true,
|
"missing": false,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"call_busy": {
|
"call_busy": {
|
||||||
@@ -1661,5 +1640,12 @@
|
|||||||
"description": "Menu item [Unpin] for un-pinning the message.",
|
"description": "Menu item [Unpin] for un-pinning the message.",
|
||||||
"missing": true,
|
"missing": true,
|
||||||
"obsolete": false
|
"obsolete": false
|
||||||
|
},
|
||||||
|
"failed_to_init_audio": {
|
||||||
|
"translation": "初始化录音失败",
|
||||||
|
"defaultMessage": "Failed to initialize audio recording",
|
||||||
|
"description": "Error message when audio is not available",
|
||||||
|
"missing": false,
|
||||||
|
"obsolete": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ export default class HashNavigation {
|
|||||||
const args = [];
|
const args = [];
|
||||||
for (const key in params) {
|
for (const key in params) {
|
||||||
if (params.hasOwnProperty(key)) {
|
if (params.hasOwnProperty(key)) {
|
||||||
args.push(key + '=' + encodeURIComponent(params[key]));
|
if (params[key] !== undefined) {
|
||||||
|
args.push(key + '=' + encodeURIComponent(params[key]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
|
|||||||
@@ -46,12 +46,21 @@ export default class AccountSettingsView extends React.Component {
|
|||||||
val={this.state.credEdit.val}
|
val={this.state.credEdit.val}
|
||||||
done={this.state.credEdit.done}
|
done={this.state.credEdit.done}
|
||||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||||
onSubmit={this.props.onCredAdd}
|
onCredAdd={this.props.onCredAdd}
|
||||||
|
onCredConfirm={this.props.onCredConfirm}
|
||||||
onCancel={_ => this.setState({credEdit: undefined})}
|
onCancel={_ => this.setState({credEdit: undefined})}
|
||||||
onError={this.props.onError} />
|
onError={this.props.onError} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Count how many times each method is validated.
|
||||||
|
const validated = {};
|
||||||
|
this.state.credentials.forEach(cred => {
|
||||||
|
if (cred.done) {
|
||||||
|
validated[cred.meth] = (validated[cred.meth] || 0) + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const credentials = [];
|
const credentials = [];
|
||||||
this.state.credentials.forEach((cred, idx) => {
|
this.state.credentials.forEach((cred, idx) => {
|
||||||
if (!['email', 'tel'].includes(cred.meth)) {
|
if (!['email', 'tel'].includes(cred.meth)) {
|
||||||
@@ -68,15 +77,14 @@ export default class AccountSettingsView extends React.Component {
|
|||||||
credentials.push(
|
credentials.push(
|
||||||
<div className="group quoted" key={idx}>
|
<div className="group quoted" key={idx}>
|
||||||
<tt className="clickable" onClick={e => {e.preventDefault(); this.setState({credEdit: cred});}}>{val}</tt>
|
<tt className="clickable" onClick={e => {e.preventDefault(); this.setState({credEdit: cred});}}>{val}</tt>
|
||||||
<span> {
|
<span> {cred.done ? null : <i className="material-icons">pending</i>}
|
||||||
cred.done ? null :
|
{!cred.done || validated[cred.meth] > 1 || this.props.reqCredMethod != cred.meth ?
|
||||||
<>
|
|
||||||
<i className="material-icons">pending</i>
|
|
||||||
<a href="#" onClick={e => {e.preventDefault(); this.props.onCredDelete(cred.meth, cred.val);}}>
|
<a href="#" onClick={e => {e.preventDefault(); this.props.onCredDelete(cred.meth, cred.val);}}>
|
||||||
<i className="material-icons">delete</i>
|
<i className="material-icons">delete</i>
|
||||||
</a>
|
</a>
|
||||||
</>
|
:
|
||||||
}</span>
|
null}
|
||||||
|
</span>
|
||||||
</div>);
|
</div>);
|
||||||
});
|
});
|
||||||
if (credentials.length > 0) {
|
if (credentials.length > 0) {
|
||||||
|
|||||||
+67
-28
@@ -21,8 +21,8 @@ import PinnedMessages from '../widgets/pinned-messages.jsx';
|
|||||||
import SendMessage from '../widgets/send-message.jsx';
|
import SendMessage from '../widgets/send-message.jsx';
|
||||||
import VideoPreview from '../widgets/video-preview.jsx';
|
import VideoPreview from '../widgets/video-preview.jsx';
|
||||||
|
|
||||||
import { DEFAULT_P2P_ACCESS_MODE, EDIT_PREVIEW_LENGTH, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY,
|
import { DEFAULT_P2P_ACCESS_MODE, EDIT_PREVIEW_LENGTH, IMAGE_PREVIEW_DIM, IMMEDIATE_P2P_SUBSCRIPTION,
|
||||||
MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE,
|
KEYPRESS_DELAY, MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE,
|
||||||
READ_DELAY, QUOTED_REPLY_LENGTH, VIDEO_PREVIEW_DIM } from '../config.js';
|
READ_DELAY, QUOTED_REPLY_LENGTH, VIDEO_PREVIEW_DIM } from '../config.js';
|
||||||
import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../constants.js';
|
import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../constants.js';
|
||||||
import { blobToBase64, fileToBase64, imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
import { blobToBase64, fileToBase64, imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
||||||
@@ -109,6 +109,7 @@ class MessagesView extends React.Component {
|
|||||||
|
|
||||||
this.state = MessagesView.getDerivedStateFromProps(props, {});
|
this.state = MessagesView.getDerivedStateFromProps(props, {});
|
||||||
|
|
||||||
|
this.componentSetup = this.componentSetup.bind(this);
|
||||||
this.leave = this.leave.bind(this);
|
this.leave = this.leave.bind(this);
|
||||||
this.sendMessage = this.sendMessage.bind(this);
|
this.sendMessage = this.sendMessage.bind(this);
|
||||||
this.retrySend = this.retrySend.bind(this);
|
this.retrySend = this.retrySend.bind(this);
|
||||||
@@ -156,8 +157,9 @@ class MessagesView extends React.Component {
|
|||||||
this.handleDrag = this.handleDrag.bind(this);
|
this.handleDrag = this.handleDrag.bind(this);
|
||||||
this.handleDrop = this.handleDrop.bind(this);
|
this.handleDrop = this.handleDrop.bind(this);
|
||||||
|
|
||||||
this.chatMessageRefs = {};
|
this.chatMessageRefs = [];
|
||||||
this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this);
|
this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this);
|
||||||
|
this.getVisibleMessageRange = this.getVisibleMessageRange.bind(this);
|
||||||
|
|
||||||
// Keeps track of the drag event.
|
// Keeps track of the drag event.
|
||||||
// Need a counter b/c the browser's 'drag' events may fire multiple times
|
// Need a counter b/c the browser's 'drag' events may fire multiple times
|
||||||
@@ -173,7 +175,7 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getOrCreateMessageRef(seqId) {
|
getOrCreateMessageRef(seqId) {
|
||||||
if (this.chatMessageRefs.hasOwnProperty(seqId)) {
|
if (this.chatMessageRefs[seqId]) {
|
||||||
return this.chatMessageRefs[seqId];
|
return this.chatMessageRefs[seqId];
|
||||||
}
|
}
|
||||||
const ref = React.createRef();
|
const ref = React.createRef();
|
||||||
@@ -181,6 +183,21 @@ class MessagesView extends React.Component {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getVisibleMessageRange(holderRect) {
|
||||||
|
let min = Number.MAX_SAFE_INTEGER, max = -1;
|
||||||
|
this.chatMessageRefs.forEach((ref, seq) => {
|
||||||
|
if (ref.current) {
|
||||||
|
const { top, bottom, height } = ref.current.getBoundingClientRect();
|
||||||
|
const visible = top <= holderRect.top ? holderRect.top - top <= height : bottom - holderRect.bottom <= height;
|
||||||
|
if (visible) {
|
||||||
|
min = Math.min(min, seq);
|
||||||
|
max = Math.max(max, seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return max >= min ? {min: min, max: max} : {min: 0, max: 0};
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (this.messagesScroller) {
|
if (this.messagesScroller) {
|
||||||
this.messagesScroller.addEventListener('scroll', this.handleScrollEvent);
|
this.messagesScroller.addEventListener('scroll', this.handleScrollEvent);
|
||||||
@@ -188,6 +205,8 @@ class MessagesView extends React.Component {
|
|||||||
|
|
||||||
// Drag and drop events
|
// Drag and drop events
|
||||||
this.mountDnDEvents(this.dndRef);
|
this.mountDnDEvents(this.dndRef);
|
||||||
|
|
||||||
|
this.componentSetup({}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@@ -208,9 +227,9 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll last message into view on component update e.g. on message received
|
|
||||||
// or vertical shrinking.
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
// Scroll last message into view on component update e.g. on message received
|
||||||
|
// or vertical shrinking.
|
||||||
if (this.messagesScroller &&
|
if (this.messagesScroller &&
|
||||||
(prevState.topic != this.state.topic || prevState.maxSeqId != this.state.maxSeqId ||
|
(prevState.topic != this.state.topic || prevState.maxSeqId != this.state.maxSeqId ||
|
||||||
prevState.minSeqId != this.state.minSeqId)) {
|
prevState.minSeqId != this.state.minSeqId)) {
|
||||||
@@ -221,6 +240,18 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.props.applicationVisible) {
|
||||||
|
// If application is not visible, flush all unsent 'read' notifications.
|
||||||
|
this.clearNotificationQueue();
|
||||||
|
} else {
|
||||||
|
// Otherwise assume there are unread messages.
|
||||||
|
this.postReadNotification(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.componentSetup(prevProps, prevState);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentSetup(prevProps, prevState) {
|
||||||
const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : undefined;
|
const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : undefined;
|
||||||
if (this.state.topic != prevState.topic) {
|
if (this.state.topic != prevState.topic) {
|
||||||
if (prevState.topic && !Tinode.isNewGroupTopicName(prevState.topic)) {
|
if (prevState.topic && !Tinode.isNewGroupTopicName(prevState.topic)) {
|
||||||
@@ -241,20 +272,18 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.props.applicationVisible) {
|
if (topic) {
|
||||||
// If application is not visible, flush all unsent 'read' notifications.
|
if ((this.state.topic != prevState.topic) || (this.props.myUserId && !prevProps.myUserId)) {
|
||||||
this.clearNotificationQueue();
|
// Don't immediately subscribe to a new p2p topic, wait for the first message.
|
||||||
} else {
|
const newTopic = (this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic);
|
||||||
// Otherwise assume there are unread messages.
|
if (topic.isP2PType() && newTopic && !IMMEDIATE_P2P_SUBSCRIPTION) {
|
||||||
this.postReadNotification(0);
|
topic.getMeta(topic.startMetaQuery().withDesc().build());
|
||||||
}
|
} else if (this.props.myUserId) {
|
||||||
|
this.subscribe(topic);
|
||||||
if (topic && ((this.state.topic != prevState.topic) || !prevProps.ready)) {
|
}
|
||||||
// Don't immediately subscribe to a new p2p topic, wait for the first message.
|
} else if (topic.isSubscribed() && this.state.isReader && !prevState.isReader) {
|
||||||
if (topic._new && topic.isP2PType()) {
|
// If reader status has changed and data became available.
|
||||||
topic.getMeta(topic.startMetaQuery().withDesc().build());
|
topic.getMeta(topic.startMetaQuery().withLaterData().build());
|
||||||
} else {
|
|
||||||
this.subscribe(topic);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,7 +477,6 @@ class MessagesView extends React.Component {
|
|||||||
|
|
||||||
// Is this a new topic?
|
// Is this a new topic?
|
||||||
const newTopic = (this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic);
|
const newTopic = (this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic);
|
||||||
|
|
||||||
// Don't request the tags. They are useless unless the user
|
// Don't request the tags. They are useless unless the user
|
||||||
// is the owner and is editing the topic.
|
// is the owner and is editing the topic.
|
||||||
let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub().withAux();
|
let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub().withAux();
|
||||||
@@ -473,6 +501,9 @@ class MessagesView extends React.Component {
|
|||||||
if (this.state.topic != ctrl.topic) {
|
if (this.state.topic != ctrl.topic) {
|
||||||
this.setState({topic: ctrl.topic});
|
this.setState({topic: ctrl.topic});
|
||||||
}
|
}
|
||||||
|
if (this.state.deleted) {
|
||||||
|
this.setState({deleted: false});
|
||||||
|
}
|
||||||
this.props.onNewTopicCreated(this.props.topic, ctrl.topic);
|
this.props.onNewTopicCreated(this.props.topic, ctrl.topic);
|
||||||
// If there are unsent messages (except hard-failed and video call messages),
|
// If there are unsent messages (except hard-failed and video call messages),
|
||||||
// try sending them now. Hard-failed and unsent video call messages will be dropped.
|
// try sending them now. Hard-failed and unsent video call messages will be dropped.
|
||||||
@@ -552,12 +583,16 @@ class MessagesView extends React.Component {
|
|||||||
|
|
||||||
if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) {
|
if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) {
|
||||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
if (topic && topic.isSubscribed() && topic.msgHasMoreMessages()) {
|
if (topic && topic.isSubscribed()) {
|
||||||
this.setState({fetchingMessages: true}, _ => {
|
const {min, max} = this.getVisibleMessageRange(event.target.getBoundingClientRect());
|
||||||
topic.getMessagesPage(MESSAGES_PAGE)
|
const gaps = topic.msgHasMoreMessages(min, max, false);
|
||||||
.catch(err => this.props.onError(err.message, 'err'))
|
if (gaps.length > 0) {
|
||||||
.finally(_ => this.setState({fetchingMessages: false}));
|
this.setState({fetchingMessages: true}, _ => {
|
||||||
});
|
topic.getMessagesPage(MESSAGES_PAGE, gaps, min, max)
|
||||||
|
.catch(err => this.props.onError(err.message, 'err'))
|
||||||
|
.finally(_ => this.setState({fetchingMessages: false}));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -737,6 +772,10 @@ class MessagesView extends React.Component {
|
|||||||
// 0 means "latest".
|
// 0 means "latest".
|
||||||
this.postReadNotification(0);
|
this.postReadNotification(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load pinned message too (if any);
|
||||||
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
|
topic.getPinnedMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAuxUpdate(aux) {
|
handleAuxUpdate(aux) {
|
||||||
@@ -1438,7 +1477,7 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pinnedMessages = [];
|
const pinnedMessages = [];
|
||||||
this.state.pins.forEach(seq => pinnedMessages.push(topic.latestMsgVersion(seq)));
|
this.state.pins.forEach(seq => pinnedMessages.push(topic.latestMsgVersion(seq) || topic.findMessage(seq)));
|
||||||
|
|
||||||
const messageNodes = [];
|
const messageNodes = [];
|
||||||
let previousFrom = null;
|
let previousFrom = null;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const messages = defineMessages({
|
|||||||
},
|
},
|
||||||
search_placeholder: {
|
search_placeholder: {
|
||||||
id: "search_placeholder",
|
id: "search_placeholder",
|
||||||
defaultMessage: "List like email:alice@example.com, tel:17025550003...",
|
defaultMessage: "List like alice@example.com, +17025550003...",
|
||||||
description: "Placeholder in contacts search field"
|
description: "Placeholder in contacts search field"
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -61,10 +61,10 @@ class NewTopicView extends React.Component {
|
|||||||
this.setState({searchQuery: Tinode.isNullValue(query) ? null : query});
|
this.setState({searchQuery: Tinode.isNullValue(query) ? null : query});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSearchResultSelected(name) {
|
handleSearchResultSelected(topicName) {
|
||||||
if (this.state.tabSelected == 'find') {
|
if (this.state.tabSelected == 'find') {
|
||||||
HashNavigation.navigateTo(HashNavigation.removeUrlParam(window.location.hash, 'tab'));
|
HashNavigation.navigateTo(HashNavigation.removeUrlParam(window.location.hash, 'tab'));
|
||||||
this.props.onCreateTopic(name);
|
this.props.onCreateTopic(topicName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class PasswordResetView extends React.PureComponent {
|
|||||||
// Reset using token.
|
// Reset using token.
|
||||||
this.props.onReset(this.state.password.trim(), {
|
this.props.onReset(this.state.password.trim(), {
|
||||||
scheme: 'token',
|
scheme: 'token',
|
||||||
token: this.state.token
|
secret: this.state.token
|
||||||
});
|
});
|
||||||
} else if (this.state.code && this.props.reqCredMethod) {
|
} else if (this.state.code && this.props.reqCredMethod) {
|
||||||
// Reset using security code.
|
// Reset using security code.
|
||||||
@@ -193,7 +193,7 @@ class PasswordResetView extends React.PureComponent {
|
|||||||
{this.state.haveCode || this.state.sent ? codeInput : null}
|
{this.state.haveCode || this.state.sent ? codeInput : null}
|
||||||
{showPasswordInput ? passwordInput : null}
|
{showPasswordInput ? passwordInput : null}
|
||||||
<div className="dialog-buttons">
|
<div className="dialog-buttons">
|
||||||
{this.state.haveCode || this.state.sent ? null :
|
{this.state.haveCode || this.state.sent || this.state.token ? null :
|
||||||
<a href="#" onClick={this.handleShowCodeField} style={{marginRight: 'auto'}}>
|
<a href="#" onClick={this.handleShowCodeField} style={{marginRight: 'auto'}}>
|
||||||
<FormattedMessage id="password_i_have_code" defaultMessage="I have code"
|
<FormattedMessage id="password_i_have_code" defaultMessage="I have code"
|
||||||
description="Call to open field to enter password reset code" />
|
description="Call to open field to enter password reset code" />
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ class SidepanelView extends React.PureComponent {
|
|||||||
tinode={this.props.tinode}
|
tinode={this.props.tinode}
|
||||||
myUserId={this.props.myUserId}
|
myUserId={this.props.myUserId}
|
||||||
trustedBadges={this.props.trustedBadges}
|
trustedBadges={this.props.trustedBadges}
|
||||||
|
reqCredMethod={this.props.reqCredMethod}
|
||||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||||
onNavigate={this.props.onNavigate}
|
onNavigate={this.props.onNavigate}
|
||||||
onCredAdd={this.props.onCredAdd}
|
onCredAdd={this.props.onCredAdd}
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ class TinodeWeb extends React.Component {
|
|||||||
}).then(token => {
|
}).then(token => {
|
||||||
if (token) {
|
if (token) {
|
||||||
return token;
|
return token;
|
||||||
} else {
|
} else if (typeof Notification != 'undefined') {
|
||||||
// Try to request permissions.
|
// Try to request permissions.
|
||||||
return Notification.requestPermission().then(permission => {
|
return Notification.requestPermission().then(permission => {
|
||||||
if (permission === 'granted') {
|
if (permission === 'granted') {
|
||||||
@@ -450,6 +450,7 @@ class TinodeWeb extends React.Component {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
throw new Error("Notifications are not supported");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,6 +762,7 @@ class TinodeWeb extends React.Component {
|
|||||||
parsed.path[0] = 'cred';
|
parsed.path[0] = 'cred';
|
||||||
parsed.params['method'] = params.cred[0];
|
parsed.params['method'] = params.cred[0];
|
||||||
parsed.params['token'] = params.token;
|
parsed.params['token'] = params.token;
|
||||||
|
parsed.params['code'] = params.code;
|
||||||
HashNavigation.navigateTo(HashNavigation.composeUrlHash(parsed.path, parsed.params));
|
HashNavigation.navigateTo(HashNavigation.composeUrlHash(parsed.path, parsed.params));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,7 +848,7 @@ class TinodeWeb extends React.Component {
|
|||||||
}
|
}
|
||||||
} else if (what == 'read') {
|
} else if (what == 'read') {
|
||||||
this.resetContactList();
|
this.resetContactList();
|
||||||
} else if (what == 'msg') {
|
} else if (what == 'msg' && cont) {
|
||||||
// Check if the topic is archived. If so, don't play a sound.
|
// Check if the topic is archived. If so, don't play a sound.
|
||||||
const topic = this.tinode.getTopic(cont.topic);
|
const topic = this.tinode.getTopic(cont.topic);
|
||||||
const archived = topic && topic.isArchived();
|
const archived = topic && topic.isArchived();
|
||||||
@@ -885,7 +887,7 @@ class TinodeWeb extends React.Component {
|
|||||||
} else {
|
} else {
|
||||||
// TODO(gene): handle other types of notifications:
|
// TODO(gene): handle other types of notifications:
|
||||||
// * ua -- user agent changes (maybe display a pictogram for mobile/desktop).
|
// * ua -- user agent changes (maybe display a pictogram for mobile/desktop).
|
||||||
console.info("Unsupported (yet) presence update:", what, "in", cont.topic);
|
console.info("Unsupported (yet) presence update:", what, "in", (cont || {}).topic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,6 +1019,7 @@ class TinodeWeb extends React.Component {
|
|||||||
} else {
|
} else {
|
||||||
// Currently selected contact deleted
|
// Currently selected contact deleted
|
||||||
this.setState({
|
this.setState({
|
||||||
|
topicSelected: null,
|
||||||
errorText: '',
|
errorText: '',
|
||||||
errorLevel: null,
|
errorLevel: null,
|
||||||
mobilePanel: 'sidepanel',
|
mobilePanel: 'sidepanel',
|
||||||
@@ -1285,7 +1288,7 @@ class TinodeWeb extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleCredConfirm(method, response) {
|
handleCredConfirm(method, response) {
|
||||||
TinodeWeb.navigateToCredentialsView({cred: [method]});
|
TinodeWeb.navigateToCredentialsView({cred: [method], code: response});
|
||||||
}
|
}
|
||||||
|
|
||||||
// User clicked Cancel button in Setting or Sign Up panel.
|
// User clicked Cancel button in Setting or Sign Up panel.
|
||||||
@@ -1333,7 +1336,7 @@ class TinodeWeb extends React.Component {
|
|||||||
|
|
||||||
const params = {};
|
const params = {};
|
||||||
if (Tinode.isP2PTopicName(topicName)) {
|
if (Tinode.isP2PTopicName(topicName)) {
|
||||||
// Because we are initialing the subscription, set 'want' to all permissions.
|
// Because we are initiating the subscription, set 'want' to all permissions.
|
||||||
params.sub = {mode: DEFAULT_P2P_ACCESS_MODE};
|
params.sub = {mode: DEFAULT_P2P_ACCESS_MODE};
|
||||||
// Give the other user all permissions too.
|
// Give the other user all permissions too.
|
||||||
params.desc = {defacs: {auth: DEFAULT_P2P_ACCESS_MODE}};
|
params.desc = {defacs: {auth: DEFAULT_P2P_ACCESS_MODE}};
|
||||||
@@ -1704,6 +1707,7 @@ class TinodeWeb extends React.Component {
|
|||||||
if (this.tinode.isAuthenticated()) {
|
if (this.tinode.isAuthenticated()) {
|
||||||
// Adding new email or phone number in account setting.
|
// Adding new email or phone number in account setting.
|
||||||
this.tinode.getMeTopic().setMeta({cred: {meth: cred, resp: code}})
|
this.tinode.getMeTopic().setMeta({cred: {meth: cred, resp: code}})
|
||||||
|
.then(_ => HashNavigation.navigateTo(HashNavigation.setUrlSidePanel(window.location.hash, 'contacts')))
|
||||||
.catch(err => this.handleError(err.message, 'err'));
|
.catch(err => this.handleError(err.message, 'err'));
|
||||||
} else {
|
} else {
|
||||||
// Credential validation on signup.
|
// Credential validation on signup.
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class ValidationView extends React.PureComponent {
|
|||||||
(numbers_only) => <input type="text" id="enter-confirmation-code"
|
(numbers_only) => <input type="text" id="enter-confirmation-code"
|
||||||
placeholder={numbers_only}
|
placeholder={numbers_only}
|
||||||
value={this.state.code} onChange={this.handleCodeChange}
|
value={this.state.code} onChange={this.handleCodeChange}
|
||||||
onKeyPress={this.handleKeyPress} required />
|
onKeyDown={this.handleKeyPress} required />
|
||||||
}</FormattedMessage>
|
}</FormattedMessage>
|
||||||
</div>
|
</div>
|
||||||
<div className="dialog-buttons">
|
<div className="dialog-buttons">
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class AudioPlayer extends React.PureComponent {
|
|||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.audioPlayer) {
|
if (this.audioPlayer) {
|
||||||
this.audioPlayer.oncanplay = null;
|
this.audioPlayer.onloadedmetadata = null;
|
||||||
this.audioPlayer.ontimeupdate = null;
|
this.audioPlayer.ontimeupdate = null;
|
||||||
this.audioPlayer.onended = null;
|
this.audioPlayer.onended = null;
|
||||||
this.audioPlayer.pause();
|
this.audioPlayer.pause();
|
||||||
@@ -94,7 +94,7 @@ class AudioPlayer extends React.PureComponent {
|
|||||||
|
|
||||||
initAudio() {
|
initAudio() {
|
||||||
this.audioPlayer = new Audio(this.props.src);
|
this.audioPlayer = new Audio(this.props.src);
|
||||||
this.audioPlayer.oncanplay = _ => this.setState({canPlay: true});
|
this.audioPlayer.onloadedmetadata = _ => this.setState({canPlay: true});
|
||||||
this.audioPlayer.ontimeupdate = _ => this.setState({
|
this.audioPlayer.ontimeupdate = _ => this.setState({
|
||||||
currentTime: secondsToTime(this.audioPlayer.currentTime, this.state.longMin)
|
currentTime: secondsToTime(this.audioPlayer.currentTime, this.state.longMin)
|
||||||
});
|
});
|
||||||
@@ -149,7 +149,7 @@ class AudioPlayer extends React.PureComponent {
|
|||||||
this.canvasContext.strokeStyle = BAR_COLOR_DARK;
|
this.canvasContext.strokeStyle = BAR_COLOR_DARK;
|
||||||
for (let i = 0; i < this.viewBuffer.length; i++) {
|
for (let i = 0; i < this.viewBuffer.length; i++) {
|
||||||
let x = 1 + i * (LINE_WIDTH + SPACING) + LINE_WIDTH * 0.5;
|
let x = 1 + i * (LINE_WIDTH + SPACING) + LINE_WIDTH * 0.5;
|
||||||
let y = this.viewBuffer[i] * height * 0.9;
|
let y = Math.max(this.viewBuffer[i] * height * 0.9, 1);
|
||||||
|
|
||||||
const color = x < thumbAt ? BAR_COLOR_DARK : BAR_COLOR;
|
const color = x < thumbAt ? BAR_COLOR_DARK : BAR_COLOR;
|
||||||
if (this.canvasContext.strokeStyle != color) {
|
if (this.canvasContext.strokeStyle != color) {
|
||||||
@@ -159,7 +159,7 @@ class AudioPlayer extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.canvasContext.moveTo(x, (height - y) * 0.5);
|
this.canvasContext.moveTo(x, (height - y) * 0.5);
|
||||||
this.canvasContext.lineTo(x, height * 0.5 + y * 0.5);
|
this.canvasContext.lineTo(x, (height + y) * 0.5);
|
||||||
}
|
}
|
||||||
// Actually draw the bars on canvas.
|
// Actually draw the bars on canvas.
|
||||||
this.canvasContext.stroke();
|
this.canvasContext.stroke();
|
||||||
@@ -216,10 +216,11 @@ class AudioPlayer extends React.PureComponent {
|
|||||||
if (!this.state.canPlay) {
|
if (!this.state.canPlay) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.playing) {
|
if (this.state.playing) {
|
||||||
this.audioPlayer.pause();
|
this.audioPlayer.pause();
|
||||||
this.setState({playing: false});
|
this.setState({playing: false});
|
||||||
} else {
|
} else if (this.audioPlayer.readyState >= 2) {
|
||||||
this.audioPlayer.play();
|
this.audioPlayer.play();
|
||||||
this.setState({playing: true}, this.visualize);
|
this.setState({playing: true}, this.visualize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,8 +31,11 @@ const VISUALIZATION_BARS = 96;
|
|||||||
// Maximum number of samples per bar.
|
// Maximum number of samples per bar.
|
||||||
const MAX_SAMPLES_PER_BAR = 10;
|
const MAX_SAMPLES_PER_BAR = 10;
|
||||||
|
|
||||||
// Recording format.
|
// Default recording format (FF, Chrome except on iOS).
|
||||||
const AUDIO_MIME_TYPE = 'audio/webm';
|
const DEFAULT_AUDIO_MIME_TYPE = 'audio/webm';
|
||||||
|
// Safari supports only mp4 as audio recording format.
|
||||||
|
const SAFARI_AUDIO_MIME_TYPE = 'audio/mp4';
|
||||||
|
const AUDIO_MIME_TYPES = [DEFAULT_AUDIO_MIME_TYPE, SAFARI_AUDIO_MIME_TYPE, ''];
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
icon_title_delete: {
|
icon_title_delete: {
|
||||||
@@ -55,6 +58,11 @@ const messages = defineMessages({
|
|||||||
defaultMessage: 'Send message',
|
defaultMessage: 'Send message',
|
||||||
description: 'Icon tool tip for sending a message'
|
description: 'Icon tool tip for sending a message'
|
||||||
},
|
},
|
||||||
|
failed_to_init_audio: {
|
||||||
|
id: 'failed_to_init_audio',
|
||||||
|
defaultMessage: 'Failed to initialize audio recording',
|
||||||
|
description: 'Error message when audio is not available'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class AudioRecorder extends React.PureComponent {
|
class AudioRecorder extends React.PureComponent {
|
||||||
@@ -188,10 +196,10 @@ class AudioRecorder extends React.PureComponent {
|
|||||||
this.canvasContext.beginPath();
|
this.canvasContext.beginPath();
|
||||||
for (let i = 0; i < this.viewBuffer.length; i++) {
|
for (let i = 0; i < this.viewBuffer.length; i++) {
|
||||||
let x = i * (LINE_WIDTH + SPACING) - dx;
|
let x = i * (LINE_WIDTH + SPACING) - dx;
|
||||||
let y = Math.min(this.viewBuffer[i] / BAR_SCALE, 0.9) * height;
|
let y = Math.max(Math.min(this.viewBuffer[i] / BAR_SCALE, 0.9) * height, 1);
|
||||||
|
|
||||||
this.canvasContext.moveTo(x, (height - y) * 0.5);
|
this.canvasContext.moveTo(x, (height - y) * 0.5);
|
||||||
this.canvasContext.lineTo(x, height * 0.5 + y * 0.5);
|
this.canvasContext.lineTo(x, (height + y) * 0.5);
|
||||||
}
|
}
|
||||||
// Actually draw the bars on canvas.
|
// Actually draw the bars on canvas.
|
||||||
this.canvasContext.stroke();
|
this.canvasContext.stroke();
|
||||||
@@ -261,11 +269,29 @@ class AudioRecorder extends React.PureComponent {
|
|||||||
|
|
||||||
initMediaRecording(stream) {
|
initMediaRecording(stream) {
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.mediaRecorder = new MediaRecorder(stream, {mimeType: AUDIO_MIME_TYPE, audioBitsPerSecond: 24_000});
|
AUDIO_MIME_TYPES.some(mimeType => {
|
||||||
|
if (MediaRecorder.isTypeSupported(mimeType)) {
|
||||||
|
this.mediaRecorder = new MediaRecorder(stream, {mimeType: mimeType, audioBitsPerSecond: 24_000});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.mediaRecorder) {
|
||||||
|
console.warn('MediaRecorder failed to initialize: no supported audio formats');
|
||||||
|
this.props.onError(this.props.intl.formatMessage(messages.failed_to_init_audio));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The following code is needed for visualization.
|
// The following code is needed for visualization.
|
||||||
this.audioContext = new AudioContext();
|
this.audioContext = new AudioContext();
|
||||||
this.audioInput = this.audioContext.createMediaStreamSource(stream);
|
this.audioInput = this.audioContext.createMediaStreamSource(stream);
|
||||||
|
if (!this.audioInput) {
|
||||||
|
console.warn('createMediaStreamSource returned null: audio input unavailable');
|
||||||
|
this.props.onError(this.props.intl.formatMessage(messages.failed_to_init_audio));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.analyser = this.audioContext.createAnalyser();
|
this.analyser = this.audioContext.createAnalyser();
|
||||||
this.analyser.fftSize = BUFFER_SIZE;
|
this.analyser.fftSize = BUFFER_SIZE;
|
||||||
this.audioInput.connect(this.analyser);
|
this.audioInput.connect(this.analyser);
|
||||||
@@ -305,11 +331,14 @@ class AudioRecorder extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtain data in a form sutable for sending or playing back.
|
// Obtain data in a form sutable for sending or playing back.
|
||||||
// If duration is valid, apply fix for Chrome's WebM duration bug.
|
|
||||||
getRecording(mimeType) {
|
getRecording(mimeType) {
|
||||||
mimeType = mimeType || AUDIO_MIME_TYPE;
|
mimeType = mimeType || DEFAULT_AUDIO_MIME_TYPE;
|
||||||
let blob = new Blob(this.audioChunks, {type: mimeType});
|
let blob = new Blob(this.audioChunks, {type: mimeType});
|
||||||
return fixWebmDuration(blob, mimeType)
|
// If duration is valid, apply fix for Chrome's WebM duration bug.
|
||||||
|
const result = mimeType == DEFAULT_AUDIO_MIME_TYPE ?
|
||||||
|
fixWebmDuration(blob, mimeType) :
|
||||||
|
Promise.resolve(blob);
|
||||||
|
return result
|
||||||
.then(fixedBlob => { blob = fixedBlob; return fixedBlob.arrayBuffer(); })
|
.then(fixedBlob => { blob = fixedBlob; return fixedBlob.arrayBuffer(); })
|
||||||
.then(arrayBuff => this.audioContext.decodeAudioData(arrayBuff))
|
.then(arrayBuff => this.audioContext.decodeAudioData(arrayBuff))
|
||||||
.then(decoded => this.createPreview(decoded))
|
.then(decoded => this.createPreview(decoded))
|
||||||
@@ -347,7 +376,9 @@ class AudioRecorder extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cleanUp() {
|
cleanUp() {
|
||||||
this.audioInput.disconnect();
|
if (this.audioInput) {
|
||||||
|
this.audioInput.disconnect();
|
||||||
|
}
|
||||||
this.stream.getTracks().forEach(track => track.stop());
|
this.stream.getTracks().forEach(track => track.stop());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,8 +58,11 @@ class CredentialEdit extends React.PureComponent {
|
|||||||
handleSubmit(e) {
|
handleSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const value = this.props.method == 'email' ? this.state.email : this.state.tel;
|
const value = this.props.method == 'email' ? this.state.email : this.state.tel;
|
||||||
if (value) {
|
if (this.state.code) {
|
||||||
this.props.onSubmit(this.props.method, value);
|
this.props.onError(null);
|
||||||
|
this.props.onCredConfirm(this.props.method, this.state.code);
|
||||||
|
} else if (value) {
|
||||||
|
this.props.onCredAdd(this.props.method, value);
|
||||||
this.setState({sent: true});
|
this.setState({sent: true});
|
||||||
const msg = this.props.method == 'email' ? messages.password_reset_email_sent : messages.password_reset_sms_sent;
|
const msg = this.props.method == 'email' ? messages.password_reset_email_sent : messages.password_reset_sms_sent;
|
||||||
this.props.onError(this.props.intl.formatMessage(msg), 'info');
|
this.props.onError(this.props.intl.formatMessage(msg), 'info');
|
||||||
@@ -68,8 +71,8 @@ class CredentialEdit extends React.PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const readyForCode = this.state.sent || !this.props.done;
|
const readyForCode = this.state.sent || !this.props.done;
|
||||||
const currentValue = CredentialEdit.formatPhoneNumber(readyForCode ?
|
const rawValue = readyForCode ? (this.state.tel || this.state.email) : this.props.val;
|
||||||
(this.state.tel || this.state.email) : this.props.val);
|
const formattedValue = this.props.method == 'tel' ? CredentialEdit.formatPhoneNumber(rawValue) : rawValue;
|
||||||
|
|
||||||
const changeEmail = (
|
const changeEmail = (
|
||||||
<><div className="panel-form-row">
|
<><div className="panel-form-row">
|
||||||
@@ -140,21 +143,19 @@ class CredentialEdit extends React.PureComponent {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (<form className="panel-form-column" onSubmit={this.handleSubmit}>
|
return (<form className="panel-form-column" onSubmit={this.handleSubmit}>
|
||||||
{readyForCode ? null :
|
{readyForCode ?
|
||||||
this.props.method == 'email' ?
|
(this.props.method == 'email' ? newEmailLabel : this.props.method == 'tel' ? newPhoneLabel : null)
|
||||||
changeEmail
|
:
|
||||||
: this.props.method == 'tel' ?
|
(this.props.method == 'email' ? changeEmail : this.props.method == 'tel' ? changePhone : null)
|
||||||
changePhone
|
}
|
||||||
: null}
|
|
||||||
<div className="panel-form-row">
|
<div className="panel-form-row">
|
||||||
<tt className="quoted">{currentValue}</tt>
|
<tt className="quoted">{formattedValue}</tt>
|
||||||
</div>
|
</div>
|
||||||
{readyForCode ? null :
|
{readyForCode ?
|
||||||
this.props.method == 'email' ?
|
null
|
||||||
newEmailInput
|
:
|
||||||
: this.props.method == 'tel' ?
|
(this.props.method == 'email' ? newEmailInput : this.props.method == 'tel' ? newPhoneInput : null)
|
||||||
newPhoneInput
|
}
|
||||||
: null}
|
|
||||||
{readyForCode ? codeInput : null}
|
{readyForCode ? codeInput : null}
|
||||||
<div className="dialog-buttons">
|
<div className="dialog-buttons">
|
||||||
<button className="secondary" onClick={this.props.onCancel}>
|
<button className="secondary" onClick={this.props.onCancel}>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export default class ErrorPanel extends React.PureComponent {
|
|||||||
{this.props.text}
|
{this.props.text}
|
||||||
{this.props.action ?
|
{this.props.action ?
|
||||||
<>
|
<>
|
||||||
 <a href="#"
|
 <a href="#"
|
||||||
style={{ whiteSpace: 'nowrap' }}
|
style={{ whiteSpace: 'nowrap' }}
|
||||||
onClick={(e) => {e.preventDefault(); this.props.action();}}>
|
onClick={(e) => {e.preventDefault(); this.props.action();}}>
|
||||||
{this.props.actionText}
|
{this.props.actionText}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class PinnedMessages extends React.PureComponent {
|
|||||||
<div><i className="material-icons gray">push_pin</i></div>
|
<div><i className="material-icons gray">push_pin</i></div>
|
||||||
}
|
}
|
||||||
<div className="pinned-scroll">{dots}</div>
|
<div className="pinned-scroll">{dots}</div>
|
||||||
<div className="pinned" onClick={this.handleSelected}>{shown}</div>
|
<div className="pinned" onClick={this.handleSelected}><p>{shown}</p></div>
|
||||||
{selected > 0 ?
|
{selected > 0 ?
|
||||||
<span className="menuTrigger upper">
|
<span className="menuTrigger upper">
|
||||||
<a href="#" onClick={this.handleMovePrev}>
|
<a href="#" onClick={this.handleMovePrev}>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export default class VisiblePassword extends React.PureComponent {
|
|||||||
this.inputRef = React.createRef();
|
this.inputRef = React.createRef();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
value: this.props.value,
|
value: this.props.value || '',
|
||||||
visible: false
|
visible: false
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export default class VisiblePassword extends React.PureComponent {
|
|||||||
handleKeyDown(e) {
|
handleKeyDown(e) {
|
||||||
if (e.keyCode == 27) {
|
if (e.keyCode == 27) {
|
||||||
// Escape pressed
|
// Escape pressed
|
||||||
this.setState({value: this.props.value, visible: false});
|
this.setState({value: this.props.value || '', visible: false});
|
||||||
if (this.props.onFinished) {
|
if (this.props.onFinished) {
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ export default class VisiblePassword extends React.PureComponent {
|
|||||||
return (
|
return (
|
||||||
<div tabIndex="-1" className="group-focus" onBlur={this.handleEditingFinished}>
|
<div tabIndex="-1" className="group-focus" onBlur={this.handleEditingFinished}>
|
||||||
<input className="with-visibility"
|
<input className="with-visibility"
|
||||||
type={this.state.visible ? "text" : "password"}
|
type={this.state.visible ? 'text' : 'password'}
|
||||||
value={this.state.value}
|
value={this.state.value}
|
||||||
placeholder={this.props.placeholder}
|
placeholder={this.props.placeholder}
|
||||||
required={this.props.required ? 'required' : ''}
|
required={this.props.required ? 'required' : ''}
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+103
-44
@@ -2212,6 +2212,7 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
/* harmony export */ "FORWARDED_PREVIEW_LENGTH": () => (/* binding */ FORWARDED_PREVIEW_LENGTH),
|
/* harmony export */ "FORWARDED_PREVIEW_LENGTH": () => (/* binding */ FORWARDED_PREVIEW_LENGTH),
|
||||||
/* harmony export */ "IMAGE_PREVIEW_DIM": () => (/* binding */ IMAGE_PREVIEW_DIM),
|
/* harmony export */ "IMAGE_PREVIEW_DIM": () => (/* binding */ IMAGE_PREVIEW_DIM),
|
||||||
/* harmony export */ "IMAGE_THUMBNAIL_DIM": () => (/* binding */ IMAGE_THUMBNAIL_DIM),
|
/* harmony export */ "IMAGE_THUMBNAIL_DIM": () => (/* binding */ IMAGE_THUMBNAIL_DIM),
|
||||||
|
/* harmony export */ "IMMEDIATE_P2P_SUBSCRIPTION": () => (/* binding */ IMMEDIATE_P2P_SUBSCRIPTION),
|
||||||
/* harmony export */ "KEYPRESS_DELAY": () => (/* binding */ KEYPRESS_DELAY),
|
/* harmony export */ "KEYPRESS_DELAY": () => (/* binding */ KEYPRESS_DELAY),
|
||||||
/* harmony export */ "KNOWN_HOSTS": () => (/* binding */ KNOWN_HOSTS),
|
/* harmony export */ "KNOWN_HOSTS": () => (/* binding */ KNOWN_HOSTS),
|
||||||
/* harmony export */ "LINK_CONTACT_US": () => (/* binding */ LINK_CONTACT_US),
|
/* harmony export */ "LINK_CONTACT_US": () => (/* binding */ LINK_CONTACT_US),
|
||||||
@@ -2289,6 +2290,7 @@ const MAX_DURATION = 600_000;
|
|||||||
const LINK_CONTACT_US = 'mailto:support@tinode.co';
|
const LINK_CONTACT_US = 'mailto:support@tinode.co';
|
||||||
const LINK_PRIVACY_POLICY = 'https://tinode.co/privacy.html';
|
const LINK_PRIVACY_POLICY = 'https://tinode.co/privacy.html';
|
||||||
const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html';
|
const LINK_TERMS_OF_SERVICE = 'https://tinode.co/terms.html';
|
||||||
|
const IMMEDIATE_P2P_SUBSCRIPTION = false;
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
@@ -3239,7 +3241,9 @@ class HashNavigation {
|
|||||||
const args = [];
|
const args = [];
|
||||||
for (const key in params) {
|
for (const key in params) {
|
||||||
if (params.hasOwnProperty(key)) {
|
if (params.hasOwnProperty(key)) {
|
||||||
args.push(key + '=' + encodeURIComponent(params[key]));
|
if (params[key] !== undefined) {
|
||||||
|
args.push(key + '=' + encodeURIComponent(params[key]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
@@ -5181,6 +5185,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = MessagesView.getDerivedStateFromProps(props, {});
|
this.state = MessagesView.getDerivedStateFromProps(props, {});
|
||||||
|
this.componentSetup = this.componentSetup.bind(this);
|
||||||
this.leave = this.leave.bind(this);
|
this.leave = this.leave.bind(this);
|
||||||
this.sendMessage = this.sendMessage.bind(this);
|
this.sendMessage = this.sendMessage.bind(this);
|
||||||
this.retrySend = this.retrySend.bind(this);
|
this.retrySend = this.retrySend.bind(this);
|
||||||
@@ -5225,8 +5230,9 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
this.handleDragOut = this.handleDragOut.bind(this);
|
this.handleDragOut = this.handleDragOut.bind(this);
|
||||||
this.handleDrag = this.handleDrag.bind(this);
|
this.handleDrag = this.handleDrag.bind(this);
|
||||||
this.handleDrop = this.handleDrop.bind(this);
|
this.handleDrop = this.handleDrop.bind(this);
|
||||||
this.chatMessageRefs = {};
|
this.chatMessageRefs = [];
|
||||||
this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this);
|
this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this);
|
||||||
|
this.getVisibleMessageRange = this.getVisibleMessageRange.bind(this);
|
||||||
this.dragCounter = 0;
|
this.dragCounter = 0;
|
||||||
this.dndRef = null;
|
this.dndRef = null;
|
||||||
this.readNotificationQueue = [];
|
this.readNotificationQueue = [];
|
||||||
@@ -5234,18 +5240,44 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
this.keyPressTimer = null;
|
this.keyPressTimer = null;
|
||||||
}
|
}
|
||||||
getOrCreateMessageRef(seqId) {
|
getOrCreateMessageRef(seqId) {
|
||||||
if (this.chatMessageRefs.hasOwnProperty(seqId)) {
|
if (this.chatMessageRefs[seqId]) {
|
||||||
return this.chatMessageRefs[seqId];
|
return this.chatMessageRefs[seqId];
|
||||||
}
|
}
|
||||||
const ref = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
|
const ref = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
|
||||||
this.chatMessageRefs[seqId] = ref;
|
this.chatMessageRefs[seqId] = ref;
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
getVisibleMessageRange(holderRect) {
|
||||||
|
let min = Number.MAX_SAFE_INTEGER,
|
||||||
|
max = -1;
|
||||||
|
this.chatMessageRefs.forEach((ref, seq) => {
|
||||||
|
if (ref.current) {
|
||||||
|
const {
|
||||||
|
top,
|
||||||
|
bottom,
|
||||||
|
height
|
||||||
|
} = ref.current.getBoundingClientRect();
|
||||||
|
const visible = top <= holderRect.top ? holderRect.top - top <= height : bottom - holderRect.bottom <= height;
|
||||||
|
if (visible) {
|
||||||
|
min = Math.min(min, seq);
|
||||||
|
max = Math.max(max, seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return max >= min ? {
|
||||||
|
min: min,
|
||||||
|
max: max
|
||||||
|
} : {
|
||||||
|
min: 0,
|
||||||
|
max: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (this.messagesScroller) {
|
if (this.messagesScroller) {
|
||||||
this.messagesScroller.addEventListener('scroll', this.handleScrollEvent);
|
this.messagesScroller.addEventListener('scroll', this.handleScrollEvent);
|
||||||
}
|
}
|
||||||
this.mountDnDEvents(this.dndRef);
|
this.mountDnDEvents(this.dndRef);
|
||||||
|
this.componentSetup({}, {});
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.messagesScroller) {
|
if (this.messagesScroller) {
|
||||||
@@ -5266,6 +5298,14 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight;
|
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!this.props.applicationVisible) {
|
||||||
|
this.clearNotificationQueue();
|
||||||
|
} else {
|
||||||
|
this.postReadNotification(0);
|
||||||
|
}
|
||||||
|
this.componentSetup(prevProps, prevState);
|
||||||
|
}
|
||||||
|
componentSetup(prevProps, prevState) {
|
||||||
const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : undefined;
|
const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : undefined;
|
||||||
if (this.state.topic != prevState.topic) {
|
if (this.state.topic != prevState.topic) {
|
||||||
if (prevState.topic && !tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNewGroupTopicName(prevState.topic)) {
|
if (prevState.topic && !tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNewGroupTopicName(prevState.topic)) {
|
||||||
@@ -5284,16 +5324,16 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
topic.onAuxUpdated = this.handleAuxUpdate;
|
topic.onAuxUpdated = this.handleAuxUpdate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!this.props.applicationVisible) {
|
if (topic) {
|
||||||
this.clearNotificationQueue();
|
if (this.state.topic != prevState.topic || this.props.myUserId && !prevProps.myUserId) {
|
||||||
} else {
|
const newTopic = this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic;
|
||||||
this.postReadNotification(0);
|
if (topic.isP2PType() && newTopic && !_config_js__WEBPACK_IMPORTED_MODULE_18__.IMMEDIATE_P2P_SUBSCRIPTION) {
|
||||||
}
|
topic.getMeta(topic.startMetaQuery().withDesc().build());
|
||||||
if (topic && (this.state.topic != prevState.topic || !prevProps.ready)) {
|
} else if (this.props.myUserId) {
|
||||||
if (topic._new && topic.isP2PType()) {
|
this.subscribe(topic);
|
||||||
topic.getMeta(topic.startMetaQuery().withDesc().build());
|
}
|
||||||
} else {
|
} else if (topic.isSubscribed() && this.state.isReader && !prevState.isReader) {
|
||||||
this.subscribe(topic);
|
topic.getMeta(topic.startMetaQuery().withLaterData().build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5485,6 +5525,11 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
topic: ctrl.topic
|
topic: ctrl.topic
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (this.state.deleted) {
|
||||||
|
this.setState({
|
||||||
|
deleted: false
|
||||||
|
});
|
||||||
|
}
|
||||||
this.props.onNewTopicCreated(this.props.topic, ctrl.topic);
|
this.props.onNewTopicCreated(this.props.topic, ctrl.topic);
|
||||||
let discard = [];
|
let discard = [];
|
||||||
topic.queuedMessages(pub => {
|
topic.queuedMessages(pub => {
|
||||||
@@ -5548,14 +5593,21 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
}
|
}
|
||||||
if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) {
|
if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) {
|
||||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
if (topic && topic.isSubscribed() && topic.msgHasMoreMessages()) {
|
if (topic && topic.isSubscribed()) {
|
||||||
this.setState({
|
const {
|
||||||
fetchingMessages: true
|
min,
|
||||||
}, _ => {
|
max
|
||||||
topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_18__.MESSAGES_PAGE).catch(err => this.props.onError(err.message, 'err')).finally(_ => this.setState({
|
} = this.getVisibleMessageRange(event.target.getBoundingClientRect());
|
||||||
fetchingMessages: false
|
const gaps = topic.msgHasMoreMessages(min, max, false);
|
||||||
}));
|
if (gaps.length > 0) {
|
||||||
});
|
this.setState({
|
||||||
|
fetchingMessages: true
|
||||||
|
}, _ => {
|
||||||
|
topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_18__.MESSAGES_PAGE, gaps, min, max).catch(err => this.props.onError(err.message, 'err')).finally(_ => this.setState({
|
||||||
|
fetchingMessages: false
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5715,6 +5767,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
this.postReadNotification(0);
|
this.postReadNotification(0);
|
||||||
}
|
}
|
||||||
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
|
topic.getPinnedMessages();
|
||||||
}
|
}
|
||||||
handleAuxUpdate(aux) {
|
handleAuxUpdate(aux) {
|
||||||
const pins = (aux['pins'] || []).slice();
|
const pins = (aux['pins'] || []).slice();
|
||||||
@@ -6337,7 +6391,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const pinnedMessages = [];
|
const pinnedMessages = [];
|
||||||
this.state.pins.forEach(seq => pinnedMessages.push(topic.latestMsgVersion(seq)));
|
this.state.pins.forEach(seq => pinnedMessages.push(topic.latestMsgVersion(seq) || topic.findMessage(seq)));
|
||||||
const messageNodes = [];
|
const messageNodes = [];
|
||||||
let previousFrom = null;
|
let previousFrom = null;
|
||||||
let prevDate = null;
|
let prevDate = null;
|
||||||
@@ -6640,7 +6694,7 @@ const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
|||||||
id: "search_placeholder",
|
id: "search_placeholder",
|
||||||
defaultMessage: [{
|
defaultMessage: [{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "List like email:alice@example.com, tel:17025550003..."
|
"value": "List like alice@example.com, +17025550003..."
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -6673,10 +6727,10 @@ class NewTopicView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
searchQuery: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNullValue(query) ? null : query
|
searchQuery: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNullValue(query) ? null : query
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
handleSearchResultSelected(name) {
|
handleSearchResultSelected(topicName) {
|
||||||
if (this.state.tabSelected == 'find') {
|
if (this.state.tabSelected == 'find') {
|
||||||
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParam(window.location.hash, 'tab'));
|
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_7__["default"].removeUrlParam(window.location.hash, 'tab'));
|
||||||
this.props.onCreateTopic(name);
|
this.props.onCreateTopic(topicName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleNewGroupSubmit(name, description, dataUrl, priv, tags, isChannel) {
|
handleNewGroupSubmit(name, description, dataUrl, priv, tags, isChannel) {
|
||||||
@@ -7144,6 +7198,7 @@ class SidepanelView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
tinode: this.props.tinode,
|
tinode: this.props.tinode,
|
||||||
myUserId: this.props.myUserId,
|
myUserId: this.props.myUserId,
|
||||||
trustedBadges: this.props.trustedBadges,
|
trustedBadges: this.props.trustedBadges,
|
||||||
|
reqCredMethod: this.props.reqCredMethod,
|
||||||
onShowCountrySelector: this.props.onShowCountrySelector,
|
onShowCountrySelector: this.props.onShowCountrySelector,
|
||||||
onNavigate: this.props.onNavigate,
|
onNavigate: this.props.onNavigate,
|
||||||
onCredAdd: this.props.onCredAdd,
|
onCredAdd: this.props.onCredAdd,
|
||||||
@@ -7657,7 +7712,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
|||||||
}).then(token => {
|
}).then(token => {
|
||||||
if (token) {
|
if (token) {
|
||||||
return token;
|
return token;
|
||||||
} else {
|
} else if (typeof Notification != 'undefined') {
|
||||||
return Notification.requestPermission().then(permission => {
|
return Notification.requestPermission().then(permission => {
|
||||||
if (permission === 'granted') {
|
if (permission === 'granted') {
|
||||||
return (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getToken)(fcm, {
|
return (0,firebase_messaging__WEBPACK_IMPORTED_MODULE_3__.getToken)(fcm, {
|
||||||
@@ -7675,6 +7730,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
throw new Error("Notifications are not supported");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
handleResize() {
|
handleResize() {
|
||||||
@@ -7957,6 +8013,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
|||||||
parsed.path[0] = 'cred';
|
parsed.path[0] = 'cred';
|
||||||
parsed.params['method'] = params.cred[0];
|
parsed.params['method'] = params.cred[0];
|
||||||
parsed.params['token'] = params.token;
|
parsed.params['token'] = params.token;
|
||||||
|
parsed.params['code'] = params.code;
|
||||||
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].composeUrlHash(parsed.path, parsed.params));
|
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].composeUrlHash(parsed.path, parsed.params));
|
||||||
}
|
}
|
||||||
handleLoginSuccessful() {
|
handleLoginSuccessful() {
|
||||||
@@ -8030,7 +8087,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
|||||||
}
|
}
|
||||||
} else if (what == 'read') {
|
} else if (what == 'read') {
|
||||||
this.resetContactList();
|
this.resetContactList();
|
||||||
} else if (what == 'msg') {
|
} else if (what == 'msg' && cont) {
|
||||||
const topic = this.tinode.getTopic(cont.topic);
|
const topic = this.tinode.getTopic(cont.topic);
|
||||||
const archived = topic && topic.isArchived();
|
const archived = topic && topic.isArchived();
|
||||||
if (cont.unread > 0 && this.state.messageSounds && !archived) {
|
if (cont.unread > 0 && this.state.messageSounds && !archived) {
|
||||||
@@ -8051,7 +8108,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (what == 'del') {} else if (what == 'upd' || what == 'call') {} else {
|
} else if (what == 'del') {} else if (what == 'upd' || what == 'call') {} else {
|
||||||
console.info("Unsupported (yet) presence update:", what, "in", cont.topic);
|
console.info("Unsupported (yet) presence update:", what, "in", (cont || {}).topic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tnMeSubsUpdated(unused) {
|
tnMeSubsUpdated(unused) {
|
||||||
@@ -8153,6 +8210,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
topicSelected: null,
|
||||||
errorText: '',
|
errorText: '',
|
||||||
errorLevel: null,
|
errorLevel: null,
|
||||||
mobilePanel: 'sidepanel',
|
mobilePanel: 'sidepanel',
|
||||||
@@ -8400,7 +8458,8 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
|||||||
}
|
}
|
||||||
handleCredConfirm(method, response) {
|
handleCredConfirm(method, response) {
|
||||||
TinodeWeb.navigateToCredentialsView({
|
TinodeWeb.navigateToCredentialsView({
|
||||||
cred: [method]
|
cred: [method],
|
||||||
|
code: response
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
handleSidepanelCancel() {
|
handleSidepanelCancel() {
|
||||||
@@ -8773,7 +8832,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
|||||||
meth: cred,
|
meth: cred,
|
||||||
resp: code
|
resp: code
|
||||||
}
|
}
|
||||||
}).catch(err => this.handleError(err.message, 'err'));
|
}).then(_ => _lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_18__["default"].setUrlSidePanel(window.location.hash, 'contacts'))).catch(err => this.handleError(err.message, 'err'));
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
credMethod: cred,
|
credMethod: cred,
|
||||||
@@ -9371,7 +9430,7 @@ class ValidationView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
|||||||
placeholder: numbers_only,
|
placeholder: numbers_only,
|
||||||
value: this.state.code,
|
value: this.state.code,
|
||||||
onChange: this.handleCodeChange,
|
onChange: this.handleCodeChange,
|
||||||
onKeyPress: this.handleKeyPress,
|
onKeyDown: this.handleKeyPress,
|
||||||
required: true
|
required: true
|
||||||
}))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "dialog-buttons"
|
className: "dialog-buttons"
|
||||||
@@ -9637,7 +9696,7 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.audioPlayer) {
|
if (this.audioPlayer) {
|
||||||
this.audioPlayer.oncanplay = null;
|
this.audioPlayer.onloadedmetadata = null;
|
||||||
this.audioPlayer.ontimeupdate = null;
|
this.audioPlayer.ontimeupdate = null;
|
||||||
this.audioPlayer.onended = null;
|
this.audioPlayer.onended = null;
|
||||||
this.audioPlayer.pause();
|
this.audioPlayer.pause();
|
||||||
@@ -9660,7 +9719,7 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
}
|
}
|
||||||
initAudio() {
|
initAudio() {
|
||||||
this.audioPlayer = new Audio(this.props.src);
|
this.audioPlayer = new Audio(this.props.src);
|
||||||
this.audioPlayer.oncanplay = _ => this.setState({
|
this.audioPlayer.onloadedmetadata = _ => this.setState({
|
||||||
canPlay: true
|
canPlay: true
|
||||||
});
|
});
|
||||||
this.audioPlayer.ontimeupdate = _ => this.setState({
|
this.audioPlayer.ontimeupdate = _ => this.setState({
|
||||||
@@ -9703,7 +9762,7 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
this.canvasContext.strokeStyle = BAR_COLOR_DARK;
|
this.canvasContext.strokeStyle = BAR_COLOR_DARK;
|
||||||
for (let i = 0; i < this.viewBuffer.length; i++) {
|
for (let i = 0; i < this.viewBuffer.length; i++) {
|
||||||
let x = 1 + i * (LINE_WIDTH + SPACING) + LINE_WIDTH * 0.5;
|
let x = 1 + i * (LINE_WIDTH + SPACING) + LINE_WIDTH * 0.5;
|
||||||
let y = this.viewBuffer[i] * height * 0.9;
|
let y = Math.max(this.viewBuffer[i] * height * 0.9, 1);
|
||||||
const color = x < thumbAt ? BAR_COLOR_DARK : BAR_COLOR;
|
const color = x < thumbAt ? BAR_COLOR_DARK : BAR_COLOR;
|
||||||
if (this.canvasContext.strokeStyle != color) {
|
if (this.canvasContext.strokeStyle != color) {
|
||||||
this.canvasContext.stroke();
|
this.canvasContext.stroke();
|
||||||
@@ -9711,7 +9770,7 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
this.canvasContext.strokeStyle = color;
|
this.canvasContext.strokeStyle = color;
|
||||||
}
|
}
|
||||||
this.canvasContext.moveTo(x, (height - y) * 0.5);
|
this.canvasContext.moveTo(x, (height - y) * 0.5);
|
||||||
this.canvasContext.lineTo(x, height * 0.5 + y * 0.5);
|
this.canvasContext.lineTo(x, (height + y) * 0.5);
|
||||||
}
|
}
|
||||||
this.canvasContext.stroke();
|
this.canvasContext.stroke();
|
||||||
if (this.props.duration) {
|
if (this.props.duration) {
|
||||||
@@ -9762,7 +9821,7 @@ class AudioPlayer extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
this.setState({
|
this.setState({
|
||||||
playing: false
|
playing: false
|
||||||
});
|
});
|
||||||
} else {
|
} else if (this.audioPlayer.readyState >= 2) {
|
||||||
this.audioPlayer.play();
|
this.audioPlayer.play();
|
||||||
this.setState({
|
this.setState({
|
||||||
playing: true
|
playing: true
|
||||||
@@ -12879,7 +12938,7 @@ class ErrorPanel extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCompo
|
|||||||
className: "icon"
|
className: "icon"
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: "material-icons"
|
className: "material-icons"
|
||||||
}, level)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.text, this.props.action ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
}, level)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, this.props.text, this.props.action ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, "\xA0 ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||||
href: "#",
|
href: "#",
|
||||||
style: {
|
style: {
|
||||||
whiteSpace: 'nowrap'
|
whiteSpace: 'nowrap'
|
||||||
@@ -14884,7 +14943,7 @@ class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
|||||||
}, dots), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}, dots), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "pinned",
|
className: "pinned",
|
||||||
onClick: this.handleSelected
|
onClick: this.handleSelected
|
||||||
}, shown), selected > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", null, shown)), selected > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
|
||||||
className: "menuTrigger upper"
|
className: "menuTrigger upper"
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||||
href: "#",
|
href: "#",
|
||||||
@@ -16505,7 +16564,7 @@ class VisiblePassword extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
|||||||
super(props);
|
super(props);
|
||||||
this.inputRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
|
this.inputRef = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
|
||||||
this.state = {
|
this.state = {
|
||||||
value: this.props.value,
|
value: this.props.value || '',
|
||||||
visible: false
|
visible: false
|
||||||
};
|
};
|
||||||
this.handleVisibility = this.handleVisibility.bind(this);
|
this.handleVisibility = this.handleVisibility.bind(this);
|
||||||
@@ -16535,7 +16594,7 @@ class VisiblePassword extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
|||||||
handleKeyDown(e) {
|
handleKeyDown(e) {
|
||||||
if (e.keyCode == 27) {
|
if (e.keyCode == 27) {
|
||||||
this.setState({
|
this.setState({
|
||||||
value: this.props.value,
|
value: this.props.value || '',
|
||||||
visible: false
|
visible: false
|
||||||
});
|
});
|
||||||
if (this.props.onFinished) {
|
if (this.props.onFinished) {
|
||||||
@@ -16566,7 +16625,7 @@ class VisiblePassword extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
|||||||
onBlur: this.handleEditingFinished
|
onBlur: this.handleEditingFinished
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", {
|
||||||
className: "with-visibility",
|
className: "with-visibility",
|
||||||
type: this.state.visible ? "text" : "password",
|
type: this.state.visible ? 'text' : 'password',
|
||||||
value: this.state.value,
|
value: this.state.value,
|
||||||
placeholder: this.props.placeholder,
|
placeholder: this.props.placeholder,
|
||||||
required: this.props.required ? 'required' : '',
|
required: this.props.required ? 'required' : '',
|
||||||
@@ -16748,7 +16807,7 @@ function isVersionServiceProvider(provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const name$o = "@firebase/app";
|
const name$o = "@firebase/app";
|
||||||
const version$1 = "0.9.5";
|
const version$1 = "0.9.7";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
@@ -16815,7 +16874,7 @@ const name$2 = "@firebase/firestore";
|
|||||||
const name$1 = "@firebase/firestore-compat";
|
const name$1 = "@firebase/firestore-compat";
|
||||||
|
|
||||||
const name = "firebase";
|
const name = "firebase";
|
||||||
const version = "9.18.0";
|
const version = "9.19.1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
@@ -20752,7 +20811,7 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
|
|
||||||
|
|
||||||
var name = "firebase";
|
var name = "firebase";
|
||||||
var version = "9.18.0";
|
var version = "9.19.1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -61,13 +61,20 @@ class AccountSettingsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().
|
|||||||
val: this.state.credEdit.val,
|
val: this.state.credEdit.val,
|
||||||
done: this.state.credEdit.done,
|
done: this.state.credEdit.done,
|
||||||
onShowCountrySelector: this.props.onShowCountrySelector,
|
onShowCountrySelector: this.props.onShowCountrySelector,
|
||||||
onSubmit: this.props.onCredAdd,
|
onCredAdd: this.props.onCredAdd,
|
||||||
|
onCredConfirm: this.props.onCredConfirm,
|
||||||
onCancel: _ => this.setState({
|
onCancel: _ => this.setState({
|
||||||
credEdit: undefined
|
credEdit: undefined
|
||||||
}),
|
}),
|
||||||
onError: this.props.onError
|
onError: this.props.onError
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const validated = {};
|
||||||
|
this.state.credentials.forEach(cred => {
|
||||||
|
if (cred.done) {
|
||||||
|
validated[cred.meth] = (validated[cred.meth] || 0) + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
const credentials = [];
|
const credentials = [];
|
||||||
this.state.credentials.forEach((cred, idx) => {
|
this.state.credentials.forEach((cred, idx) => {
|
||||||
if (!['email', 'tel'].includes(cred.meth)) {
|
if (!['email', 'tel'].includes(cred.meth)) {
|
||||||
@@ -89,9 +96,9 @@ class AccountSettingsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().
|
|||||||
credEdit: cred
|
credEdit: cred
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, val), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, " ", cred.done ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
}, val), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, " ", cred.done ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: "material-icons"
|
className: "material-icons"
|
||||||
}, "pending"), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
}, "pending"), "\xA0", !cred.done || validated[cred.meth] > 1 || this.props.reqCredMethod != cred.meth ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||||
href: "#",
|
href: "#",
|
||||||
onClick: e => {
|
onClick: e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -99,7 +106,7 @@ class AccountSettingsView extends (react__WEBPACK_IMPORTED_MODULE_0___default().
|
|||||||
}
|
}
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: "material-icons"
|
className: "material-icons"
|
||||||
}, "delete"))))));
|
}, "delete")) : null)));
|
||||||
});
|
});
|
||||||
if (credentials.length > 0) {
|
if (credentials.length > 0) {
|
||||||
credentials.unshift(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", {
|
credentials.unshift(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", {
|
||||||
@@ -313,8 +320,11 @@ class CredentialEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
|||||||
handleSubmit(e) {
|
handleSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const value = this.props.method == 'email' ? this.state.email : this.state.tel;
|
const value = this.props.method == 'email' ? this.state.email : this.state.tel;
|
||||||
if (value) {
|
if (this.state.code) {
|
||||||
this.props.onSubmit(this.props.method, value);
|
this.props.onError(null);
|
||||||
|
this.props.onCredConfirm(this.props.method, this.state.code);
|
||||||
|
} else if (value) {
|
||||||
|
this.props.onCredAdd(this.props.method, value);
|
||||||
this.setState({
|
this.setState({
|
||||||
sent: true
|
sent: true
|
||||||
});
|
});
|
||||||
@@ -324,7 +334,8 @@ class CredentialEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
|||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const readyForCode = this.state.sent || !this.props.done;
|
const readyForCode = this.state.sent || !this.props.done;
|
||||||
const currentValue = CredentialEdit.formatPhoneNumber(readyForCode ? this.state.tel || this.state.email : this.props.val);
|
const rawValue = readyForCode ? this.state.tel || this.state.email : this.props.val;
|
||||||
|
const formattedValue = this.props.method == 'tel' ? CredentialEdit.formatPhoneNumber(rawValue) : rawValue;
|
||||||
const changeEmail = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
const changeEmail = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "panel-form-row"
|
className: "panel-form-row"
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", {
|
||||||
@@ -441,11 +452,11 @@ class CredentialEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
|||||||
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", {
|
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("form", {
|
||||||
className: "panel-form-column",
|
className: "panel-form-column",
|
||||||
onSubmit: this.handleSubmit
|
onSubmit: this.handleSubmit
|
||||||
}, readyForCode ? null : this.props.method == 'email' ? changeEmail : this.props.method == 'tel' ? changePhone : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}, readyForCode ? this.props.method == 'email' ? newEmailLabel : this.props.method == 'tel' ? newPhoneLabel : null : this.props.method == 'email' ? changeEmail : this.props.method == 'tel' ? changePhone : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "panel-form-row"
|
className: "panel-form-row"
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", {
|
||||||
className: "quoted"
|
className: "quoted"
|
||||||
}, currentValue)), readyForCode ? null : this.props.method == 'email' ? newEmailInput : this.props.method == 'tel' ? newPhoneInput : null, readyForCode ? codeInput : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}, formattedValue)), readyForCode ? null : this.props.method == 'email' ? newEmailInput : this.props.method == 'tel' ? newPhoneInput : null, readyForCode ? codeInput : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "dialog-buttons"
|
className: "dialog-buttons"
|
||||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
|
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
|
||||||
className: "secondary",
|
className: "secondary",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -71,7 +71,7 @@ class PasswordResetView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pu
|
|||||||
if (this.state.token) {
|
if (this.state.token) {
|
||||||
this.props.onReset(this.state.password.trim(), {
|
this.props.onReset(this.state.password.trim(), {
|
||||||
scheme: 'token',
|
scheme: 'token',
|
||||||
token: this.state.token
|
secret: this.state.token
|
||||||
});
|
});
|
||||||
} else if (this.state.code && this.props.reqCredMethod) {
|
} else if (this.state.code && this.props.reqCredMethod) {
|
||||||
const cred = this.state.email.trim() || this.state.tel.trim();
|
const cred = this.state.email.trim() || this.state.tel.trim();
|
||||||
@@ -222,7 +222,7 @@ class PasswordResetView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pu
|
|||||||
onSubmit: this.handleSubmit
|
onSubmit: this.handleSubmit
|
||||||
}, !this.state.sent && showCredentialInput ? credentialInput : null, this.state.haveCode || this.state.sent ? codeInput : null, showPasswordInput ? passwordInput : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}, !this.state.sent && showCredentialInput ? credentialInput : null, this.state.haveCode || this.state.sent ? codeInput : null, showPasswordInput ? passwordInput : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
className: "dialog-buttons"
|
className: "dialog-buttons"
|
||||||
}, this.state.haveCode || this.state.sent ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
}, this.state.haveCode || this.state.sent || this.state.token ? null : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||||
href: "#",
|
href: "#",
|
||||||
onClick: this.handleShowCodeField,
|
onClick: this.handleShowCodeField,
|
||||||
style: {
|
style: {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -37,7 +37,9 @@ const BAR_COLOR = '#BBBD';
|
|||||||
const BAR_SCALE = 64.0;
|
const BAR_SCALE = 64.0;
|
||||||
const VISUALIZATION_BARS = 96;
|
const VISUALIZATION_BARS = 96;
|
||||||
const MAX_SAMPLES_PER_BAR = 10;
|
const MAX_SAMPLES_PER_BAR = 10;
|
||||||
const AUDIO_MIME_TYPE = 'audio/webm';
|
const DEFAULT_AUDIO_MIME_TYPE = 'audio/webm';
|
||||||
|
const SAFARI_AUDIO_MIME_TYPE = 'audio/mp4';
|
||||||
|
const AUDIO_MIME_TYPES = [DEFAULT_AUDIO_MIME_TYPE, SAFARI_AUDIO_MIME_TYPE, ''];
|
||||||
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
||||||
icon_title_delete: {
|
icon_title_delete: {
|
||||||
id: "icon_title_delete",
|
id: "icon_title_delete",
|
||||||
@@ -66,6 +68,13 @@ const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
|||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Send message"
|
"value": "Send message"
|
||||||
}]
|
}]
|
||||||
|
},
|
||||||
|
failed_to_init_audio: {
|
||||||
|
id: "failed_to_init_audio",
|
||||||
|
defaultMessage: [{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Failed to initialize audio recording"
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
||||||
@@ -170,9 +179,9 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
this.canvasContext.beginPath();
|
this.canvasContext.beginPath();
|
||||||
for (let i = 0; i < this.viewBuffer.length; i++) {
|
for (let i = 0; i < this.viewBuffer.length; i++) {
|
||||||
let x = i * (LINE_WIDTH + SPACING) - dx;
|
let x = i * (LINE_WIDTH + SPACING) - dx;
|
||||||
let y = Math.min(this.viewBuffer[i] / BAR_SCALE, 0.9) * height;
|
let y = Math.max(Math.min(this.viewBuffer[i] / BAR_SCALE, 0.9) * height, 1);
|
||||||
this.canvasContext.moveTo(x, (height - y) * 0.5);
|
this.canvasContext.moveTo(x, (height - y) * 0.5);
|
||||||
this.canvasContext.lineTo(x, height * 0.5 + y * 0.5);
|
this.canvasContext.lineTo(x, (height + y) * 0.5);
|
||||||
}
|
}
|
||||||
this.canvasContext.stroke();
|
this.canvasContext.stroke();
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
@@ -237,12 +246,28 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
}
|
}
|
||||||
initMediaRecording(stream) {
|
initMediaRecording(stream) {
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.mediaRecorder = new MediaRecorder(stream, {
|
AUDIO_MIME_TYPES.some(mimeType => {
|
||||||
mimeType: AUDIO_MIME_TYPE,
|
if (MediaRecorder.isTypeSupported(mimeType)) {
|
||||||
audioBitsPerSecond: 24_000
|
this.mediaRecorder = new MediaRecorder(stream, {
|
||||||
|
mimeType: mimeType,
|
||||||
|
audioBitsPerSecond: 24_000
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
if (!this.mediaRecorder) {
|
||||||
|
console.warn('MediaRecorder failed to initialize: no supported audio formats');
|
||||||
|
this.props.onError(this.props.intl.formatMessage(messages.failed_to_init_audio));
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.audioContext = new AudioContext();
|
this.audioContext = new AudioContext();
|
||||||
this.audioInput = this.audioContext.createMediaStreamSource(stream);
|
this.audioInput = this.audioContext.createMediaStreamSource(stream);
|
||||||
|
if (!this.audioInput) {
|
||||||
|
console.warn('createMediaStreamSource returned null: audio input unavailable');
|
||||||
|
this.props.onError(this.props.intl.formatMessage(messages.failed_to_init_audio));
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.analyser = this.audioContext.createAnalyser();
|
this.analyser = this.audioContext.createAnalyser();
|
||||||
this.analyser.fftSize = BUFFER_SIZE;
|
this.analyser.fftSize = BUFFER_SIZE;
|
||||||
this.audioInput.connect(this.analyser);
|
this.audioInput.connect(this.analyser);
|
||||||
@@ -275,11 +300,12 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
this.recordingTimestamp = this.startedOn;
|
this.recordingTimestamp = this.startedOn;
|
||||||
}
|
}
|
||||||
getRecording(mimeType) {
|
getRecording(mimeType) {
|
||||||
mimeType = mimeType || AUDIO_MIME_TYPE;
|
mimeType = mimeType || DEFAULT_AUDIO_MIME_TYPE;
|
||||||
let blob = new Blob(this.audioChunks, {
|
let blob = new Blob(this.audioChunks, {
|
||||||
type: mimeType
|
type: mimeType
|
||||||
});
|
});
|
||||||
return webm_duration_fix__WEBPACK_IMPORTED_MODULE_3___default()(blob, mimeType).then(fixedBlob => {
|
const result = mimeType == DEFAULT_AUDIO_MIME_TYPE ? webm_duration_fix__WEBPACK_IMPORTED_MODULE_3___default()(blob, mimeType) : Promise.resolve(blob);
|
||||||
|
return result.then(fixedBlob => {
|
||||||
blob = fixedBlob;
|
blob = fixedBlob;
|
||||||
return fixedBlob.arrayBuffer();
|
return fixedBlob.arrayBuffer();
|
||||||
}).then(arrayBuff => this.audioContext.decodeAudioData(arrayBuff)).then(decoded => this.createPreview(decoded)).then(preview => ({
|
}).then(arrayBuff => this.audioContext.decodeAudioData(arrayBuff)).then(decoded => this.createPreview(decoded)).then(preview => ({
|
||||||
@@ -311,7 +337,9 @@ class AudioRecorder extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
cleanUp() {
|
cleanUp() {
|
||||||
this.audioInput.disconnect();
|
if (this.audioInput) {
|
||||||
|
this.audioInput.disconnect();
|
||||||
|
}
|
||||||
this.stream.getTracks().forEach(track => track.stop());
|
this.stream.getTracks().forEach(track => track.stop());
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1577
-1422
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+255
-13
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user