Merge branch 'develop' into element_4362

This commit is contained in:
ismailgulek 2021-08-09 18:09:45 +03:00
commit 9a62d5d231
No known key found for this signature in database
GPG key ID: E96336D42D9470A9
76 changed files with 665 additions and 413 deletions

View file

@ -5,6 +5,15 @@ Changes to be released in next version
*
🙌 Improvements
* Settings: The notifications toggle no longer detects the system's "Deliver Quietly" configuration as disabled (#2368).
* Settings: Adds a link to open the Settings app to quickly configure app notifications.
* VoIP: Text & icon changes on call tiles (#4642).
* Voice messages: Stop recording and go into locked mode when the application becomes inactive (#4656)
* Voice messages: Allow voice message playback control from the iOS lock screen and control center (#4655)
* Voice messages: Improve audio recording quality
* Voice messages: Remove labs setting and enable them by default
* Room: Remove the green border from direct message room avatars (#4520).
* VoIP: Additional changes on call tiles (#4642).
* SSO: Stable ids for MSC 2858 (#4362).
🐛 Bugfix
@ -16,12 +25,40 @@ Changes to be released in next version
🗣 Translations
*
🧱 Build
* Add a script to initialize quickly and easily the project.
Others
* Docs: Add reference to AppIdentifiers.xcconfig in INSTALL.md
Changes in 1.4.9 (2021-08-03)
=================================================
✨ Features
*
🙌 Improvements
* Voice Messages: Increased recording state microphone icon size
* Voice Messages: Using "Voice message - MM.dd.yyyy HH.mm.ss" as the format for recorded audio files
🐛 Bugfix
* Voice Messages: Fixed race conditions when sending voice messages (#4641)
⚠️ API Changes
*
🗣 Translations
*
🧱 Build
*
Others
*
Improvements:
Changes in 1.4.8 (2021-07-29)
=================================================

View file

@ -22,8 +22,8 @@ APPLICATION_GROUP_IDENTIFIER = group.im.vector
APPLICATION_SCHEME = element
// Version
MARKETING_VERSION = 1.4.9
CURRENT_PROJECT_VERSION = 1.4.9
MARKETING_VERSION = 1.4.10
CURRENT_PROJECT_VERSION = 1.4.10
// Team

View file

@ -309,10 +309,6 @@ final class BuildSettings: NSObject {
static let messageDetailsAllowCopyMedia: Bool = true
static let messageDetailsAllowPasteMedia: Bool = true
// MARK: - Voice Message
static let voiceMessagesEnabled = false
// MARK: - Notifications
static let decryptNotificationsByDefault: Bool = true

View file

@ -77,7 +77,14 @@ Every time you change the `$matrixKitVersion` variable in the `Podfile`, you hav
## Build
## Generate Xcode project
### Configure project
You may need to change the bundle identifier and app group identifier to be unique to get Xcode to build the app. Make sure to change the bundle identifier, application group identifier and app name in the `Config/AppIdentifiers.xcconfig` file to your new identifiers.
More advanced build configuration can be found in the `project.yml` file and each target has a `target.yml` file in its respective folder.
### Generate Xcode project
In order to get rid of git conflicts, the `Riot.xcodeproj` is not pushed into the git repository anymore but generated using `XcodeGen`. To generate the `xcodeproj` file simply run the following command line from the root folder :
@ -117,12 +124,14 @@ $ open Riot.xcworkspace
**Note**: If you have multiple Xcode versions installed don't forget to use the right version of Command Line Tools when you are building the app. To check the Command Line Tools version go to `Xcode > Preferences > Locations > Command Line Tools` and check that the displayed version match your Xcode version.
### Configure project
You may need to change the bundle identifier and app group identifier to be unique to get Xcode to build the app. Make sure to change the bundle identifier, application group identifier and app name in the `project.yml` file to your new identifiers.
### Generate the project in one line without effort
Each target has its own YAML file in the folder Targets folder.
If you want to generate the project easily and quickly, there is a local script called `setup_project.sh` that creates the `xcodeproj` and `xcworkspace` with all source files and dependencies with commands described before. It automatically selects the right dependencies based on your local Git branch or your Podfile local modifications. All you have to do is to go in the project root folder and run the script:
```
$ ./setup_project.sh
```
## Generate IPA

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Video.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Video@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Video@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Voice call.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Voice call@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Voice call@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 B

View file

@ -1,17 +1,17 @@
{
"images" : [
{
"filename" : "24.png",
"filename" : "Video.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "24@2x.png",
"filename" : "Video@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "24@3x.png",
"filename" : "Video@3x.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

View file

@ -298,7 +298,6 @@
"settings_global_settings_info" = "Глобални настройки на известия са налични на Вашия %@ уеб клиент";
"settings_pin_rooms_with_missed_notif" = "Закачане на стаи с пропуснати известия";
"settings_pin_rooms_with_unread" = "Закачане на стаи с непрочетени съобщения";
"settings_on_denied_notification" = "Известията са отказани за %@. Моля, включете ги в настройките на устройството";
"settings_enable_callkit" = "Интегрирани разговори";
"settings_callkit_info" = "Получаване на входящи повиквания при заключен екран. Показване на Element разговори в историята на системата. Ако iCloud е включен, историята на разговорите се споделя с Apple.";
"settings_ui_language" = "Език";

View file

@ -295,7 +295,6 @@
"settings_global_settings_info" = "Els paràmetres de notificació globals estan disponibles al teu client web %@";
"settings_pin_rooms_with_missed_notif" = "Fixa sales amb notificacions pendents";
"settings_pin_rooms_with_unread" = "Fixa sales amb missatges pendents";
"settings_on_denied_notification" = "%@ no permet notificacions, si us plau activa-les en els ajustos del teu dispositiu";
"settings_enable_callkit" = "Trucades integrades";
"settings_callkit_info" = "Rep les trucades entrants a la pantalla de bloqueig. Consulta les trucades de Element a l'historial de trucades del sistema. Si està habilitat iCloud, aquest historial de trucades es compartirà amb Apple.";
"settings_ui_language" = "Llenguatge";

View file

@ -373,7 +373,6 @@
"settings_global_settings_info" = "Mae gosodiadau hysbysu eang ar gael ar eich cleient %@ gwe";
"settings_pin_rooms_with_missed_notif" = "Pinio ystafelloedd gyda hysbysiadau heb eu gweld";
"settings_pin_rooms_with_unread" = "Pinio ystafelloedd gyda negeseuon heb eu darllen";
"settings_on_denied_notification" = "Gwrthodir hysbysiadau i %@, caniatewch nhw yn eich gosodiadau dyfais";
"settings_enable_callkit" = "Galw integredig";
"settings_callkit_info" = "Derbyn galwadau sy'n dod i mewn ar eich sgrin clo. Gwelwch eich galwadau Element yn hanes galwadau'r system. Os yw iCloud wedi'i alluogi, bydd yr hanes galw hwn yn cael ei rannu gydag Apple.";
"settings_calls_stun_server_fallback_button" = "Caniatáu gweinydd cymorth galw wrth gefn";

View file

@ -316,7 +316,6 @@
"settings_global_settings_info" = "Globale Benachrichtigungseinstellungen sind auf deinem %@ web-Client verfügbar";
"settings_pin_rooms_with_missed_notif" = "Pinnen von Räumen mit verpassten Benachrichtigungen";
"settings_pin_rooms_with_unread" = "Pinnen von Räumen mit ungelesenen Nachrichten";
"settings_on_denied_notification" = "Benachrichtigungen verboten für %@, bitte in den Geräte-Einstellungen erlauben";
"settings_contacts_discover_matrix_users" = "Entdecke andere Benutzer mittels E-Mail-Adressen oder Telefonnummern";
"settings_labs_e2e_encryption_prompt_message" = "Zum Fertigstellen der Verschlüsselung bitte neu anmelden.";
"settings_third_party_notices" = "Anmerkungen von Dritten";

View file

@ -492,11 +492,13 @@ Tap the + to start adding people.";
"settings_security" = "SECURITY";
"settings_enable_push_notif" = "Notifications on this device";
"settings_device_notifications" = "Device notifications";
"settings_show_decrypted_content" = "Show decrypted content";
"settings_global_settings_info" = "Global notification settings are available on your %@ web client";
"settings_pin_rooms_with_missed_notif" = "Pin rooms with missed notifications";
"settings_pin_rooms_with_unread" = "Pin rooms with unread messages";
"settings_on_denied_notification" = "Notifications are denied for %@, please allow them in your device settings";
"settings_notifications_disabled_alert_title" = "Notifications disabled";
"settings_notifications_disabled_alert_message" = "To enable notifications, go to your device settings.";
//"settings_enable_all_notif" = "Enable all notifications";
//"settings_messages_my_display_name" = "Msg containing my display name";
//"settings_messages_my_user_name" = "Msg containing my user name";
@ -844,14 +846,17 @@ Tap the + to start adding people.";
"event_formatter_rerequest_keys_part1_link" = "Re-request encryption keys";
"event_formatter_rerequest_keys_part2" = " from your other sessions.";
"event_formatter_message_edited_mention" = "(edited)";
"event_formatter_call_voice" = "Voice call";
"event_formatter_call_video" = "Video call";
"event_formatter_call_connecting" = "Connecting…";
"event_formatter_call_ringing" = "Ringing…";
"event_formatter_call_has_ended" = "Ended %@";
"event_formatter_call_you_currently_in" = "Active call";
"event_formatter_call_you_declined" = "You declined this call";
"event_formatter_call_you_missed" = "You missed this call";
"event_formatter_call_has_ended" = "Call ended";
"event_formatter_call_has_ended_with_time" = "Call ended • %@";
"event_formatter_call_incoming_voice" = "Incoming voice call";
"event_formatter_call_incoming_video" = "Incoming video call";
"event_formatter_call_active_voice" = "Active voice call";
"event_formatter_call_active_video" = "Active video call";
"event_formatter_call_you_declined" = "Call declined";
"event_formatter_call_missed_voice" = "Missed voice call";
"event_formatter_call_missed_video" = "Missed video call";
"event_formatter_call_connection_failed" = "Connection failed";
"event_formatter_call_back" = "Call back";
"event_formatter_call_decline" = "Decline";
@ -1687,3 +1692,4 @@ Tap the + to start adding people.";
"voice_message_release_to_send" = "Hold to record, release to send";
"voice_message_remaining_recording_time" = "%@s left";
"voice_message_stop_locked_mode_recording" = "Tap on your recording to stop or listen";
"voice_message_lock_screen_placeholder" = "Voice message";

View file

@ -975,7 +975,6 @@
"settings_calls_stun_server_fallback_description" = "Permesi repaŝan servilon %@ asistan je vokoj, kiam la hejmservilo ne provizas servilon (via IP-adreso ne doniĝus dum voko).";
"settings_calls_stun_server_fallback_button" = "Permesi repaŝan servilon asistan je vokoj";
"settings_callkit_info" = "Ricevi vokpetojn ĉe via ŝlosa ekrano. Vidi viajn vokojn de Element ĉe la sistema vokhistorio. Se iCloud estas ŝaltita, la vokhistorio doniĝas ankaŭ al Apple.";
"settings_on_denied_notification" = "Sciigo por %s estas malŝaltitaj, bonvole permesu ilin per la agordoj de via aparato";
"settings_pin_rooms_with_unread" = "Alpingli ĉambrojn kun nelegitaj mesaĝoj";
"settings_pin_rooms_with_missed_notif" = "Alpinigli ĉambrojn kun nerimarkitaj sciigoj";
"settings_show_decrypted_content" = "Montri malĉifritajn enhavojn";

View file

@ -321,7 +321,6 @@
"settings_global_settings_info" = "Los ajustes de notificación globales están disponibles en tu cliente web %@";
"settings_pin_rooms_with_missed_notif" = "Fijar salas con notificaciones pendientes";
"settings_pin_rooms_with_unread" = "Fijar salas con mensajes no leídos";
"settings_on_denied_notification" = "Las notificaciones están denegadas para %@, por favor habilita notificaciones en los ajustes de tu dispositivo";
"settings_enable_callkit" = "Integración de llamadas";
"settings_callkit_info" = "Recibe llamadas entrantes en tu pantalla de bloqueo. Ve tus llamadas de Element en el historial de llamadas del sistema. Si iCloud está habilitado, este historial de llamadas se compartirá con Apple.";
"settings_ui_language" = "Idioma";

View file

@ -497,7 +497,6 @@
"settings_global_settings_info" = "Üldised teavituste seadistused leiduvad sinu %@ veebikliendis";
"settings_pin_rooms_with_missed_notif" = "Klammerda jututoad, kus leidub lugemata teavitusi";
"settings_pin_rooms_with_unread" = "Klammerda jututoad, kus leidub lugemata sõnumeid";
"settings_on_denied_notification" = "Teavitused on %@ jaoks keelatud, palun luba nad oma seadme seadistustes";
"settings_enable_callkit" = "Lõimitud helistamine";
"settings_callkit_info" = "Vasta kõnedele lukustuskuvalt. Vaata Element'i kõnesid süsteemi kõnelogist. Kui iCloud on kasutusel, siis kõnede ajalugu jagatakse Applega.";
"settings_calls_stun_server_fallback_button" = "Kasuta kõnehõlbustusserverit";
@ -1361,7 +1360,7 @@
// Room Notification Settings
"room_notifs_settings_notify_me_for" = "Teavita mind";
"room_details_notifs" = "Teavitused";
"voice_message_stop_locked_mode_recording" = "Salvestuse peatamiseks ja taasesituseks vajuta lainekese nuppu";
"voice_message_stop_locked_mode_recording" = "Salvestuse peatamiseks ja taasesituseks vajuta salvestuse vaadet";
"voice_message_remaining_recording_time" = "salvestusaega jäänud %@s";
// Mark: - Voice Messages

View file

@ -396,7 +396,6 @@
"room_participants_remove_third_party_invite_msg" = "Hirugarrengoen gonbidapenak kentzea ez da onartzen APIa ez dagoen bitartean";
"settings_sign_out_e2e_warn" = "Zure muturretik muturrerako zifratze gakoak galduko dituzu. Horrek esan nahi du ezin izango dituzula mezu zaharrak gehiago irakurri zifratutako geletan gailu honetatik.";
"settings_global_settings_info" = "Jakinarazpen orokorren ezarpenak eskuragarri daude zure %@ web bezeroan";
"settings_on_denied_notification" = "Jakinarazpenak ukatu dira %@(e)n, baimendu zure gailuaren ezarpenetan";
"room_details_history_section_prompt_msg" = "Historiala nork irakurri dezakeen aldatzea gelak honetara aurrerantzean bidalitako mezuei besterik ez zaie aplikatuko. Badagoen historialaren ikusgaitasuna ez da aldatuko.";
// Call
"call_incoming_voice_prompt" = "%@ erabiltzailearen deia jasotzen";

View file

@ -278,7 +278,6 @@
"settings_global_settings_info" = "Les paramètres de notification globaux sont disponibles sur votre client web %@";
"settings_pin_rooms_with_missed_notif" = "Épingler les salons avec des notifications non lues";
"settings_pin_rooms_with_unread" = "Épingler les salons avec des messages non lus";
"settings_on_denied_notification" = "Les notifications sont refusées pour %@, merci de les autoriser dans les paramètres de votre appareil";
"settings_unignore_user" = "Afficher tous les messages de %@ ?";
"settings_contacts_discover_matrix_users" = "Utiliser un e-mail ou un numéro de téléphone pour retrouver des utilisateurs";
"settings_contacts_phonebook_country" = "Pays pour le répertoire téléphonique";

View file

@ -311,7 +311,6 @@
"settings_global_settings_info" = "Globális értesítési beállításokat a webes kliensedben találod: %@";
"settings_pin_rooms_with_missed_notif" = "Szobák kitűzése elszalasztott értesítésekkel";
"settings_pin_rooms_with_unread" = "Szobák kitűzése olvasatlan üzenetekkel";
"settings_on_denied_notification" = "Az értesítések tiltva vannak ehhez: %@, kérlek engedélyezd az eszköz beállításaiban";
"settings_enable_callkit" = "Beépített hívás";
"settings_callkit_info" = "Hívások fogadása a zárolt képernyőn. Element hívások megjelenítése a rendszer hívás naplójában. Ha az iCloud engedélyezett akkor a hívásnapló az Apple-el megosztásra kerül.";
"settings_ui_language" = "Nyelv";
@ -1424,7 +1423,7 @@
// Room Notification Settings
"room_notifs_settings_notify_me_for" = "Értesítés ezért:";
"room_details_notifs" = "Értesítések";
"voice_message_stop_locked_mode_recording" = "Megállításhoz és visszajátszáshoz koppints a hullámhosszra";
"voice_message_stop_locked_mode_recording" = "Megállításhoz és visszajátszáshoz koppints a felvételre";
"voice_message_remaining_recording_time" = "%@s távozott";
// Mark: - Voice Messages

View file

@ -442,7 +442,6 @@
"settings_fail_to_update_profile" = "Mistókst að uppfæra notandasnið";
"settings_pin_rooms_with_missed_notif" = "Festa spjallrásir með óskoðuðum tilkynningum";
"settings_pin_rooms_with_unread" = "Festa spjallrásir með ólesnum skilaboðum";
"settings_on_denied_notification" = "Tilkynningum er hafnað fyrir %@, leyfðu þær í stillingum tækisins";
"settings_ui_theme_picker_message" = "\"Sjálfvirkt\" notar \"Umsnúa litum\" stillingar tækisins";
"settings_contacts_discover_matrix_users" = "Notaðu tölvupóstföng og símanúmer til að finna notendur";
"settings_labs_e2e_encryption_prompt_message" = "Til að ljúka við uppsetningu á dulritun verðurðu að skrá þig inn aftur.";

View file

@ -1,7 +1,7 @@
// Permissions usage explanations
"NSCameraUsageDescription" = "La fotocamera viene utilizzata per scattare fotografie, registrare video ed eseguire videochiamate.";
"NSPhotoLibraryUsageDescription" = "La libreria fotografica viene utilizzata per inviare foto e video.";
"NSMicrophoneUsageDescription" = "Il microfono viene utilizzato per registrare video ed effettuare chiamate.";
"NSMicrophoneUsageDescription" = "Element ha bisogno di accedere al microfono per effettuare e ricevere chiamate, registrare video e messaggi vocali.";
"NSContactsUsageDescription" = "Per scoprire i contatti che già usano Matrix, Element può inviare gli indirizzi email e i numeri di telefono della tua rubrica al server identità che hai scelto. Se supportato, viene fatto un hash dei dati personali prima dell'invio - controlla la politica sulla privacy del tuo server di identità per maggiori informazioni.";
"NSCalendarsUsageDescription" = "Vedi le tue riunioni programmate nell'app.";
"NSFaceIDUsageDescription" = "Face ID viene usato per accedere all'app.";

View file

@ -327,7 +327,6 @@
"settings_global_settings_info" = "Le impostazioni di notifica avanzate sono disponibili nel tuo %@ web client";
"settings_pin_rooms_with_missed_notif" = "Segna le stanze con notifiche perse";
"settings_pin_rooms_with_unread" = "Segna le stanze con messaggi non letti";
"settings_on_denied_notification" = "Le notifiche non sono permesse per %@, abilitale nelle impostazioni del tuo dispositivo";
"settings_enable_callkit" = "Chiamate integrate";
"settings_callkit_info" = "Ricevi le chiamate in arrivo sul blocca schermo. Mostra le chiamate Element nella cronologia di chiamate del dispositivo. Se iCloud è attivo, questa cronologia sarà condivisa con Apple.";
"settings_ui_language" = "Lingua";
@ -1395,3 +1394,10 @@
// Room Notification Settings
"room_notifs_settings_notify_me_for" = "Inviami notifiche per";
"room_details_notifs" = "Notifiche";
"voice_message_stop_locked_mode_recording" = "Tocca la registrazione per fermare o ascoltare";
"voice_message_remaining_recording_time" = "%@s rimasti";
// Mark: - Voice Messages
"voice_message_release_to_send" = "Tieni premuto per registrare, rilascia per inviare";
"settings_labs_voice_messages" = "Messaggi vocali";

View file

@ -289,7 +289,6 @@
"settings_show_decrypted_content" = "復号化された文章を表示";
"settings_global_settings_info" = "あなたの %@ webクライアント上で、全体の通知設定が可能です";
"settings_pin_rooms_with_missed_notif" = "通知の届かなかった部屋をピン止めする";
"settings_on_denied_notification" = "%@で通知されないように設定されています。あなたの端末設定で許可してください";
"settings_callkit_info" = "画面がロックされているときに着信がありました。Elementの着信はシステムの通話履歴で確認できます。 iCloudが有効になっている場合、この通話履歴はAppleと共有されます。";
"settings_ui_language" = "言語";
"settings_ui_theme" = "外観";

View file

@ -1305,7 +1305,6 @@
"security_settings_blacklist_unverified_devices" = "Ɣur-k·m ad tazneḍ akk iznan ɣer tɣimiyin ur nettwattkal ara";
"security_settings_crypto_sessions_description_2" = "MA yella ur tessineḍ ara anekcum, senfel awal-ik·imuffir, rnu wennez aḥraz aɣellsan.";
"settings_send_crash_report" = "Azen tura tura isefka yerrẓen & useqdec";
"settings_on_denied_notification" = "Ttwagin yilɣa i %@, ttxil-k·m sireg-iten deg yiɣewaren n yibenk-inek·inem";
"settings_global_settings_info" = "Iɣewwaren n yilɣa imatuyen llan ɣef umsaɣ-inek·inem web %@";
"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "Ulac aqeddac n timagit i yettusbadun, ihi ur tezmireḍ ara ad tebduḍ adiwenni akked unermis isseqdacen imayl.";
"contacts_address_book_permission_required" = "Ttusrant tsirag i unekcum ɣer yinermisen idiganen";

View file

@ -857,7 +857,6 @@
"room_details_photo_for_dm" = "Bilde";
"room_details_photo" = "Rombilde";
"settings_flair" = "Vis kobling hvor tillatt";
"settings_on_denied_notification" = "Varsler er ikke tillat for %@, vennligst tillat dem i enhetens innstillinger";
"settings_pin_rooms_with_missed_notif" = "Fest rom med tapte varsler";
"room_info_list_several_members" = "%@ medlemmer";
"pin_protection_not_allowed_pin" = "Av sikkerhetsårsaker er denne PIN-koden ikke tilgjengelig. Prøv en annen PIN-kode";

View file

@ -289,7 +289,6 @@
"settings_global_settings_info" = "Globale meldingsinstellingen zijn beschikbaar op uw %@-webcliënt";
"settings_pin_rooms_with_missed_notif" = "Gesprekken met gemiste meldingen vastprikken";
"settings_pin_rooms_with_unread" = "Gesprekken met ongelezen berichten vastprikken";
"settings_on_denied_notification" = "Meldingen worden geweigerd voor %@, sta ze toe in uw apparaatinstellingen";
//"settings_enable_all_notif" = "Alle notificaties aanzetten";
//"settings_messages_my_display_name" = "Bericht dat mijn naam bevat";
//"settings_messages_my_user_name" = "Bericht dat mijn gebruikersnaam bevat";

View file

@ -503,7 +503,6 @@
"settings_key_backup" = "KOPIA ZAPASOWA KLUCZY";
"settings_enable_push_notif" = "Powiadomienia na tym urządzeniu";
"settings_global_settings_info" = "Globalne i szczegółowe ustawienia powiadomień są dostępne z poziomu klienta webowego: %@";
"settings_on_denied_notification" = "Powiadomienia dla aplikacji %@ są wyłączone. Proszę zezwól na nie w ustawieniach urządzenia";
"settings_callkit_info" = "Odbieraj połączenia przychodzące na ekranie blokady. Zobacz swoje połęczenia Element w historii połączeń w systemie. Jeśli usługa iCloud jest włączona, historia połączeń zostanie udostępniona Apple.";
"settings_ui_theme_picker_message" = "\"Auto\" używa ustawienia \"Odwróć kolory\" Twojego urządzenia";
"close" = "Zamknij";

View file

@ -317,7 +317,6 @@
"settings_enable_push_notif" = "Notificações neste dispositivo";
"settings_show_decrypted_content" = "Mostrar conteúdo decriptado";
"settings_global_settings_info" = "Configurações de notificação globais estão disponíveis em seu cliente web %@";
"settings_on_denied_notification" = "Notificações são negadas para %@, por favor permita-as nas configurações de seu dispositivo";
"settings_enable_callkit" = "Chamamento integrado";
"settings_callkit_info" = "Receba chamadas chegando em sua tela de bloqueio. Veja suas chamadas Element no histórico de chamadas do sistema. Se iCloud está ativado, este histórico de chamadas vai ser compartilhado com Apple.";
"settings_ui_language" = "Língua";
@ -1393,7 +1392,7 @@
"room_notifs_settings_notify_me_for" = "Notifique-me para";
"room_details_notifs" = "Notificações";
"voice_message_remaining_recording_time" = "%@s restando";
"voice_message_stop_locked_mode_recording" = "Toque no comprimento de onda para parar e dar playback";
"voice_message_stop_locked_mode_recording" = "Toque em sua gravação para parar ou escutar";
// Mark: - Voice Messages

View file

@ -259,7 +259,6 @@
"settings_fail_to_update_profile" = "Не удалось обновить профиль";
"settings_enable_push_notif" = "Уведомления на этом устройстве";
"settings_global_settings_info" = "Глобальные настройки уведомлений доступны в вашем %@ веб-клиенте";
"settings_on_denied_notification" = "Уведомления для %@ запрещены, пожалуйста, разрешите их в настройках вашего устройства";
"settings_ui_language" = "Язык";
"settings_unignore_user" = "Показать все сообщения от %@?";
"settings_labs_e2e_encryption" = "Сквозное шифрование";

View file

@ -493,7 +493,6 @@
"settings_sign_out_e2e_warn" = "Do të humbni kyçet tuaj të fshehtëzimit skaj-më-skaj. Kjo do të thotë se sdo të jeni më në gjendje të lexoni mesazhe të vjetër te dhoma të fshehtëzuara në këtë pajisje.";
"settings_surname" = "Mbiemër";
"settings_global_settings_info" = "Rregullimet globale për njoftime i gjeni te klienti juaj %@ web";
"settings_on_denied_notification" = "Njoftimet për %@ spranohen, ju lutemi, lejojini që nga rregullimet e pajisjes tuaj";
"settings_enable_callkit" = "Thirrje të integruara";
"settings_callkit_info" = "Merrini thirrjet ardhëse edhe me ekran të kyçur. Shihni thirrjet tuaja nën Element te historiku i thirrjeve të sistemit. Nëse iCloud është i aktivizuar, ky historik thirrjesh do ti jepet kompanisë Apple.";
"settings_ui_theme_picker_message" = "\"Auto\" përdor rregullimet \"Përmbysi Ngjyrat\" të pajisjes tuaj";

View file

@ -309,7 +309,6 @@
"settings_show_decrypted_content" = "Visa avkrypterat innehåll";
"settings_pin_rooms_with_missed_notif" = "Fäst rum med missade aviseringar";
"settings_pin_rooms_with_unread" = "Fäst rum med olästa meddelanden";
"settings_on_denied_notification" = "Aviseringar har nekats för %@, vänligen tillåt dem i dina enhetsinställningar";
"settings_enable_callkit" = "Integrerade samtal";
"settings_integrations_allow_button" = "Hantera integrationer";
"settings_ui_language" = "Språk";

View file

@ -290,7 +290,6 @@
"settings_global_settings_info" = "Cài đặt thông báo toàn cầu khả dụng trên %@ trình duyệt khách của bạn";
"settings_pin_rooms_with_missed_notif" = "Neo phòng có thông báo bỏ lỡ";
"settings_pin_rooms_with_unread" = "Neo phòng có tin nhắn chưa đọc";
"settings_on_denied_notification" = "Thông báo bị từ chối cho %@, vui lòng cho phép trong cài đặt thiết bị của bạn";
"settings_enable_callkit" = "Cuộc gọi tích hợp";
"settings_callkit_info" = "Nhận cuộc gọi tới trên màn hình khóa. Xem lịch sử cuộc gọi trong lịch sử cuộc gọi của hệ thống. Nếu iCloud được kích hoạt, lịch sử cuộc gọi sẽ được chia sẻ với Apple.";
"settings_ui_language" = "Ngôn ngữ";

View file

@ -272,7 +272,6 @@
"settings_global_settings_info" = "全局通知设置可在 %@ 的网页客户端中修改";
"settings_pin_rooms_with_missed_notif" = "置顶含有错过的通知的聊天室";
"settings_pin_rooms_with_unread" = "置顶含有未读消息的聊天室";
"settings_on_denied_notification" = "%@ 的通知请求被拒绝,请在系统设置中允许";
"settings_unignore_user" = "显示所有来自 %@ 的消息?";
"settings_contacts_discover_matrix_users" = "使用电子邮件和手机号码来发现用户";
"settings_contacts_phonebook_country" = "电话本国家";
@ -1426,7 +1425,7 @@
"settings_ui_theme_picker_message_invert_colours" = "“自动”使用您设备的“反转颜色”设置";
"room_recents_unknown_room_error_message" = "找不到这个房间。 确保它存在";
"room_creation_dm_error" = "我们无法创建您的 DM。 请检查您要邀请的用户,然后重试。";
"voice_message_stop_locked_mode_recording" = "轻按波长停止和回放消息";
"voice_message_stop_locked_mode_recording" = "轻按录音停止或收听";
"voice_message_remaining_recording_time" = "剩 %@s";
// Mark: - Voice Messages

View file

@ -344,7 +344,6 @@
"room_ongoing_conference_call_with_close" = "群組通話進行中。 以 %@ 或 %@ 加入。%@ 該通話。";
"settings_pin_rooms_with_missed_notif" = "釘選含有錯過的通知的聊天室";
"settings_pin_rooms_with_unread" = "釘選含有未讀訊息的聊天室";
"settings_on_denied_notification" = "因 %@ 的通知不被允許,請在裝置設定中允許";
"settings_enable_callkit" = "整合式通話";
"settings_callkit_info" = "在鎖定畫面接聽 Element 來電、在通話紀錄中顯示 Element 通話。 如果您已啟用 iCloud ,則這些通話紀錄會與蘋果公司共享。";
"settings_ui_language" = "語言";

View file

@ -36,6 +36,8 @@ internal enum Asset {
internal static let callDialpadCallIcon = ImageAsset(name: "call_dialpad_call_icon")
internal static let callGoToChatIcon = ImageAsset(name: "call_go_to_chat_icon")
internal static let callHangupLarge = ImageAsset(name: "call_hangup_large")
internal static let callMissedVideo = ImageAsset(name: "call_missed_video")
internal static let callMissedVoice = ImageAsset(name: "call_missed_voice")
internal static let callMoreIcon = ImageAsset(name: "call_more_icon")
internal static let callPausedIcon = ImageAsset(name: "call_paused_icon")
internal static let callPausedWhiteIcon = ImageAsset(name: "call_paused_white_icon")

View file

@ -1242,6 +1242,14 @@ internal enum VectorL10n {
internal static var errorUserAlreadyLoggedIn: String {
return VectorL10n.tr("Vector", "error_user_already_logged_in")
}
/// Active video call
internal static var eventFormatterCallActiveVideo: String {
return VectorL10n.tr("Vector", "event_formatter_call_active_video")
}
/// Active voice call
internal static var eventFormatterCallActiveVoice: String {
return VectorL10n.tr("Vector", "event_formatter_call_active_voice")
}
/// Answer
internal static var eventFormatterCallAnswer: String {
return VectorL10n.tr("Vector", "event_formatter_call_answer")
@ -1266,9 +1274,29 @@ internal enum VectorL10n {
internal static var eventFormatterCallEndCall: String {
return VectorL10n.tr("Vector", "event_formatter_call_end_call")
}
/// Ended %@
internal static func eventFormatterCallHasEnded(_ p1: String) -> String {
return VectorL10n.tr("Vector", "event_formatter_call_has_ended", p1)
/// Call ended
internal static var eventFormatterCallHasEnded: String {
return VectorL10n.tr("Vector", "event_formatter_call_has_ended")
}
/// Call ended %@
internal static func eventFormatterCallHasEndedWithTime(_ p1: String) -> String {
return VectorL10n.tr("Vector", "event_formatter_call_has_ended_with_time", p1)
}
/// Incoming video call
internal static var eventFormatterCallIncomingVideo: String {
return VectorL10n.tr("Vector", "event_formatter_call_incoming_video")
}
/// Incoming voice call
internal static var eventFormatterCallIncomingVoice: String {
return VectorL10n.tr("Vector", "event_formatter_call_incoming_voice")
}
/// Missed video call
internal static var eventFormatterCallMissedVideo: String {
return VectorL10n.tr("Vector", "event_formatter_call_missed_video")
}
/// Missed voice call
internal static var eventFormatterCallMissedVoice: String {
return VectorL10n.tr("Vector", "event_formatter_call_missed_voice")
}
/// Retry
internal static var eventFormatterCallRetry: String {
@ -1278,26 +1306,10 @@ internal enum VectorL10n {
internal static var eventFormatterCallRinging: String {
return VectorL10n.tr("Vector", "event_formatter_call_ringing")
}
/// Video call
internal static var eventFormatterCallVideo: String {
return VectorL10n.tr("Vector", "event_formatter_call_video")
}
/// Voice call
internal static var eventFormatterCallVoice: String {
return VectorL10n.tr("Vector", "event_formatter_call_voice")
}
/// Active call
internal static var eventFormatterCallYouCurrentlyIn: String {
return VectorL10n.tr("Vector", "event_formatter_call_you_currently_in")
}
/// You declined this call
/// Call declined
internal static var eventFormatterCallYouDeclined: String {
return VectorL10n.tr("Vector", "event_formatter_call_you_declined")
}
/// You missed this call
internal static var eventFormatterCallYouMissed: String {
return VectorL10n.tr("Vector", "event_formatter_call_you_missed")
}
/// Group call
internal static var eventFormatterGroupCall: String {
return VectorL10n.tr("Vector", "event_formatter_group_call")
@ -4114,6 +4126,10 @@ internal enum VectorL10n {
internal static var settingsDeactivateMyAccount: String {
return VectorL10n.tr("Vector", "settings_deactivate_my_account")
}
/// Device notifications
internal static var settingsDeviceNotifications: String {
return VectorL10n.tr("Vector", "settings_device_notifications")
}
/// SESSIONS
internal static var settingsDevices: String {
return VectorL10n.tr("Vector", "settings_devices")
@ -4390,6 +4406,14 @@ internal enum VectorL10n {
internal static var settingsNightMode: String {
return VectorL10n.tr("Vector", "settings_night_mode")
}
/// To enable notifications, go to your device settings.
internal static var settingsNotificationsDisabledAlertMessage: String {
return VectorL10n.tr("Vector", "settings_notifications_disabled_alert_message")
}
/// Notifications disabled
internal static var settingsNotificationsDisabledAlertTitle: String {
return VectorL10n.tr("Vector", "settings_notifications_disabled_alert_title")
}
/// NOTIFICATION SETTINGS
internal static var settingsNotificationsSettings: String {
return VectorL10n.tr("Vector", "settings_notifications_settings")
@ -4402,10 +4426,6 @@ internal enum VectorL10n {
internal static func settingsOlmVersion(_ p1: String) -> String {
return VectorL10n.tr("Vector", "settings_olm_version", p1)
}
/// Notifications are denied for %@, please allow them in your device settings
internal static func settingsOnDeniedNotification(_ p1: String) -> String {
return VectorL10n.tr("Vector", "settings_on_denied_notification", p1)
}
/// OTHER
internal static var settingsOther: String {
return VectorL10n.tr("Vector", "settings_other")
@ -4882,6 +4902,10 @@ internal enum VectorL10n {
internal static var voice: String {
return VectorL10n.tr("Vector", "voice")
}
/// Voice message
internal static var voiceMessageLockScreenPlaceholder: String {
return VectorL10n.tr("Vector", "voice_message_lock_screen_placeholder")
}
/// Hold to record, release to send
internal static var voiceMessageReleaseToSend: String {
return VectorL10n.tr("Vector", "voice_message_release_to_send")

View file

@ -52,7 +52,6 @@ final class RiotSettings: NSObject {
static let roomCreationScreenRoomIsPublic = "roomCreationScreenRoomIsPublic"
static let allowInviteExernalUsers = "allowInviteExernalUsers"
static let enableRingingForGroupCalls = "enableRingingForGroupCalls"
static let enableVoiceMessages = "enableVoiceMessages"
static let roomSettingsScreenShowLowPriorityOption = "roomSettingsScreenShowLowPriorityOption"
static let roomSettingsScreenShowDirectChatOption = "roomSettingsScreenShowDirectChatOption"
static let roomSettingsScreenAllowChangingAccessSettings = "roomSettingsScreenAllowChangingAccessSettings"
@ -96,7 +95,6 @@ final class RiotSettings: NSObject {
private override init() {
super.init()
defaults.register(defaults: [UserDefaultsKeys.enableVoiceMessages: BuildSettings.voiceMessagesEnabled])
}
// MARK: Servers
@ -221,14 +219,6 @@ final class RiotSettings: NSObject {
}
}
var enableVoiceMessages: Bool {
get {
return defaults.bool(forKey: UserDefaultsKeys.enableVoiceMessages)
} set {
defaults.set(newValue, forKey: UserDefaultsKeys.enableVoiceMessages)
}
}
// MARK: Calls
/// Indicate if `allowStunServerFallback` settings has been set once.

View file

@ -23,7 +23,6 @@
@property (weak, nonatomic) IBOutlet UIView *missedNotifAndUnreadIndicator;
@property (weak, nonatomic) IBOutlet MXKImageView *roomAvatar;
@property (weak, nonatomic) IBOutlet UIView *directRoomBorderView;
@property (weak, nonatomic) IBOutlet UIImageView *encryptedRoomIcon;
@property (weak, nonatomic) IBOutlet UILabel *missedNotifAndUnreadBadgeLabel;

View file

@ -27,11 +27,6 @@
#import "MXRoomSummary+Riot.h"
#pragma mark - Defines & Constants
static const CGFloat kDirectRoomBorderColorAlpha = 0.75;
static const CGFloat kDirectRoomBorderWidth = 3.0;
@implementation RecentTableViewCell
#pragma mark - Class methods
@ -54,16 +49,6 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
self.lastEventDate.textColor = ThemeService.shared.theme.textSecondaryColor;
self.missedNotifAndUnreadBadgeLabel.textColor = ThemeService.shared.theme.baseTextPrimaryColor;
// Prepare direct room border
CGColorRef directRoomBorderColor = CGColorCreateCopyWithAlpha(ThemeService.shared.theme.tintColor.CGColor, kDirectRoomBorderColorAlpha);
[self.directRoomBorderView.layer setCornerRadius:self.directRoomBorderView.frame.size.width / 2];
self.directRoomBorderView.clipsToBounds = YES;
self.directRoomBorderView.layer.borderColor = directRoomBorderColor;
self.directRoomBorderView.layer.borderWidth = kDirectRoomBorderWidth;
CFRelease(directRoomBorderColor);
self.roomAvatar.defaultBackgroundColor = [UIColor clearColor];
}
@ -138,8 +123,6 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
// The room title is not bold anymore
self.roomTitle.font = [UIFont systemFontOfSize:17 weight:UIFontWeightMedium];
}
self.directRoomBorderView.hidden = !roomCellData.roomSummary.room.isDirect;
[roomCellData.roomSummary setRoomAvatarImageIn:self.roomAvatar];
}

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -34,14 +34,6 @@
<constraint firstAttribute="height" constant="42" id="WPC-tL-hnM"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8CY-Ku-0qh">
<rect key="frame" x="13" y="15" width="42" height="42"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="42" id="ize-F0-OeQ"/>
<constraint firstAttribute="width" constant="42" id="t6V-Zm-EM3"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lg1-xQ-AGn">
<rect key="frame" x="69" y="14" width="451" height="21"/>
<accessibility key="accessibilityConfiguration" identifier="TitleLabel"/>
@ -109,7 +101,6 @@
</subviews>
<constraints>
<constraint firstItem="F6K-PV-15f" firstAttribute="trailing" secondItem="360-Go-RcG" secondAttribute="trailing" id="3qB-Na-Eqs"/>
<constraint firstItem="8CY-Ku-0qh" firstAttribute="centerX" secondItem="RX5-eD-c3c" secondAttribute="centerX" id="FVh-1h-VkB"/>
<constraint firstItem="360-Go-RcG" firstAttribute="leading" secondItem="OeZ-wN-eil" secondAttribute="trailing" constant="8" id="KuE-8m-e9A"/>
<constraint firstItem="e7r-zL-9bw" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" id="PUW-if-ewh"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="leading" secondItem="RX5-eD-c3c" secondAttribute="trailing" constant="14" id="Pgp-JM-oQd"/>
@ -127,13 +118,11 @@
<constraint firstAttribute="trailing" secondItem="dQt-mN-T6b" secondAttribute="trailing" constant="30" id="t2m-pb-5zd"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="14" id="tY3-6V-A3B"/>
<constraint firstItem="RX5-eD-c3c" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" constant="13" id="tgy-cX-Wxm"/>
<constraint firstItem="8CY-Ku-0qh" firstAttribute="centerY" secondItem="RX5-eD-c3c" secondAttribute="centerY" id="ukJ-yz-Kit"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RecentTableViewCell"/>
<connections>
<outlet property="directRoomBorderView" destination="8CY-Ku-0qh" id="vKk-ZO-TQq"/>
<outlet property="encryptedRoomIcon" destination="NAZ-zd-MHS" id="ZsH-Zr-Q4K"/>
<outlet property="lastEventDate" destination="360-Go-RcG" id="Y0L-Dj-ZVn"/>
<outlet property="lastEventDecriptionLabelTrailingConstraint" destination="t2m-pb-5zd" id="cxp-7Z-bEg"/>

View file

@ -22,7 +22,6 @@
@interface RoomTableViewCell : MXKTableViewCell
@property (weak, nonatomic) IBOutlet MXKImageView *avatarImageView;
@property (weak, nonatomic) IBOutlet UIView *directRoomBorderView;
@property (weak, nonatomic) IBOutlet UIImageView *encryptedRoomIcon;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;

View file

@ -22,11 +22,6 @@
#import "MXRoomSummary+Riot.h"
#pragma mark - Defines & Constants
static const CGFloat kDirectRoomBorderColorAlpha = 0.75;
static const CGFloat kDirectRoomBorderWidth = 3.0;
@implementation RoomTableViewCell
#pragma mark - Class methods
@ -37,16 +32,6 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
self.titleLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
// Prepare direct room border
CGColorRef directRoomBorderColor = CGColorCreateCopyWithAlpha(ThemeService.shared.theme.tintColor.CGColor, kDirectRoomBorderColorAlpha);
[self.directRoomBorderView.layer setCornerRadius:self.directRoomBorderView.frame.size.width / 2];
self.directRoomBorderView.clipsToBounds = YES;
self.directRoomBorderView.layer.borderColor = directRoomBorderColor;
self.directRoomBorderView.layer.borderWidth = kDirectRoomBorderWidth;
CFRelease(directRoomBorderColor);
self.avatarImageView.defaultBackgroundColor = [UIColor clearColor];
}
@ -64,15 +49,6 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
[room.summary setRoomAvatarImageIn:self.avatarImageView];
self.titleLabel.text = room.summary.displayname;
self.directRoomBorderView.hidden = !room.isDirect;
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.directRoomBorderView.hidden = YES;
}
+ (CGFloat)cellHeight

View file

@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -14,8 +12,8 @@
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="L2L-l5-wPx" customClass="RoomTableViewCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="74"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="L2L-l5-wPx" id="aXz-IR-jj5">
<rect key="frame" x="0.0" y="0.0" width="600" height="73.5"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" ambiguous="YES" tableViewCell="L2L-l5-wPx" id="aXz-IR-jj5">
<rect key="frame" x="0.0" y="0.0" width="600" height="74"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FfX-ul-Kr4" customClass="MXKImageView">
@ -23,19 +21,12 @@
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AvatarImageView"/>
<constraints>
<constraint firstAttribute="width" constant="42" id="DCk-EO-Wpn"/>
<constraint firstAttribute="height" constant="42" id="bkm-0A-IeX"/>
<constraint firstAttribute="width" secondItem="FfX-ul-Kr4" secondAttribute="height" multiplier="1:1" id="ycc-8M-xEj"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="O8i-B6-S6A">
<rect key="frame" x="26" y="16" width="42" height="42"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" secondItem="O8i-B6-S6A" secondAttribute="height" multiplier="1:1" id="KP4-Uc-4pf"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lg1-xQ-AGn">
<rect key="frame" x="82" y="27" width="34" height="20"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" ambiguous="YES" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lg1-xQ-AGn">
<rect key="frame" x="82" y="27" width="33" height="20"/>
<accessibility key="accessibilityConfiguration" identifier="TitleLabel"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="NW9-MB-gf4"/>
@ -45,7 +36,7 @@
<nil key="highlightedColor"/>
</label>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="e2e_verified" translatesAutoresizingMaskIntoConstraints="NO" id="apY-Nk-wQh">
<rect key="frame" x="62" y="45" width="11" height="13"/>
<rect key="frame" x="58" y="45" width="11" height="13"/>
<accessibility key="accessibilityConfiguration" identifier="EncryptedRoomIcon"/>
<constraints>
<constraint firstAttribute="width" constant="11" id="6Pz-2E-7D8"/>
@ -56,25 +47,22 @@
<constraints>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="leading" secondItem="FfX-ul-Kr4" secondAttribute="trailing" constant="14" id="A6H-TC-2Pg"/>
<constraint firstAttribute="bottom" secondItem="FfX-ul-Kr4" secondAttribute="bottom" constant="15.5" id="D2o-qq-OsZ"/>
<constraint firstItem="O8i-B6-S6A" firstAttribute="centerY" secondItem="FfX-ul-Kr4" secondAttribute="centerY" id="L8U-Xi-rD7"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="centerY" secondItem="aXz-IR-jj5" secondAttribute="centerY" id="O6E-Di-2d4"/>
<constraint firstItem="apY-Nk-wQh" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="topMargin" constant="34" id="Rlm-bQ-Qpr"/>
<constraint firstItem="O8i-B6-S6A" firstAttribute="width" secondItem="FfX-ul-Kr4" secondAttribute="width" id="Sej-VT-sBx"/>
<constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="Lg1-xQ-AGn" secondAttribute="trailing" constant="15" id="U1F-vo-7f6"/>
<constraint firstItem="apY-Nk-wQh" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leadingMargin" constant="42" id="dut-Df-DIU"/>
<constraint firstItem="FfX-ul-Kr4" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leadingMargin" constant="6" id="qey-6T-URF"/>
<constraint firstItem="FfX-ul-Kr4" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leadingMargin" constant="10" id="qey-6T-URF"/>
<constraint firstItem="FfX-ul-Kr4" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="16" id="wyT-JI-kQS"/>
<constraint firstItem="O8i-B6-S6A" firstAttribute="centerX" secondItem="FfX-ul-Kr4" secondAttribute="centerX" id="xfK-sI-YJQ"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomTableViewCell"/>
<connections>
<outlet property="avatarImageView" destination="FfX-ul-Kr4" id="NOo-Lj-BBY"/>
<outlet property="directRoomBorderView" destination="O8i-B6-S6A" id="b7x-Sz-SiX"/>
<outlet property="encryptedRoomIcon" destination="apY-Nk-wQh" id="qlf-6j-voX"/>
<outlet property="titleLabel" destination="Lg1-xQ-AGn" id="uqU-hH-KT0"/>
</connections>
<point key="canvasLocation" x="-14" y="132"/>
</tableViewCell>
</objects>
<resources>

View file

@ -36,7 +36,6 @@
@property (weak, nonatomic) IBOutlet UIView *editionArrowView;
@property (weak, nonatomic) IBOutlet UIView *directRoomBorderView;
@property (weak, nonatomic) IBOutlet MXKImageView *roomAvatar;
@property (weak, nonatomic) IBOutlet UIImageView *encryptedRoomIcon;

View file

@ -26,11 +26,6 @@
#import "MXTools.h"
#pragma mark - Defines & Constants
static const CGFloat kDirectRoomBorderColorAlpha = 0.75;
static const CGFloat kDirectRoomBorderWidth = 3.0;
@implementation RoomCollectionViewCell
#pragma mark - Class methods
@ -67,16 +62,6 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
self.roomTitle1.textColor = ThemeService.shared.theme.textPrimaryColor;
self.roomTitle2.textColor = ThemeService.shared.theme.textPrimaryColor;
// Prepare direct room border
CGColorRef directRoomBorderColor = CGColorCreateCopyWithAlpha(ThemeService.shared.theme.tintColor.CGColor, kDirectRoomBorderColorAlpha);
[self.directRoomBorderView.layer setCornerRadius:self.directRoomBorderView.frame.size.width / 2];
self.directRoomBorderView.clipsToBounds = YES;
self.directRoomBorderView.layer.borderColor = directRoomBorderColor;
self.directRoomBorderView.layer.borderWidth = kDirectRoomBorderWidth;
CFRelease(directRoomBorderColor);
self.editionArrowView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
self.roomAvatar.defaultBackgroundColor = [UIColor clearColor];
@ -145,8 +130,6 @@ static const CGFloat kDirectRoomBorderWidth = 3.0;
}
self.directRoomBorderView.hidden = !roomCellData.roomSummary.room.isDirect;
[roomCellData.roomSummary setRoomAvatarImageIn:self.roomAvatar];
}
}

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -24,16 +24,8 @@
<constraint firstAttribute="width" secondItem="T1Q-RS-8o6" secondAttribute="height" multiplier="1:1" id="zmb-Nw-TEX"/>
</constraints>
</view>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xws-BR-H47">
<rect key="frame" x="10" y="10" width="60" height="60"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" constant="60" id="3OW-3y-Rg7"/>
<constraint firstAttribute="width" secondItem="xws-BR-H47" secondAttribute="height" multiplier="1:1" id="bEP-hL-5lg"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="!" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="scs-Ov-Tjv" customClass="BadgeLabel" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="56" y="8" width="16.5" height="16.5"/>
<rect key="frame" x="62" y="9" width="4.5" height="14.5"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -81,9 +73,8 @@
<constraint firstItem="oxX-IL-dG4" firstAttribute="top" secondItem="T1Q-RS-8o6" secondAttribute="bottom" constant="4" id="2DB-H2-E2v"/>
<constraint firstAttribute="bottom" secondItem="jta-3V-4wL" secondAttribute="bottom" id="3rt-Ig-1rG"/>
<constraint firstItem="oxX-IL-dG4" firstAttribute="leading" secondItem="eCk-zY-LXq" secondAttribute="leading" constant="4" id="6gu-JD-Gb1"/>
<constraint firstItem="scs-Ov-Tjv" firstAttribute="centerY" secondItem="xws-BR-H47" secondAttribute="top" constant="6" id="CRF-wK-Lcp"/>
<constraint firstItem="scs-Ov-Tjv" firstAttribute="centerY" secondItem="T1Q-RS-8o6" secondAttribute="top" constant="6" id="CRF-wK-Lcp"/>
<constraint firstItem="X8H-1U-wc3" firstAttribute="centerX" secondItem="oxX-IL-dG4" secondAttribute="centerX" id="K9T-eO-WNb"/>
<constraint firstItem="xws-BR-H47" firstAttribute="centerX" secondItem="T1Q-RS-8o6" secondAttribute="centerX" id="Lo3-Ov-Bw8"/>
<constraint firstItem="Jkz-Zp-aaG" firstAttribute="centerX" secondItem="oxX-IL-dG4" secondAttribute="centerX" id="OQy-tF-e3Z"/>
<constraint firstItem="jta-3V-4wL" firstAttribute="centerX" secondItem="eCk-zY-LXq" secondAttribute="centerX" id="R87-mq-SlO"/>
<constraint firstItem="5Yd-df-HbB" firstAttribute="bottom" secondItem="T1Q-RS-8o6" secondAttribute="bottom" constant="2" id="RQU-MS-Qfr"/>
@ -91,8 +82,7 @@
<constraint firstItem="X8H-1U-wc3" firstAttribute="leading" secondItem="eCk-zY-LXq" secondAttribute="leading" constant="7" id="XU5-Lv-9Xn"/>
<constraint firstItem="T1Q-RS-8o6" firstAttribute="top" secondItem="eCk-zY-LXq" secondAttribute="top" constant="10" id="cc7-bg-15Z"/>
<constraint firstItem="Jkz-Zp-aaG" firstAttribute="leading" secondItem="eCk-zY-LXq" secondAttribute="leading" constant="7" id="fPh-Lb-Bv9"/>
<constraint firstItem="xws-BR-H47" firstAttribute="centerY" secondItem="T1Q-RS-8o6" secondAttribute="centerY" id="faX-hg-WfP"/>
<constraint firstItem="scs-Ov-Tjv" firstAttribute="centerX" secondItem="xws-BR-H47" secondAttribute="trailing" priority="750" constant="-6" id="fgA-Sf-Y4E"/>
<constraint firstItem="scs-Ov-Tjv" firstAttribute="centerX" secondItem="T1Q-RS-8o6" secondAttribute="trailing" priority="750" constant="-6" id="fgA-Sf-Y4E"/>
<constraint firstAttribute="trailing" secondItem="oxX-IL-dG4" secondAttribute="trailing" constant="4" id="hDl-X9-M4n"/>
<constraint firstItem="T1Q-RS-8o6" firstAttribute="centerX" secondItem="eCk-zY-LXq" secondAttribute="centerX" id="hmB-fl-oN2"/>
<constraint firstAttribute="trailing" secondItem="X8H-1U-wc3" secondAttribute="trailing" constant="7" id="o5i-7H-n0G"/>
@ -103,7 +93,6 @@
</constraints>
<connections>
<outlet property="badgeLabel" destination="scs-Ov-Tjv" id="KPV-Qb-cnT"/>
<outlet property="directRoomBorderView" destination="xws-BR-H47" id="34A-hu-DXq"/>
<outlet property="editionArrowView" destination="jta-3V-4wL" id="XLj-Cx-3bn"/>
<outlet property="encryptedRoomIcon" destination="5Yd-df-HbB" id="5pc-Vi-wMZ"/>
<outlet property="roomAvatar" destination="T1Q-RS-8o6" id="4sR-Wm-jwz"/>
@ -116,11 +105,11 @@
</objects>
<designables>
<designable name="scs-Ov-Tjv">
<size key="intrinsicContentSize" width="16.5" height="16.5"/>
<size key="intrinsicContentSize" width="4.5" height="14.5"/>
</designable>
</designables>
<resources>
<image name="encryption_normal" width="16" height="16"/>
<image name="encryption_normal" width="12" height="12"/>
<systemColor name="groupTableViewBackgroundColor">
<color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>

View file

@ -998,6 +998,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}
[self refreshRoomInputToolbar];
[VoiceMessageMediaServiceProvider.sharedProvider setCurrentRoomSummary:dataSource.room.summary];
}
- (void)onRoomDataSourceReady

View file

@ -32,8 +32,6 @@ class CallBubbleCellBaseContentView: UIView {
@IBOutlet weak var avatarImageView: MXKImageView!
@IBOutlet weak var callerNameLabel: UILabel!
@IBOutlet weak var callIconView: UIImageView!
@IBOutlet weak var callTypeLabel: UILabel!
@IBOutlet weak var dotLabel: UILabel!
@IBOutlet private weak var callStatusLabel: UILabel!
@IBOutlet private weak var callSummaryHeightConstraint: NSLayoutConstraint!
@ -51,7 +49,6 @@ class CallBubbleCellBaseContentView: UIView {
var statusText: String? {
didSet {
dotLabel.isHidden = statusText == nil
callStatusLabel.text = statusText
}
}
@ -105,9 +102,7 @@ extension CallBubbleCellBaseContentView: Themable {
bgView.backgroundColor = theme.colors.tile
callerNameLabel.textColor = theme.textPrimaryColor
callIconView.tintColor = theme.textTertiaryColor
callTypeLabel.textColor = theme.textSecondaryColor
dotLabel.textColor = theme.textSecondaryColor
callIconView.tintColor = theme.textSecondaryColor
callStatusLabel.textColor = theme.textSecondaryColor
if let bottomContainerView = bottomContainerView as? Themable {

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -78,7 +78,7 @@
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="kdm-vj-rsY">
<rect key="frame" x="92" y="98" width="160.5" height="20"/>
<rect key="frame" x="130" y="98" width="84" height="20"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="voice_call_hangon_icon" translatesAutoresizingMaskIntoConstraints="NO" id="iQL-Bn-D9b">
<rect key="frame" x="0.0" y="2" width="16" height="16"/>
@ -87,20 +87,8 @@
<constraint firstAttribute="height" constant="16" id="OdD-1h-kkV"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Voice call" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="alq-3S-yHg">
<rect key="frame" x="22" y="2" width="58" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="•" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6xJ-gU-ls1">
<rect key="frame" x="86" y="2" width="6.5" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Active call" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="A3h-4o-nXF">
<rect key="frame" x="98.5" y="2" width="62" height="16"/>
<rect key="frame" x="22" y="2" width="62" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -197,9 +185,7 @@
<outlet property="callIconView" destination="iQL-Bn-D9b" id="Cih-PG-EM2"/>
<outlet property="callStatusLabel" destination="A3h-4o-nXF" id="9Zf-aC-DAq"/>
<outlet property="callSummaryHeightConstraint" destination="xI1-oH-QU6" id="EnC-Bt-TkY"/>
<outlet property="callTypeLabel" destination="alq-3S-yHg" id="lgA-Dw-PH2"/>
<outlet property="callerNameLabel" destination="ONW-WU-t2g" id="0Vj-Xn-CLD"/>
<outlet property="dotLabel" destination="6xJ-gU-ls1" id="8ln-dF-l7V"/>
<outlet property="paginationLabel" destination="GQH-kh-LXA" id="Mww-Ps-yv1"/>
<outlet property="paginationSeparatorView" destination="YdR-PH-eGM" id="aK7-LF-awm"/>
<outlet property="paginationTitleView" destination="H6S-AE-DTm" id="yep-a0-QYq"/>

View file

@ -57,6 +57,7 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
private var viewState: ViewState = .unknown {
didSet {
updateBottomContentView()
updateCallIcon()
}
}
@ -78,11 +79,24 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
return formatter
}
private func updateCallIcon() {
switch viewState {
case .missed:
innerContentView.callIconView.image = isVideoCall ?
Asset.Images.callMissedVideo.image :
Asset.Images.callMissedVoice.image
default:
innerContentView.callIconView.image = isVideoCall ?
Asset.Images.callVideoIcon.image :
Asset.Images.voiceCallHangonIcon.image
}
}
private func updateBottomContentView() {
bottomContentView = bottomView(for: viewState)
}
private var callTypeIcon: UIImage {
private var callButtonIcon: UIImage {
if isVideoCall {
return Asset.Images.callVideoIcon.image
} else {
@ -112,7 +126,7 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
view.secondButton.style = .positive
view.secondButton.setTitle(VectorL10n.eventFormatterCallAnswer, for: .normal)
view.secondButton.setImage(callTypeIcon, for: .normal)
view.secondButton.setImage(callButtonIcon, for: .normal)
view.secondButton.removeTarget(nil, action: nil, for: .touchUpInside)
view.secondButton.addTarget(self, action: #selector(answerCallAction(_:)), for: .touchUpInside)
@ -134,7 +148,7 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
view.firstButton.style = .positive
view.firstButton.setTitle(VectorL10n.eventFormatterCallBack, for: .normal)
view.firstButton.setImage(callTypeIcon, for: .normal)
view.firstButton.setImage(callButtonIcon, for: .normal)
view.firstButton.removeTarget(nil, action: nil, for: .touchUpInside)
view.firstButton.addTarget(self, action: #selector(callBackAction(_:)), for: .touchUpInside)
@ -145,7 +159,7 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
view.firstButton.style = .positive
view.firstButton.setTitle(VectorL10n.eventFormatterCallBack, for: .normal)
view.firstButton.setImage(callTypeIcon, for: .normal)
view.firstButton.setImage(callButtonIcon, for: .normal)
view.firstButton.removeTarget(nil, action: nil, for: .touchUpInside)
view.firstButton.addTarget(self, action: #selector(callBackAction(_:)), for: .touchUpInside)
@ -158,7 +172,7 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
view.firstButton.style = .positive
view.firstButton.setTitle(VectorL10n.eventFormatterCallRetry, for: .normal)
view.firstButton.setImage(callTypeIcon, for: .normal)
view.firstButton.setImage(callButtonIcon, for: .normal)
view.firstButton.removeTarget(nil, action: nil, for: .touchUpInside)
view.firstButton.addTarget(self, action: #selector(callBackAction(_:)), for: .touchUpInside)
@ -174,13 +188,13 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
.connecting:
viewState = .active
if call.isIncoming {
statusText = VectorL10n.eventFormatterCallYouCurrentlyIn
statusText = isVideoCall ? VectorL10n.eventFormatterCallActiveVideo : VectorL10n.eventFormatterCallActiveVoice
} else {
statusText = VectorL10n.eventFormatterCallConnecting
}
case .inviteSent:
if call.isIncoming {
statusText = VectorL10n.eventFormatterCallYouCurrentlyIn
statusText = isVideoCall ? VectorL10n.eventFormatterCallActiveVideo : VectorL10n.eventFormatterCallActiveVoice
} else {
statusText = VectorL10n.eventFormatterCallRinging
}
@ -189,14 +203,14 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
.onHold,
.remotelyOnHold:
viewState = .active
statusText = VectorL10n.eventFormatterCallYouCurrentlyIn
statusText = isVideoCall ? VectorL10n.eventFormatterCallActiveVideo : VectorL10n.eventFormatterCallActiveVoice
case .ringing:
if call.isIncoming {
viewState = .ringing
statusText = nil
statusText = isVideoCall ? VectorL10n.eventFormatterCallIncomingVideo : VectorL10n.eventFormatterCallIncomingVoice
} else {
viewState = .active
statusText = VectorL10n.eventFormatterCallYouCurrentlyIn
statusText = isVideoCall ? VectorL10n.eventFormatterCallActiveVideo : VectorL10n.eventFormatterCallActiveVoice
}
case .ended:
switch call.endReason {
@ -206,27 +220,27 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
.remoteHangup,
.answeredElseWhere:
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
case .missed:
if call.isIncoming {
viewState = .missed
statusText = VectorL10n.eventFormatterCallYouMissed
statusText = isVideoCall ? VectorL10n.eventFormatterCallMissedVideo : VectorL10n.eventFormatterCallMissedVoice
} else {
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
}
case .busy:
configureForRejectedCall(call: call)
@unknown default:
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
}
case .inviteExpired,
.answeredElseWhere:
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
@unknown default:
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
}
}
@ -247,21 +261,21 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
statusText = VectorL10n.eventFormatterCallYouDeclined
} else {
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
}
}
private func configureForHangupCall(withEvent event: MXEvent) {
guard let hangupEventContent = MXCallHangupEventContent(fromJSON: event.content) else {
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
return
}
switch hangupEventContent.reasonType {
case .userHangup:
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
default:
viewState = .failed
statusText = VectorL10n.eventFormatterCallConnectionFailed
@ -272,11 +286,19 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
if isIncoming {
// missed call
viewState = .missed
statusText = VectorL10n.eventFormatterCallYouMissed
statusText = isVideoCall ? VectorL10n.eventFormatterCallMissedVideo : VectorL10n.eventFormatterCallMissedVoice
} else {
// outgoing unanswered call
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
}
}
private func updateStatusTextForEndedCall() {
if callDurationString.count > 0 {
statusText = VectorL10n.eventFormatterCallHasEndedWithTime(callDurationString)
} else {
statusText = VectorL10n.eventFormatterCallHasEnded
}
}
@ -366,11 +388,7 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
callDurationString = readableCallDuration(from: events)
isIncoming = inviteEvent.sender != bubbleCellData.mxSession.myUserId
callInviteEvent = inviteEvent
innerContentView.callIconView.image = self.callTypeIcon
innerContentView.callTypeLabel.text = isVideoCall ?
VectorL10n.eventFormatterCallVideo :
VectorL10n.eventFormatterCallVoice
updateCallIcon()
let callId = callInviteEventContent.callId
guard let call = bubbleCellData.mxSession.callManager.call(withCallId: callId) else {
@ -394,7 +412,7 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
// there is no reject or hangup event, we can just say this call has ended
viewState = .ended
statusText = VectorL10n.eventFormatterCallHasEnded(callDurationString)
updateStatusTextForEndedCall()
return
}

View file

@ -158,6 +158,14 @@ class RoomGroupCallStatusBubbleCell: RoomBaseCallBubbleCell {
}
}
private func updateStatusTextForEndedCall() {
if callDurationString.count > 0 {
statusText = VectorL10n.eventFormatterCallHasEndedWithTime(callDurationString)
} else {
statusText = VectorL10n.eventFormatterCallHasEnded
}
}
// MARK: - Actions
@objc
@ -224,7 +232,6 @@ class RoomGroupCallStatusBubbleCell: RoomBaseCallBubbleCell {
self.widgetEvent = widgetEvent
self.widgetId = widgetId
innerContentView.callIconView.image = Asset.Images.callVideoIcon.image
innerContentView.callTypeLabel.text = VectorL10n.eventFormatterCallVideo
if isIncoming && !isJoined &&
TimeInterval(widgetEvent.age)/MSEC_PER_SEC < Constants.secondsToDisplayAnswerDeclineOptions {
@ -266,7 +273,7 @@ class RoomGroupCallStatusBubbleCell: RoomBaseCallBubbleCell {
in: room,
with: roomState) else {
self.viewState = .ended
self.statusText = VectorL10n.eventFormatterCallHasEnded(self.callDurationString)
self.updateStatusTextForEndedCall()
return
}
@ -278,14 +285,14 @@ class RoomGroupCallStatusBubbleCell: RoomBaseCallBubbleCell {
guard let widget = widgets.first(where: { $0.widgetId == widgetId }) else {
self.viewState = .ended
self.statusText = VectorL10n.eventFormatterCallHasEnded(self.callDurationString)
self.updateStatusTextForEndedCall()
return
}
if widget.isActive {
if !self.isIncoming {
self.viewState = .active
self.statusText = VectorL10n.eventFormatterCallYouCurrentlyIn
self.statusText = VectorL10n.eventFormatterCallActiveVideo
} else if !self.isJoined &&
TimeInterval(widgetEvent.age)/MSEC_PER_SEC < Constants.secondsToDisplayAnswerDeclineOptions {
@ -298,11 +305,11 @@ class RoomGroupCallStatusBubbleCell: RoomBaseCallBubbleCell {
}
} else {
self.viewState = .active
self.statusText = VectorL10n.eventFormatterCallYouCurrentlyIn
self.statusText = VectorL10n.eventFormatterCallActiveVideo
}
} else {
self.viewState = .ended
self.statusText = VectorL10n.eventFormatterCallHasEnded(self.callDurationString)
self.updateStatusTextForEndedCall()
}
}
}

View file

@ -82,10 +82,6 @@ const CGFloat kComposerContainerTrailingPadding = 12;
- (void)setVoiceMessageToolbarView:(UIView *)voiceMessageToolbarView
{
if (RiotSettings.shared.enableVoiceMessages == NO) {
return;
}
_voiceMessageToolbarView = voiceMessageToolbarView;
self.voiceMessageToolbarView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:self.voiceMessageToolbarView];
@ -407,10 +403,7 @@ const CGFloat kComposerContainerTrailingPadding = 12;
[UIView animateWithDuration:kActionMenuContentAlphaAnimationDuration delay:_actionMenuOpened ? 0 : .1 options:UIViewAnimationOptionCurveEaseIn animations:^{
self->messageComposerContainer.alpha = actionMenuOpened ? 0 : 1;
self.rightInputToolbarButton.alpha = self->growingTextView.text.length == 0 || actionMenuOpened ? 0 : 1;
if (RiotSettings.shared.enableVoiceMessages)
{
self.voiceMessageToolbarView.alpha = self->growingTextView.text.length > 0 || actionMenuOpened ? 0 : 1;
}
self.voiceMessageToolbarView.alpha = self->growingTextView.text.length > 0 || actionMenuOpened ? 0 : 1;
} completion:nil];
[UIView animateWithDuration:kActionMenuComposerHeightAnimationDuration animations:^{
@ -442,16 +435,7 @@ const CGFloat kComposerContainerTrailingPadding = 12;
- (void)updateUIWithTextMessage:(NSString *)textMessage animated:(BOOL)animated
{
self.actionMenuOpened = NO;
if (RiotSettings.shared.enableVoiceMessages == NO) {
self.rightInputToolbarButton.alpha = textMessage.length ? 1.0f : 0.0f;
self.messageComposerContainerTrailingConstraint.constant = (textMessage.length ? self.frame.size.width - self.rightInputToolbarButton.frame.origin.x : 0.0f) + kComposerContainerTrailingPadding;
[self layoutIfNeeded];
return;
}
[UIView animateWithDuration:(animated ? 0.15f : 0.0f) animations:^{
self.rightInputToolbarButton.alpha = textMessage.length ? 1.0f : 0.0f;
self.voiceMessageToolbarView.alpha = textMessage.length ? 0.0f : 1.0;

View file

@ -84,6 +84,7 @@ class VoiceMessageAttachmentCacheManager {
workQueue.async {
// Run this in the work queue to preserve order
if let finalURL = self.finalURLs[identifier], let duration = self.durations[identifier], let samples = self.samples[identifier]?[numberOfSamples] {
MXLog.debug("[VoiceMessageAttachmentCacheManager] Finished task - using cached results")
let result = VoiceMessageAttachmentCacheManagerLoadResult(eventIdentifier: identifier, url: finalURL, duration: duration, samples: samples)
DispatchQueue.main.async {
completion(Result.success(result))
@ -109,22 +110,93 @@ class VoiceMessageAttachmentCacheManager {
completionCallbacks[callbackKey] = [CompletionWrapper(completion)]
}
let dispatchGroup = DispatchGroup()
if let finalURL = finalURLs[identifier], let duration = durations[identifier] {
sampleFileAtURL(finalURL, duration: duration, numberOfSamples: numberOfSamples, identifier: identifier)
return
}
func sampleFileAtURL(_ url: URL, duration: TimeInterval) {
let analyser = WaveformAnalyzer(audioAssetURL: url)
dispatchGroup.enter()
analyser?.samples(count: numberOfSamples, completionHandler: { samples in
MXLog.debug("[VoiceMessageAttachmentCacheManager] Finished sampling voice message")
dispatchGroup.leave()
DispatchQueue.main.async { // These don't behave accordingly if called from a background thread
if attachment.isEncrypted {
attachment.decrypt(toTempFile: { filePath in
self.workQueue.async {
self.convertFileAtPath(filePath, numberOfSamples: numberOfSamples, identifier: identifier)
}
}, failure: { error in
// A nil error in this case is a cancellation on the MXMediaLoader
if let error = error {
MXLog.error("Failed decrypting attachment with error: \(String(describing: error))")
self.invokeFailureCallbacksForIdentifier(identifier, error: VoiceMessageAttachmentCacheManagerError.decryptionError(error))
}
})
} else {
attachment.prepare({
self.workQueue.async {
self.convertFileAtPath(attachment.cacheFilePath, numberOfSamples: numberOfSamples, identifier: identifier)
}
}, failure: { error in
// A nil error in this case is a cancellation on the MXMediaLoader
if let error = error {
MXLog.error("Failed preparing attachment with error: \(String(describing: error))")
self.invokeFailureCallbacksForIdentifier(identifier, error: VoiceMessageAttachmentCacheManagerError.preparationError(error))
}
})
}
}
}
private func convertFileAtPath(_ path: String?, numberOfSamples: Int, identifier: String) {
guard let filePath = path else {
return
}
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let newURL = temporaryDirectoryURL.appendingPathComponent(ProcessInfo().globallyUniqueString).appendingPathExtension("m4a")
VoiceMessageAudioConverter.convertToMPEG4AAC(sourceURL: URL(fileURLWithPath: filePath), destinationURL: newURL) { result in
MXLog.debug("[VoiceMessageAttachmentCacheManager] Finished converting voice message")
self.workQueue.async {
switch result {
case .success:
self.finalURLs[identifier] = newURL
VoiceMessageAudioConverter.mediaDurationAt(newURL) { result in
self.workQueue.async {
MXLog.debug("[VoiceMessageAttachmentCacheManager] Finished retrieving media duration")
switch result {
case .success:
if let duration = try? result.get() {
self.durations[identifier] = duration
self.sampleFileAtURL(newURL, duration: duration, numberOfSamples: numberOfSamples, identifier: identifier)
} else {
MXLog.error("[VoiceMessageAttachmentCacheManager] Failed retrieving media duration")
}
case .failure(let error):
MXLog.error("[VoiceMessageAttachmentCacheManager] Failed retrieving audio duration with error: \(error)")
}
}
}
case .failure(let error):
MXLog.error("[VoiceMessageAttachmentCacheManager] Failed decoding audio message with error: \(error)")
self.invokeFailureCallbacksForIdentifier(identifier, error: VoiceMessageAttachmentCacheManagerError.conversionError(error))
}
}
}
}
private func sampleFileAtURL(_ url: URL, duration: TimeInterval, numberOfSamples: Int, identifier: String) {
let analyser = WaveformAnalyzer(audioAssetURL: url)
analyser?.samples(count: numberOfSamples, completionHandler: { samples in
self.workQueue.async {
guard let samples = samples else {
MXLog.debug("[VoiceMessageAttachmentCacheManager] Failed sampling voice message")
self.invokeFailureCallbacksForIdentifier(identifier, error: VoiceMessageAttachmentCacheManagerError.samplingError)
return
}
MXLog.debug("[VoiceMessageAttachmentCacheManager] Finished sampling voice message")
if var existingSamples = self.samples[identifier] {
existingSamples[numberOfSamples] = samples
self.samples[identifier] = existingSamples
@ -133,86 +205,8 @@ class VoiceMessageAttachmentCacheManager {
}
self.invokeSuccessCallbacksForIdentifier(identifier, url: url, duration: duration, samples: samples)
})
}
if let finalURL = finalURLs[identifier], let duration = durations[identifier] {
sampleFileAtURL(finalURL, duration: duration)
dispatchGroup.wait()
MXLog.debug("[VoiceMessageAttachmentCacheManager] Finished task")
return
}
func convertFileAtPath(_ path: String?) {
guard let filePath = path else {
return
}
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let newURL = temporaryDirectoryURL.appendingPathComponent(ProcessInfo().globallyUniqueString).appendingPathExtension("m4a")
dispatchGroup.enter()
VoiceMessageAudioConverter.convertToMPEG4AAC(sourceURL: URL(fileURLWithPath: filePath), destinationURL: newURL) { result in
switch result {
case .success:
self.finalURLs[identifier] = newURL
VoiceMessageAudioConverter.mediaDurationAt(newURL) { result in
MXLog.debug("[VoiceMessageAttachmentCacheManager] Finished converting voice message")
switch result {
case .success:
if let duration = try? result.get() {
self.durations[identifier] = duration
sampleFileAtURL(newURL, duration: duration)
} else {
MXLog.error("[VoiceMessageAttachmentCacheManager] enqueueLoadAttachment: Failed to retrieve media duration")
}
case .failure(let error):
MXLog.error("[VoiceMessageAttachmentCacheManager] enqueueLoadAttachment: failed getting audio duration with: \(error)")
}
dispatchGroup.leave()
}
case .failure(let error):
self.invokeFailureCallbacksForIdentifier(identifier, error: VoiceMessageAttachmentCacheManagerError.conversionError(error))
MXLog.error("[VoiceMessageAttachmentCacheManager] enqueueLoadAttachment: failed decoding audio message with: \(error)")
dispatchGroup.leave()
}
}
}
dispatchGroup.enter()
DispatchQueue.main.async { // These don't behave accordingly if called from a background thread
if attachment.isEncrypted {
attachment.decrypt(toTempFile: { filePath in
convertFileAtPath(filePath)
dispatchGroup.leave()
}, failure: { error in
// A nil error in this case is a cancellation on the MXMediaLoader
if let error = error {
MXLog.error("Failed decrypting attachment with error: \(String(describing: error))")
self.invokeFailureCallbacksForIdentifier(identifier, error: VoiceMessageAttachmentCacheManagerError.decryptionError(error))
}
dispatchGroup.leave()
})
} else {
attachment.prepare({
convertFileAtPath(attachment.cacheFilePath)
dispatchGroup.leave()
}, failure: { error in
// A nil error in this case is a cancellation on the MXMediaLoader
if let error = error {
MXLog.error("Failed preparing attachment with error: \(String(describing: error))")
self.invokeFailureCallbacksForIdentifier(identifier, error: VoiceMessageAttachmentCacheManagerError.preparationError(error))
}
dispatchGroup.leave()
})
}
}
dispatchGroup.wait()
MXLog.debug("[VoiceMessageAttachmentCacheManager] Finished task")
})
}
private func invokeSuccessCallbacksForIdentifier(_ identifier: String, url: URL, duration: TimeInterval, samples: [Float]) {
@ -232,6 +226,8 @@ class VoiceMessageAttachmentCacheManager {
}
self.completionCallbacks[callbackKey] = nil
MXLog.debug("[VoiceMessageAttachmentCacheManager] Successfully finished task")
}
private func invokeFailureCallbacksForIdentifier(_ identifier: String, error: Error) {
@ -249,5 +245,7 @@ class VoiceMessageAttachmentCacheManager {
}
self.completionCallbacks[callbackKey] = nil
MXLog.debug("[VoiceMessageAttachmentCacheManager] Failed task with error: \(error)")
}
}

View file

@ -24,12 +24,12 @@ enum VoiceMessageAudioConverterError: Error {
struct VoiceMessageAudioConverter {
static func convertToOpusOgg(sourceURL: URL, destinationURL: URL, completion: @escaping (Result<Void, VoiceMessageAudioConverterError>) -> Void) {
let command = "-hide_banner -y -i \"\(sourceURL.path)\" -c:a libopus \"\(destinationURL.path)\""
let command = "-hide_banner -y -i \"\(sourceURL.path)\" -c:a libopus -b:a 24k \"\(destinationURL.path)\""
executeCommand(command, completion: completion)
}
static func convertToMPEG4AAC(sourceURL: URL, destinationURL: URL, completion: @escaping (Result<Void, VoiceMessageAudioConverterError>) -> Void) {
let command = "-hide_banner -y -i \"\(sourceURL.path)\" -c:a aac_at -b:a 192k \"\(destinationURL.path)\""
let command = "-hide_banner -y -i \"\(sourceURL.path)\" -c:a aac_at \"\(destinationURL.path)\""
executeCommand(command, completion: completion)
}

View file

@ -45,6 +45,7 @@ class VoiceMessageAudioPlayer: NSObject {
private let delegateContainer = DelegateContainer()
private(set) var url: URL?
private(set) var displayName: String?
var isPlaying: Bool {
guard let audioPlayer = audioPlayer else {
@ -68,12 +69,13 @@ class VoiceMessageAudioPlayer: NSObject {
removeObservers()
}
func loadContentFromURL(_ url: URL) {
func loadContentFromURL(_ url: URL, displayName: String? = nil) {
if self.url == url {
return
}
self.url = url
self.displayName = displayName
removeObservers()

View file

@ -51,7 +51,8 @@ class VoiceMessageAudioRecorder: NSObject, AVAudioRecorderDelegate {
func recordWithOutputURL(_ url: URL) {
let settings = [AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 12000,
AVSampleRateKey: 48000,
AVEncoderBitRateKey: 128000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue]

View file

@ -29,12 +29,13 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
static let maximumAudioRecordingDuration: TimeInterval = 120.0
static let maximumAudioRecordingLengthReachedThreshold: TimeInterval = 10.0
static let elapsedTimeFormat = "m:ss"
static let fileNameFormat = "'Voice message - 'MM.dd.yyyy HH.mm.ss"
static let minimumRecordingDuration = 1.0
}
private let themeService: ThemeService
private let mediaServiceProvider: VoiceMessageMediaServiceProvider
private let temporaryFileURL: URL
private var temporaryFileURL: URL!
private let _voiceMessageToolbarView: VoiceMessageToolbarView
private var displayLink: CADisplayLink!
@ -48,12 +49,18 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
private var isInLockedMode: Bool = false
private var notifiedRemainingTime = false
private static let timeFormatter: DateFormatter = {
private static let elapsedTimeFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = Constants.elapsedTimeFormat
return dateFormatter
}()
private static let fileNameDateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = Constants.fileNameFormat
return dateFormatter
}()
@objc public weak var delegate: VoiceMessageControllerDelegate?
@objc public var isRecordingAudio: Bool {
@ -68,9 +75,6 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
self.themeService = themeService
self.mediaServiceProvider = mediaServiceProvider
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(ProcessInfo().globallyUniqueString).appendingPathExtension("m4a")
_voiceMessageToolbarView = VoiceMessageToolbarView.loadFromNib()
super.init()
@ -84,6 +88,8 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
NotificationCenter.default.addObserver(self, selector: #selector(updateTheme), name: .themeServiceDidChangeTheme, object: nil)
updateTheme()
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillResignActive), name: UIApplication.willResignActiveNotification, object: nil)
updateUI()
}
@ -107,6 +113,11 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
audioRecorder = mediaServiceProvider.audioRecorder()
audioRecorder?.registerDelegate(self)
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let fileName = VoiceMessageController.fileNameDateFormatter.string(from: Date())
temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(fileName).appendingPathExtension("m4a")
audioRecorder?.recordWithOutputURL(temporaryFileURL)
}
@ -260,7 +271,7 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
})
dispatchGroup.enter()
let destinationURL = sourceURL.deletingPathExtension().appendingPathExtension("opus")
let destinationURL = sourceURL.deletingPathExtension().appendingPathExtension("ogg")
VoiceMessageAudioConverter.convertToOpusOgg(sourceURL: sourceURL, destinationURL: destinationURL) { result in
switch result {
case .success:
@ -303,6 +314,10 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
_voiceMessageToolbarView.update(theme: themeService.theme)
}
@objc private func applicationWillResignActive() {
finishRecording()
}
@objc private func handleDisplayLinkTick() {
updateUI()
}
@ -342,7 +357,7 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
var details = VoiceMessageToolbarViewDetails()
details.state = (isRecording ? (isInLockedMode ? .lockedModeRecord : .record) : (isInLockedMode ? .lockedModePlayback : .idle))
details.elapsedTime = VoiceMessageController.timeFormatter.string(from: Date(timeIntervalSinceReferenceDate: currentTime))
details.elapsedTime = VoiceMessageController.elapsedTimeFormatter.string(from: Date(timeIntervalSinceReferenceDate: currentTime))
details.audioSamples = audioSamples
if isRecording {
@ -391,7 +406,7 @@ public class VoiceMessageController: NSObject, VoiceMessageToolbarViewDelegate,
var details = VoiceMessageToolbarViewDetails()
details.state = (audioRecorder?.isRecording ?? false ? (isInLockedMode ? .lockedModeRecord : .record) : (isInLockedMode ? .lockedModePlayback : .idle))
details.elapsedTime = VoiceMessageController.timeFormatter.string(from: Date(timeIntervalSinceReferenceDate: (audioPlayer.isPlaying ? audioPlayer.currentTime : audioPlayer.duration)))
details.elapsedTime = VoiceMessageController.elapsedTimeFormatter.string(from: Date(timeIntervalSinceReferenceDate: (audioPlayer.isPlaying ? audioPlayer.currentTime : audioPlayer.duration)))
details.audioSamples = audioSamples
details.isPlaying = audioPlayer.isPlaying
details.progress = (audioPlayer.isPlaying ? (audioPlayer.duration > 0.0 ? audioPlayer.currentTime / audioPlayer.duration : 0.0) : 0.0)

View file

@ -15,20 +15,84 @@
//
import Foundation
import MediaPlayer
@objc public class VoiceMessageMediaServiceProvider: NSObject, VoiceMessageAudioPlayerDelegate, VoiceMessageAudioRecorderDelegate {
private enum Constants {
static let roomAvatarImageSize: CGSize = CGSize(width: 600, height: 600)
static let roomAvatarFontSize: CGFloat = 40.0
static let roomAvatarMimetype: String = "image/jpeg"
}
private var roomAvatarLoader: MXMediaLoader?
private let audioPlayers: NSMapTable<NSString, VoiceMessageAudioPlayer>
private let audioRecorders: NSHashTable<VoiceMessageAudioRecorder>
// Retain currently playing audio player so it doesn't stop playing on timeline cell reusage
private var displayLink: CADisplayLink!
// Retain currently playing audio player so it doesn't stop playing on timeline cell reuse
private var currentlyPlayingAudioPlayer: VoiceMessageAudioPlayer?
@objc public static let sharedProvider = VoiceMessageMediaServiceProvider()
private var roomAvatar: UIImage?
@objc public var currentRoomSummary: MXRoomSummary? {
didSet {
// set avatar placeholder for now
roomAvatar = AvatarGenerator.generateAvatar(forMatrixItem: currentRoomSummary?.roomId,
withDisplayName: currentRoomSummary?.displayname,
size: Constants.roomAvatarImageSize.width,
andFontSize: Constants.roomAvatarFontSize)
guard let avatarUrl = currentRoomSummary?.avatar else {
return
}
if let cachePath = MXMediaManager.thumbnailCachePath(forMatrixContentURI: avatarUrl,
andType: Constants.roomAvatarMimetype,
inFolder: currentRoomSummary?.roomId,
toFitViewSize: Constants.roomAvatarImageSize,
with: MXThumbnailingMethodCrop),
FileManager.default.fileExists(atPath: cachePath) {
// found in the cache, load it
roomAvatar = MXMediaManager.loadThroughCache(withFilePath: cachePath)
} else {
// cancel previous loader first
roomAvatarLoader?.cancel()
roomAvatarLoader = nil
guard let mediaManager = currentRoomSummary?.mxSession.mediaManager else {
return
}
// not found in the cache, download it
roomAvatarLoader = mediaManager.downloadThumbnail(fromMatrixContentURI: avatarUrl,
withType: Constants.roomAvatarMimetype,
inFolder: currentRoomSummary?.roomId,
toFitViewSize: Constants.roomAvatarImageSize,
with: MXThumbnailingMethodCrop,
success: { filePath in
if let filePath = filePath {
self.roomAvatar = MXMediaManager.loadThroughCache(withFilePath: filePath)
}
self.roomAvatarLoader = nil
}, failure: { error in
self.roomAvatarLoader = nil
})
}
}
}
private override init() {
audioPlayers = NSMapTable<NSString, VoiceMessageAudioPlayer>(valueOptions: .weakMemory)
audioRecorders = NSHashTable<VoiceMessageAudioRecorder>(options: .weakMemory)
super.init()
displayLink = CADisplayLink(target: WeakTarget(self, selector: #selector(handleDisplayLinkTick)), selector: WeakTarget.triggerSelector)
displayLink.isPaused = true
displayLink.add(to: .current, forMode: .common)
}
@objc func audioPlayerForIdentifier(_ identifier: String) -> VoiceMessageAudioPlayer {
@ -57,12 +121,21 @@ import Foundation
func audioPlayerDidStartPlaying(_ audioPlayer: VoiceMessageAudioPlayer) {
currentlyPlayingAudioPlayer = audioPlayer
setUpRemoteCommandCenter()
stopAllServicesExcept(audioPlayer)
}
func audioPlayerDidStopPlaying(_ audioPlayer: VoiceMessageAudioPlayer) {
if currentlyPlayingAudioPlayer == audioPlayer {
currentlyPlayingAudioPlayer = nil
tearDownRemoteCommandCenter()
}
}
func audioPlayerDidFinishPlaying(_ audioPlayer: VoiceMessageAudioPlayer) {
if currentlyPlayingAudioPlayer == audioPlayer {
currentlyPlayingAudioPlayer = nil
tearDownRemoteCommandCenter()
}
}
@ -96,4 +169,90 @@ import Foundation
audioPlayer.unloadContent()
}
}
@objc private func handleDisplayLinkTick() {
updateNowPlayingInfoCenter()
}
private func setUpRemoteCommandCenter() {
displayLink.isPaused = false
UIApplication.shared.beginReceivingRemoteControlEvents()
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.playCommand.removeTarget(nil)
commandCenter.playCommand.addTarget { [weak self] event in
guard let audioPlayer = self?.currentlyPlayingAudioPlayer else {
return MPRemoteCommandHandlerStatus.commandFailed
}
audioPlayer.play()
return MPRemoteCommandHandlerStatus.success
}
commandCenter.pauseCommand.isEnabled = true
commandCenter.pauseCommand.removeTarget(nil)
commandCenter.pauseCommand.addTarget { [weak self] event in
guard let audioPlayer = self?.currentlyPlayingAudioPlayer else {
return MPRemoteCommandHandlerStatus.commandFailed
}
audioPlayer.pause()
return MPRemoteCommandHandlerStatus.success
}
commandCenter.skipForwardCommand.isEnabled = true
commandCenter.skipForwardCommand.removeTarget(nil)
commandCenter.skipForwardCommand.addTarget { [weak self] event in
guard let audioPlayer = self?.currentlyPlayingAudioPlayer, let skipEvent = event as? MPSkipIntervalCommandEvent else {
return MPRemoteCommandHandlerStatus.commandFailed
}
audioPlayer.seekToTime(audioPlayer.currentTime + skipEvent.interval)
return MPRemoteCommandHandlerStatus.success
}
commandCenter.skipBackwardCommand.isEnabled = true
commandCenter.skipBackwardCommand.removeTarget(nil)
commandCenter.skipBackwardCommand.addTarget { [weak self] event in
guard let audioPlayer = self?.currentlyPlayingAudioPlayer, let skipEvent = event as? MPSkipIntervalCommandEvent else {
return MPRemoteCommandHandlerStatus.commandFailed
}
audioPlayer.seekToTime(audioPlayer.currentTime - skipEvent.interval)
return MPRemoteCommandHandlerStatus.success
}
}
private func tearDownRemoteCommandCenter() {
displayLink.isPaused = true
UIApplication.shared.endReceivingRemoteControlEvents()
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
nowPlayingInfoCenter.nowPlayingInfo = nil
}
private func updateNowPlayingInfoCenter() {
guard let audioPlayer = currentlyPlayingAudioPlayer else {
return
}
let artwork = MPMediaItemArtwork(boundsSize: Constants.roomAvatarImageSize) { [weak self] size in
return self?.roomAvatar ?? UIImage()
}
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
nowPlayingInfoCenter.nowPlayingInfo = [MPMediaItemPropertyTitle: audioPlayer.displayName ?? VectorL10n.voiceMessageLockScreenPlaceholder,
MPMediaItemPropertyArtist: currentRoomSummary?.displayname as Any,
MPMediaItemPropertyArtwork: artwork,
MPMediaItemPropertyPlaybackDuration: audioPlayer.duration as Any,
MPNowPlayingInfoPropertyElapsedPlaybackTime: audioPlayer.currentTime as Any]
}
}

View file

@ -56,8 +56,7 @@ class VoiceMessagePlaybackController: VoiceMessageAudioPlayerDelegate, VoiceMess
let playbackView: VoiceMessagePlaybackView
init(mediaServiceProvider: VoiceMessageMediaServiceProvider,
cacheManager: VoiceMessageAttachmentCacheManager) {
init(mediaServiceProvider: VoiceMessageMediaServiceProvider, cacheManager: VoiceMessageAttachmentCacheManager) {
self.mediaServiceProvider = mediaServiceProvider
self.cacheManager = cacheManager
@ -93,7 +92,7 @@ class VoiceMessagePlaybackController: VoiceMessageAudioPlayerDelegate, VoiceMess
audioPlayer.play()
}
} else if let url = urlToLoad {
audioPlayer.loadContentFromURL(url)
audioPlayer.loadContentFromURL(url, displayName: attachment?.originalFileName)
audioPlayer.play()
}
}
@ -153,6 +152,7 @@ class VoiceMessagePlaybackController: VoiceMessageAudioPlayerDelegate, VoiceMess
details.progress = (audioPlayer.duration > 0.0 ? audioPlayer.currentTime / audioPlayer.duration : 0.0)
}
}
details.loading = self.loading
playbackView.configureWithDetails(details)

View file

@ -23,7 +23,7 @@
<rect key="frame" x="0.0" y="0.0" width="544" height="72"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8fP-9K-WTa">
<rect key="frame" x="492" y="-90" width="44" height="152"/>
<rect key="frame" x="492" y="-80" width="44" height="152"/>
<subviews>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kvc-OZ-peC">
<rect key="frame" x="0.0" y="0.0" width="44" height="152"/>
@ -120,15 +120,15 @@
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7OQ-1F-5qT">
<rect key="frame" x="488" y="10" width="52" height="52"/>
<rect key="frame" x="478" y="0.0" width="72" height="72"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="BDj-Sw-VQ5">
<rect key="frame" x="0.0" y="0.0" width="52" height="52"/>
<rect key="frame" x="0.0" y="0.0" width="72" height="72"/>
<state key="normal" image="voice_message_record_button_default"/>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rel-Fo-ROL">
<rect key="frame" x="0.0" y="0.0" width="52" height="52"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<rect key="frame" x="0.0" y="0.0" width="72" height="72"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<state key="normal" image="voice_message_record_button_recording"/>
</button>
</subviews>
@ -136,14 +136,14 @@
<constraints>
<constraint firstItem="BDj-Sw-VQ5" firstAttribute="leading" secondItem="7OQ-1F-5qT" secondAttribute="leading" id="2Xv-EI-etf"/>
<constraint firstAttribute="trailing" secondItem="BDj-Sw-VQ5" secondAttribute="trailing" id="2ZQ-3v-0W7"/>
<constraint firstAttribute="height" constant="52" id="4XA-Gb-5NO"/>
<constraint firstAttribute="height" constant="72" id="4XA-Gb-5NO"/>
<constraint firstAttribute="trailing" secondItem="BDj-Sw-VQ5" secondAttribute="trailing" id="Dki-cT-7xX"/>
<constraint firstAttribute="bottom" secondItem="BDj-Sw-VQ5" secondAttribute="bottom" id="fzv-iX-c1Y"/>
<constraint firstItem="BDj-Sw-VQ5" firstAttribute="top" secondItem="7OQ-1F-5qT" secondAttribute="top" id="mNa-EU-ZKQ"/>
<constraint firstAttribute="bottom" secondItem="BDj-Sw-VQ5" secondAttribute="bottom" id="phX-gD-B2H"/>
<constraint firstItem="BDj-Sw-VQ5" firstAttribute="top" secondItem="7OQ-1F-5qT" secondAttribute="top" id="pv8-li-wP8"/>
<constraint firstItem="BDj-Sw-VQ5" firstAttribute="leading" secondItem="7OQ-1F-5qT" secondAttribute="leading" id="ynJ-4x-1jv"/>
<constraint firstAttribute="width" constant="52" id="zPb-1B-JyA"/>
<constraint firstAttribute="width" constant="72" id="zPb-1B-JyA"/>
</constraints>
</view>
</subviews>
@ -152,7 +152,7 @@
<constraint firstItem="dyu-ha-046" firstAttribute="leading" secondItem="XRB-CY-ijK" secondAttribute="leading" id="BoC-Ut-chI"/>
<constraint firstAttribute="bottom" secondItem="dyu-ha-046" secondAttribute="bottom" id="U4h-FY-D3W"/>
<constraint firstItem="8fP-9K-WTa" firstAttribute="bottom" secondItem="7OQ-1F-5qT" secondAttribute="bottom" id="X4v-7T-LgP"/>
<constraint firstAttribute="trailing" secondItem="7OQ-1F-5qT" secondAttribute="trailing" constant="4" id="giC-4J-EUL"/>
<constraint firstAttribute="trailing" secondItem="7OQ-1F-5qT" secondAttribute="trailing" constant="-6" id="giC-4J-EUL"/>
<constraint firstItem="dyu-ha-046" firstAttribute="top" secondItem="XRB-CY-ijK" secondAttribute="top" id="ra2-Me-23b"/>
<constraint firstItem="8fP-9K-WTa" firstAttribute="centerX" secondItem="7OQ-1F-5qT" secondAttribute="centerX" id="xL5-g3-aHb"/>
<constraint firstAttribute="trailing" secondItem="dyu-ha-046" secondAttribute="trailing" id="xME-WZ-OMX"/>
@ -280,7 +280,7 @@
<image name="voice_message_lock_icon_locked" width="24" height="24"/>
<image name="voice_message_lock_icon_unlocked" width="16" height="16"/>
<image name="voice_message_record_button_default" width="22" height="26.5"/>
<image name="voice_message_record_button_recording" width="52" height="52"/>
<image name="voice_message_record_button_recording" width="72" height="72"/>
<image name="voice_message_record_icon" width="10" height="10"/>
</resources>
</document>

View file

@ -89,6 +89,7 @@ enum
enum
{
NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX = 0,
NOTIFICATION_SETTINGS_SYSTEM_SETTINGS,
NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT,
NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX,
NOTIFICATION_SETTINGS_PIN_MISSED_NOTIFICATIONS_INDEX,
@ -143,7 +144,6 @@ enum
enum
{
LABS_ENABLE_RINGING_FOR_GROUP_CALLS_INDEX = 0,
LABS_ENABLE_VOICE_MESSAGES = 1
};
enum
@ -235,6 +235,11 @@ TableViewSectionsDelegate>
*/
@property (nonatomic) BOOL newPhoneEditingEnabled;
/**
The current `UNUserNotificationCenter` notification settings for the app.
*/
@property (nonatomic) UNNotificationSettings *systemNotificationSettings;
@property (nonatomic, weak) DeactivateAccountViewController *deactivateAccountViewController;
@property (nonatomic, strong) SignOutAlertPresenter *signOutAlertPresenter;
@property (nonatomic, weak) UIButton *signOutButton;
@ -351,6 +356,7 @@ TableViewSectionsDelegate>
Section *sectionNotificationSettings = [Section sectionWithTag:SECTION_TAG_NOTIFICATIONS];
[sectionNotificationSettings addRowWithTag:NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX];
[sectionNotificationSettings addRowWithTag:NOTIFICATION_SETTINGS_SYSTEM_SETTINGS];
if (RiotSettings.shared.settingsScreenShowNotificationDecodedContentOption)
{
[sectionNotificationSettings addRowWithTag:NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT];
@ -488,7 +494,6 @@ TableViewSectionsDelegate>
{
Section *sectionLabs = [Section sectionWithTag:SECTION_TAG_LABS];
[sectionLabs addRowWithTag:LABS_ENABLE_RINGING_FOR_GROUP_CALLS_INDEX];
[sectionLabs addRowWithTag:LABS_ENABLE_VOICE_MESSAGES];
sectionLabs.headerTitle = NSLocalizedStringFromTable(@"settings_labs", @"Vector", nil);
if (sectionLabs.hasAnyRows)
{
@ -1231,6 +1236,24 @@ TableViewSectionsDelegate>
[self editNewPhoneNumberTextField];
keepNewPhoneNumberEditing = NO;
}
// Update notification access
[self refreshSystemNotificationSettings];
}
- (void)refreshSystemNotificationSettings
{
MXWeakify(self);
// Get the system notification settings to check authorization status and configuration.
[UNUserNotificationCenter.currentNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
dispatch_async(dispatch_get_main_queue(), ^{
MXStrongifyAndReturnIfNil(self);
self.systemNotificationSettings = settings;
[self.tableView reloadData];
});
}];
}
- (void)formatNewPhoneNumber
@ -1791,13 +1814,38 @@ TableViewSectionsDelegate>
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_enable_push_notif", @"Vector", nil);
labelAndSwitchCell.mxkSwitch.on = account.pushNotificationServiceIsActive;
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
labelAndSwitchCell.mxkSwitch.enabled = YES;
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(togglePushNotifications:) forControlEvents:UIControlEventTouchUpInside];
BOOL isPushEnabled = account.pushNotificationServiceIsActive;
// Even if push is enabled for the account, the user may have turned off notifications in system settings
if (isPushEnabled && self.systemNotificationSettings)
{
isPushEnabled = self.systemNotificationSettings.authorizationStatus == UNAuthorizationStatusAuthorized;
}
labelAndSwitchCell.mxkSwitch.on = isPushEnabled;
cell = labelAndSwitchCell;
}
else if (row == NOTIFICATION_SETTINGS_SYSTEM_SETTINGS)
{
cell = [tableView dequeueReusableCellWithIdentifier:kSettingsViewControllerPhoneBookCountryCellId];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kSettingsViewControllerPhoneBookCountryCellId];
}
cell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
cell.textLabel.text = NSLocalizedStringFromTable(@"settings_device_notifications", @"Vector", nil);
cell.detailTextLabel.text = @"";
[cell vc_setAccessoryDisclosureIndicatorWithCurrentTheme];
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
}
else if (row == NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT)
{
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
@ -2265,17 +2313,6 @@ TableViewSectionsDelegate>
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableRingingForGroupCalls:) forControlEvents:UIControlEventValueChanged];
cell = labelAndSwitchCell;
} else if (row == LABS_ENABLE_VOICE_MESSAGES)
{
MXKTableViewCellWithLabelAndSwitch *labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_labs_voice_messages", @"Vector", nil);
labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.enableVoiceMessages;
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleEnableVoiceMessages:) forControlEvents:UIControlEventValueChanged];
cell = labelAndSwitchCell;
}
}
@ -2501,6 +2538,10 @@ TableViewSectionsDelegate>
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
[self showInviteFriendsFromSourceView:selectedCell];
}
else if (section == SECTION_TAG_NOTIFICATIONS && row == NOTIFICATION_SETTINGS_SYSTEM_SETTINGS)
{
[self openSystemSettingsApp];
}
else if (section == SECTION_TAG_DISCOVERY)
{
[self.settingsDiscoveryTableViewSection selectRow:row];
@ -2804,20 +2845,20 @@ TableViewSectionsDelegate>
- (void)togglePushNotifications:(UISwitch *)sender
{
// Check first whether the user allow notification from device settings
UIUserNotificationType currentUserNotificationTypes = UIApplication.sharedApplication.currentUserNotificationSettings.types;
if (currentUserNotificationTypes == UIUserNotificationTypeNone)
// Check first whether the user allow notification from system settings
if (self.systemNotificationSettings.authorizationStatus == UNAuthorizationStatusDenied)
{
[currentAlert dismissViewControllerAnimated:NO completion:nil];
__weak typeof(self) weakSelf = self;
NSString *appDisplayName = [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"];
currentAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:NSLocalizedStringFromTable(@"settings_on_denied_notification", @"Vector", nil), appDisplayName] message:nil preferredStyle:UIAlertControllerStyleAlert];
NSString *title = NSLocalizedStringFromTable(@"settings_notifications_disabled_alert_title", @"Vector", nil);
NSString *message = NSLocalizedStringFromTable(@"settings_notifications_disabled_alert_message", @"Vector", nil);
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"]
style:UIAlertActionStyleDefault
currentAlert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (weakSelf)
@ -2828,6 +2869,21 @@ TableViewSectionsDelegate>
}]];
UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"settings"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self openSystemSettingsApp];
}
}];
[currentAlert addAction:settingsAction];
currentAlert.preferredAction = settingsAction;
[currentAlert mxk_setAccessibilityIdentifier: @"SettingsVCPushNotificationsAlert"];
[self presentViewController:currentAlert animated:YES completion:nil];
@ -2871,6 +2927,12 @@ TableViewSectionsDelegate>
}
}
- (void)openSystemSettingsApp
{
NSURL *settingsAppURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:settingsAppURL options:@{} completionHandler:nil];
}
- (void)toggleCallKit:(UISwitch *)sender
{
[MXKAppSettings standardAppSettings].enableCallKit = sender.isOn;
@ -2959,11 +3021,6 @@ TableViewSectionsDelegate>
RiotSettings.shared.enableRingingForGroupCalls = sender.isOn;
}
- (void)toggleEnableVoiceMessages:(UISwitch *)sender
{
RiotSettings.shared.enableVoiceMessages = sender.isOn;
}
- (void)togglePinRoomsWithMissedNotif:(UISwitch *)sender
{
RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome = sender.isOn;

30
setup_project.sh Executable file
View file

@ -0,0 +1,30 @@
#!/bin/bash
# Use this script to setup the Xcode project
# Remove existing project file if any
rm -r Riot.xcodeproj
# Create the xcodeproj with all project source files
xcodegen
# Use appropriated dependencies
# Check if Podfile changed in unstaged
git diff --exit-code --quiet --name-only Podfile
PODFILE_HAS_CHANGED_UNSTAGED=$?
# Check if Podfile changed in staged
git diff --staged --exit-code --quiet --name-only Podfile
PODFILE_HAS_CHANGED_STAGED=$?
# If Podfile has changed locally do not modify it
# otherwise use the appropriated dependencies according to the current branch
if [[ "$PODFILE_HAS_CHANGED_UNSTAGED" -eq 1 || "$PODFILE_HAS_CHANGED_STAGED" -eq 1 ]]; then
echo "Podfile has been changed locally do not modify it"
else
echo "Podfile has not been changed locally, use appropriated dependencies according to the current branch"
bundle exec fastlane point_dependencies_to_same_feature
fi
# Create the xcworkspace with all project dependencies
pod install