Merge pull request #4454 from vector-im/release/1.4.2/release
Release 1.4.2
@@ -36,6 +36,10 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gems-
|
||||
|
||||
# Make sure we use the latest version of MatrixKit
|
||||
- name: Reset MatrixKit pod
|
||||
run: rm -rf Pods/MatrixKit
|
||||
|
||||
# Common setup
|
||||
# Note: GH actions do not support yaml anchor yet. We need to duplicate this for every job
|
||||
- name: Bundle install
|
||||
@@ -72,6 +76,10 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gems-
|
||||
|
||||
# Make sure we use the latest version of MatrixKit
|
||||
- name: Reset MatrixKit pod
|
||||
run: rm -rf Pods/MatrixKit
|
||||
|
||||
# Common setup
|
||||
# Note: GH actions do not support yaml anchor yet. We need to duplicate this for every job
|
||||
- name: Bundle install
|
||||
|
||||
@@ -18,6 +18,7 @@ DerivedData
|
||||
*.xcuserstate
|
||||
out/
|
||||
.vscode/
|
||||
vendor/
|
||||
|
||||
# CocoaPods
|
||||
#
|
||||
|
||||
@@ -1,3 +1,72 @@
|
||||
Changes in 1.4.2 (2021-06-21)
|
||||
=================================================
|
||||
|
||||
✨ Features
|
||||
* Add left panel (#4398).
|
||||
|
||||
🙌 Improvements
|
||||
* MXRoomSummary: Adapt room summary changes on MatrixSDK (#4360).
|
||||
* EncryptionKeyManager: Create keys for room last message data type.
|
||||
* Integrated FLEX for debug builds.
|
||||
* VoIP: Add dial pad for PSTN capable servers to menu on homescreen.
|
||||
* VoIP: Replace call bar with PiP tiles for every type of calls.
|
||||
* Security settings: Display the cross-signing section (#4430).
|
||||
* Security settings: The Secure backup section has been updated to match element-web UX (#4430).
|
||||
* Wording: Replace Recovery Passphrase and Recovery Key by Security Phrase and Security Key (#4268).
|
||||
* Room directory: Join room by alias or id (#4429).
|
||||
* Room lists: Avoid app freezes by building them on a separated thread (#3777).
|
||||
|
||||
🐛 Bugfix
|
||||
* StartChatViewController: Add more helpful message when trying to start DM with a user that does not exist (#224).
|
||||
* RoomDirectCallStatusBubbleCell: Fix crash when entering a DM after a call is hung-up/rejected while being answered (#4403).
|
||||
* ContactsDataSource: iPad Crashes when you select a contact in search and then collapse a section or clear the query text (#4414).
|
||||
* SettingsViewController: Fix "auto" theme message to clarify that it matches the system theme on iOS 13+ (#2860).
|
||||
* VoIP: Handle application inactive state too for VoIP pushes (#4269).
|
||||
* VoIP: Do not terminate the app if protected data not available (#4419).
|
||||
* KeyVerification: Listen for request state changes and show QR reader option when it's ready.
|
||||
* NSE: Recreate background sync service if credentials changed (#3695).
|
||||
* HomeViewController: Don't clip the home view when searching for rooms on iPhone 12 Pro Max (#4450).
|
||||
|
||||
⚠️ API Changes
|
||||
*
|
||||
|
||||
🗣 Translations
|
||||
*
|
||||
|
||||
🧱 Build
|
||||
* GH Actions: Make sure we use the latest version of MatrixKit.
|
||||
|
||||
Others
|
||||
*
|
||||
|
||||
Improvements:
|
||||
* Upgrade MatrixKit version ([v0.15.1](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.15.1)).
|
||||
|
||||
Changes in 1.4.1 (2021-06-08)
|
||||
=================================================
|
||||
|
||||
✨ Features
|
||||
*
|
||||
|
||||
🙌 Improvements
|
||||
*
|
||||
|
||||
🐛 Bugfix
|
||||
* SettingsViewController: Fix crash when changing the app language (#4377).
|
||||
* UserSessionsService: Fix room lists lost after a reset cache (#4395).
|
||||
|
||||
⚠️ API Changes
|
||||
*
|
||||
|
||||
🗣 Translations
|
||||
*
|
||||
|
||||
🧱 Build
|
||||
*
|
||||
|
||||
Others
|
||||
*
|
||||
|
||||
Changes in 1.4.0 (2021-06-03)
|
||||
=================================================
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ APPLICATION_GROUP_IDENTIFIER = group.im.vector
|
||||
APPLICATION_SCHEME = element
|
||||
|
||||
// Version
|
||||
MARKETING_VERSION = 1.4.0
|
||||
CURRENT_PROJECT_VERSION = 1.4.0
|
||||
MARKETING_VERSION = 1.4.2
|
||||
CURRENT_PROJECT_VERSION = 1.4.2
|
||||
|
||||
|
||||
// Team
|
||||
|
||||
@@ -114,6 +114,8 @@ final class BuildSettings: NSObject {
|
||||
static let applicationCopyrightUrlString = "https://element.io/copyright"
|
||||
static let applicationPrivacyPolicyUrlString = "https://element.io/privacy"
|
||||
static let applicationTermsConditionsUrlString = "https://element.io/terms-of-service"
|
||||
static let applicationHelpUrlString =
|
||||
"https://element.io/help"
|
||||
|
||||
|
||||
// MARk: - Matrix permalinks
|
||||
@@ -200,6 +202,8 @@ final class BuildSettings: NSObject {
|
||||
|
||||
static let allowInviteExernalUsers: Bool = true
|
||||
|
||||
static let enableSideMenu: Bool = true
|
||||
|
||||
// MARK: - Feature Specifics
|
||||
|
||||
/// Not allowed pin codes. User won't be able to select one of the pin in the list.
|
||||
|
||||
@@ -12,7 +12,7 @@ To build Element iOS project you need:
|
||||
|
||||
### Install Ruby
|
||||
|
||||
Ruby is required for several build tools like CocoaPods, bundler and fastlane. Ruby is preinstalled on macOS, the system version is sufficient to build the porject tools, it's not required to install the latest version. If you want to install the lastest version of Ruby please check [official instructions](https://www.ruby-lang.org/en/documentation/installation/#homebrew).
|
||||
Ruby is required for several build tools like CocoaPods, bundler and fastlane. Ruby is preinstalled on macOS, the system version is sufficient to build the project tools, it's not required to install the latest version. If you want to install the lastest version of Ruby please check [official instructions](https://www.ruby-lang.org/en/documentation/installation/#homebrew).
|
||||
|
||||
If you do not want to grant the ruby package manager, [RubyGems](https://rubygems.org/), admin privileges and you prefer install gems into your user directory, you can read instructions from the CocoaPods [guide about sudo-less installation](https://guides.cocoapods.org/using/getting-started.html#sudo-less-installation).
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use_frameworks!
|
||||
# - `{ {kit spec hash} => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for each repo. Used by Fastfile during CI
|
||||
#
|
||||
# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it
|
||||
$matrixKitVersion = '= 0.15.0'
|
||||
$matrixKitVersion = '= 0.15.1'
|
||||
# $matrixKitVersion = :local
|
||||
# $matrixKitVersion = {'develop' => 'develop'}
|
||||
|
||||
@@ -68,6 +68,9 @@ abstract_target 'RiotPods' do
|
||||
pod 'ReadMoreTextView', '~> 3.0.1'
|
||||
pod 'SwiftBase32', '~> 0.9.0'
|
||||
pod 'SwiftJWT', '~> 3.6.200'
|
||||
pod 'SideMenu', '~> 6.5'
|
||||
|
||||
pod 'FLEX', '~> 4.4.1', :configurations => ['Debug']
|
||||
|
||||
target 'RiotTests' do
|
||||
inherit! :search_paths
|
||||
|
||||
@@ -221,7 +221,7 @@
|
||||
<!--Home View Controller-->
|
||||
<scene sceneID="SZi-Ac-WJp">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="HomeViewController" id="pBa-To-3YT" customClass="HomeViewController" sceneMemberID="viewController">
|
||||
<viewController storyboardIdentifier="HomeViewController" extendedLayoutIncludesOpaqueBars="YES" id="pBa-To-3YT" customClass="HomeViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="m3s-18-JgR"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="2lp-r9-RR5"/>
|
||||
@@ -581,7 +581,7 @@
|
||||
</scene>
|
||||
</scenes>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="Tfl-tq-LQp"/>
|
||||
<segue reference="mhb-l9-pM3"/>
|
||||
<segue reference="f5u-Y1-7nt"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
<resources>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "side_menu_action_icon_feedback.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_action_icon_feedback@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_action_icon_feedback@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 428 B |
|
After Width: | Height: | Size: 725 B |
|
After Width: | Height: | Size: 1023 B |
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "side_menu_action_icon_help.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_action_icon_help@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_action_icon_help@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 661 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "side_menu_action_icon_settings.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_action_icon_settings@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_action_icon_settings@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 517 B |
|
After Width: | Height: | Size: 917 B |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "side_menu_action_icon_share.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_action_icon_share@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_action_icon_share@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 380 B |
|
After Width: | Height: | Size: 533 B |
|
After Width: | Height: | Size: 732 B |
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "side_menu_icon.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_icon@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "side_menu_icon@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -235,3 +235,29 @@
|
||||
"room_creation_error_invite_user_by_email_without_identity_server" = "لَم يُضبَط خادِم هُويَّة لِذَلِكَ لَا يُمكِنُكَ إضافَة مُشَارِك بالبَريد الإلِكتُرونيّ.";
|
||||
"room_creation_invite_another_user" = "البَحث / الدَعوة عَن طَريق مُعَرِّف المُستَخدِم، الاِسم أو البَريد الإلِكتُرونيّ";
|
||||
"room_creation_wait_for_creation" = "يَجرِي إنشاء غُرفَة بِالفِعل. يُرجَى الاِنتِظار.";
|
||||
"room_participants_remove_third_party_invite_prompt_msg" = "هَل أنتَ مُتَأكِّدٌ أنَّكَ تٌريدُ إبطَالَ هَذِهِ الدَّعوَة؟";
|
||||
"room_participants_remove_prompt_msg" = "هَل أنتَ مُتَأكِّدٌ أنَّكَ تُريدُ إزالَة %@ مِن هَذِهِ المُحادَثَة؟";
|
||||
"room_participants_action_unban" = "رَفعُ الحَظْر";
|
||||
"room_participants_action_ban" = "الحَظْرُ مِن هَذِهِ الغُرفَة";
|
||||
"room_participants_action_remove" = "الإزالَةُ مِن هَذِهِ الغُرفَة";
|
||||
"room_participants_action_leave" = "مُغادَرَةُ هَذِهِ الغُرفَة";
|
||||
"room_participants_action_invite" = "دَعوَة";
|
||||
"room_participants_action_section_security" = "الأمَان";
|
||||
"room_participants_action_section_other" = "الخِيَارَات";
|
||||
"room_participants_action_section_devices" = "الجَلسَات";
|
||||
"room_participants_action_section_direct_chats" = "المُحادَثَاتُ المُبَاشِرَة";
|
||||
"room_participants_action_section_admin_tools" = "أدَوَاتُ المُدير";
|
||||
"room_participants_ago" = "مُنذُ";
|
||||
"room_participants_now" = "الآن";
|
||||
"room_participants_idle" = "خَامِل";
|
||||
"room_participants_unknown" = "غَير مَعرُوف";
|
||||
"room_participants_offline" = "غَيرُ مُتَّصِل";
|
||||
"room_participants_online" = "مُتَّصِل";
|
||||
"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "لَم يُضبَط خادِم هُويَّة لِذَلِكَ لَا يُمكِنُكَ بَدأ مُحادَثَة مَعَ جِهَةِ اِتِّصالٍ بِاِستِخدَامِ بَريدٍ إلِكتُرونيّ.";
|
||||
"room_participants_invited_section" = "مَدعُوّ";
|
||||
"room_participants_invite_malformed_id" = "مُعَرِّفٌ غَيرُ صَالِح. يَجِبُ أن يَكُون عُنوانُ بَريدٍ إلِكتُرونيِّ أو مُعَرِّفِ Matrix مِثل 'localpart:domain@'";
|
||||
"room_participants_invite_malformed_id_title" = "خَطَأ في الدَّعوَة";
|
||||
"room_participants_invite_another_user" = "البَحث / الدَّعوَةُ بِواسِطَةِ مُعَرِّف المُستَخدِم، الاِسم أو البَريدِ الإلِكتُرونيّ";
|
||||
"room_participants_filter_room_members_for_dm" = "تَصفِيَةُ الأعضَاء";
|
||||
"room_participants_filter_room_members" = "تَصفِيَةُ أعضَاءِ الغُرفَة";
|
||||
"room_participants_invite_prompt_msg" = "هَل أنتَ مُتَأكِّدٌ أنَّكَ تٌريدُ دَعوةَ %@ إلَى هَذِهِ المُحادَثَة؟";
|
||||
|
||||
@@ -62,3 +62,9 @@
|
||||
/* New message indicator on a room */
|
||||
"MESSAGE_IN_X" = "Съобщение в %@";
|
||||
"MESSAGE_PROTECTED" = "Ново съобщение";
|
||||
|
||||
/* Group call from user, CallKit caller name */
|
||||
"GROUP_CALL_FROM_USER" = "%@ (групов разговор)";
|
||||
|
||||
/* A user added a Jitsi call to a room */
|
||||
"GROUP_CALL_STARTED" = "Беше стартиран групов разговор";
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
"room_participants_action_start_video_call" = "Започни видео разговор";
|
||||
"room_participants_action_mention" = "Спомени";
|
||||
// Chat
|
||||
"room_jump_to_first_unread" = "Виж първото непрочетено съобщение";
|
||||
"room_jump_to_first_unread" = "Към непрочетеното";
|
||||
"room_new_message_notification" = "%d ново съобщение";
|
||||
"room_new_messages_notification" = "%d нови съобщения";
|
||||
"room_one_user_is_typing" = "%@ пише…";
|
||||
@@ -672,7 +672,7 @@
|
||||
"room_message_unable_open_link_error_message" = "Неуспешно отваряне на връзката.";
|
||||
"room_event_action_reply" = "Отговори";
|
||||
"room_event_action_edit" = "Редактирай";
|
||||
"auth_login_single_sign_on" = "Влез със SSO";
|
||||
"auth_login_single_sign_on" = "Вход";
|
||||
"room_event_action_reaction_agree" = "Съгласи се с %@";
|
||||
"room_event_action_reaction_disagree" = "Противоречи на %@";
|
||||
"room_event_action_reaction_like" = "Харесай %@";
|
||||
@@ -860,7 +860,7 @@
|
||||
"settings_add_3pid_password_title_email" = "Добави имейл адрес";
|
||||
"settings_add_3pid_password_title_msidsn" = "Добави телефонен номер";
|
||||
"settings_add_3pid_password_message" = "За да продължите, въведете паролата си";
|
||||
"settings_add_3pid_invalid_password_message" = "Невалидна парола";
|
||||
"settings_add_3pid_invalid_password_message" = "Невалидни данни за вход";
|
||||
"settings_devices_description" = "Публичното име на сесията е видимо за хората, с които общувате";
|
||||
"settings_discovery_no_identity_server" = "В момента не използвате сървър за самоличност. Добавете такъв, за да бъдете откриваеми от съществуващи познати контакти.";
|
||||
"settings_discovery_terms_not_signed" = "Съгласете се с условията за ползване на сървъра за самоличност (%@) за да бъдете откриваеми по имейл адрес или телефон.";
|
||||
@@ -1014,7 +1014,7 @@
|
||||
"device_verification_self_verify_wait_title" = "Завършване на сигурността";
|
||||
"device_verification_self_verify_wait_new_sign_in_title" = "Потвърждение на вход";
|
||||
"device_verification_self_verify_wait_information" = "Потвърдете тази сесия от някоя от другите ви сесии, за че да й дадете достъп до шифрованите съобщения.\n\nИзползвайте най-новия Element на другите си устройства:";
|
||||
"device_verification_self_verify_wait_additional_information" = "или друг Matrix клиент поддържащ кръстосано-подписване";
|
||||
"device_verification_self_verify_wait_additional_information" = "Това работи в Element и в други Matrix клиенти поддържащи кръстосано-подписване.";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Използвай ключ за възстановяване";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Използвай парола или ключ за възстановяване";
|
||||
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Ако не можете да достъпите съществуваща сесия";
|
||||
@@ -1280,3 +1280,123 @@
|
||||
"switch" = "Смяна";
|
||||
"joined" = "Се присъедини";
|
||||
"store_promotional_text" = "Пазещо-поверителността ви приложение за чат и съвместна работа, което е част от отворена мрежа. Децентрализирано, за да ви даде контрол. Без събиране на данни, без задни вратички и без достъп на трети страни.";
|
||||
"space_beta_announce_information" = "Пространства са нов начин да групирате стаи и хора. Все още не работят на iOS, но можете да ги използвате през Уеб и Desktop.";
|
||||
"space_beta_announce_subtitle" = "Новата версия на общности";
|
||||
"space_beta_announce_title" = "Пространства ще е налично скоро";
|
||||
"space_beta_announce_badge" = "БЕТА";
|
||||
"space_feature_unavailable_information" = "Пространства е нов начин за групиране на стаи и хора.\n\nСкоро ще са налични за ползване. Засега, ако се присъедините към Пространство от друга платформа, и тук ще можете да достъпите стаите, към които се присъедините.";
|
||||
"space_feature_unavailable_subtitle" = "Функция Пространства не се поддържа на iOS все още, но можете да ги използвате в Уеб и Desktop версията";
|
||||
|
||||
// Mark: - Spaces
|
||||
|
||||
"space_feature_unavailable_title" = "Все още не се поддържат Пространства";
|
||||
"room_intro_cell_information_multiple_dm_sentence2" = "Само вие сте в този разговор, освен ако някой от вас не покани друг да се присъедини.";
|
||||
"room_intro_cell_information_dm_sentence2" = "Никой друг освен двама ви не може да се присъедини в този разговор.";
|
||||
"room_intro_cell_information_dm_sentence1_part3" = ". ";
|
||||
"room_intro_cell_information_dm_sentence1_part1" = "Това е началото на директните ви съобщения с ";
|
||||
"room_intro_cell_information_room_without_topic_sentence2_part2" = " за да кажете на хората за какво е тази стая.";
|
||||
"room_intro_cell_information_room_without_topic_sentence2_part1" = "Добави тема";
|
||||
"room_intro_cell_information_room_with_topic_sentence2" = "Тема: %@";
|
||||
"room_intro_cell_information_room_sentence1_part3" = ". ";
|
||||
"room_intro_cell_information_room_sentence1_part1" = "Това е началото на ";
|
||||
|
||||
// Mark: - Room creation introduction cell
|
||||
|
||||
"room_intro_cell_add_participants_action" = "Добави хора";
|
||||
"room_avatar_view_accessibility_hint" = "Промени аватара на стаята";
|
||||
|
||||
// Mark: - Room avatar view
|
||||
|
||||
"room_avatar_view_accessibility_label" = "аватар";
|
||||
"invite_friends_share_text" = "Хей, говори с мен в %@: %@";
|
||||
|
||||
// MARK: - Invite friends
|
||||
|
||||
"invite_friends_action" = "Покани приятели в %@";
|
||||
"favourites_empty_view_information" = "Можете да добавяте в любими по няколко начина - най-бързият е чрез натискане и задържане. Докоснете звездата и стаята ще се появи тук автоматично.";
|
||||
|
||||
// MARK: - Favourites
|
||||
|
||||
"favourites_empty_view_title" = "Любими хора и стаи";
|
||||
"home_empty_view_information" = "Комплексно приложение за защитен чат за екипи, приятели и организации. Докоснете бутон + по-долу за да добавите хора и стаи.";
|
||||
|
||||
// MARK: - Home
|
||||
|
||||
"home_empty_view_title" = "Добре дошли в %@,\n%@";
|
||||
"call_transfer_error_message" = "Прехвърлянето на разговора се провали";
|
||||
"call_transfer_error_title" = "Грешка";
|
||||
"call_transfer_contacts_all" = "Всички";
|
||||
"call_transfer_contacts_recent" = "Скорошни";
|
||||
"call_transfer_dialpad" = "Панел за набиране";
|
||||
"call_transfer_users" = "Потребители";
|
||||
|
||||
// MARK: - Call Transfer
|
||||
"call_transfer_title" = "Прехвърляне";
|
||||
|
||||
// MARK: - Dial Pad
|
||||
"dialpad_title" = "Панел за набиране";
|
||||
"pin_protection_settings_change_pin" = "Промяна на PIN код";
|
||||
"pin_protection_confirm_pin_to_change" = "Потвърдете PIN кода за да го промените";
|
||||
"secrets_setup_recovery_passphrase_summary_information" = "Запомнете паролата си. Може да се използва за да отключи шифрованите съобщения и данни.";
|
||||
"secrets_setup_recovery_passphrase_summary_title" = "Запазете паролата си";
|
||||
"bug_report_background_mode" = "Продължи във фонов режим";
|
||||
"call_actions_unhold" = "Възобнови";
|
||||
"event_formatter_group_call_incoming" = "%@ в %@";
|
||||
"event_formatter_group_call_leave" = "Напусни";
|
||||
"event_formatter_group_call_join" = "Влез";
|
||||
"event_formatter_group_call" = "Групов разговор";
|
||||
"event_formatter_call_end_call" = "Затвори";
|
||||
"event_formatter_call_retry" = "Опитай пак";
|
||||
"event_formatter_call_answer" = "Отговори";
|
||||
"event_formatter_call_decline" = "Откажи";
|
||||
"event_formatter_call_back" = "Звънни отново";
|
||||
"event_formatter_call_connection_failed" = "Връзката се провали";
|
||||
"event_formatter_call_you_missed" = "Пропуснахте това обаждане";
|
||||
"event_formatter_call_you_declined" = "Отказахте разговора";
|
||||
"event_formatter_call_you_currently_in" = "Активен разговор";
|
||||
"event_formatter_call_has_ended" = "Прекратяване на %@";
|
||||
"event_formatter_call_ringing" = "Звънене…";
|
||||
"event_formatter_call_connecting" = "Свързване…";
|
||||
"event_formatter_call_video" = "Видео разговор";
|
||||
"event_formatter_call_voice" = "Гласов разговор";
|
||||
"room_details_integrations" = "Интеграции";
|
||||
"room_details_search" = "Търси в стаята";
|
||||
"settings_show_NSFW_public_rooms" = "Показвай публични стаи с чувствително съдържание";
|
||||
"settings_labs_enable_ringing_for_group_calls" = "Позвъняване за групови разговори";
|
||||
"room_multiple_typing_notification" = "%@ и други";
|
||||
"room_no_privileges_to_create_group_call" = "Трябва да сте администратор или модератор за да започнете разговор.";
|
||||
"room_join_group_call" = "Влез";
|
||||
"room_open_dialpad" = "Панел за набиране";
|
||||
"room_place_voice_call" = "Гласов разговор";
|
||||
"room_accessibility_video_call" = "Видео разговор";
|
||||
"room_event_action_delete_confirmation_message" = "Сигурни ли сте, че искате да изтриете неизпратеното съобщение?";
|
||||
"room_event_action_delete_confirmation_title" = "Изтрий неизпратеното съобщение";
|
||||
"room_unsent_messages_cancel_message" = "Сигурни ли сте, че искате да изтриете всички неизпратени съобщения в тази стая?";
|
||||
"room_unsent_messages_cancel_title" = "Изтрий неизпратените съобщения";
|
||||
"room_message_replying_to" = "Отговаряне на %@";
|
||||
"room_message_editing" = "Редактиране";
|
||||
|
||||
// Chat
|
||||
"room_slide_to_end_group_call" = "Издърпайте за да прекратите разговора за всички";
|
||||
"rooms_empty_view_information" = "Стаите са удобни за какъв да е групов чат - личен или публичен. Докоснете + за да намерите съществуващи стаи или да създадете нови.";
|
||||
"rooms_empty_view_title" = "Стаи";
|
||||
"people_empty_view_information" = "Чатете защитено с всеки. Докоснете + за да добавите хора.";
|
||||
"people_empty_view_title" = "Хора";
|
||||
"social_login_button_title_sign_up" = "Регистрирай се с %@";
|
||||
"social_login_button_title_sign_in" = "Влез с %@";
|
||||
"social_login_button_title_continue" = "Продължи с %@";
|
||||
"social_login_list_title_sign_up" = "или";
|
||||
"social_login_list_title_sign_in" = "или";
|
||||
|
||||
// Social login
|
||||
|
||||
"social_login_list_title_continue" = "Продължи с";
|
||||
"callbar_only_single_active_group" = "Докоснете за влизане в груповия разговор (%@)";
|
||||
"callbar_return" = "Връщане";
|
||||
"callbar_only_multiple_paused" = "%@ паузирани разговора";
|
||||
"callbar_only_single_paused" = "Паузиран разговор";
|
||||
"callbar_active_and_multiple_paused" = "1 активен разговор (%@) · %@ паузирани разговора";
|
||||
"callbar_active_and_single_paused" = "1 активен разговор (%@) · 1 паузиран разговор";
|
||||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Докоснете за връщане в разговора (%@)";
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
"room_participants_action_start_video_call" = "Starte Video-Anruf";
|
||||
"room_participants_action_mention" = "Erwähnen";
|
||||
// Chat
|
||||
"room_jump_to_first_unread" = "Zur ersten ungelesenen Nachricht springen";
|
||||
"room_jump_to_first_unread" = "Zur ersten ungelesenen Nachricht";
|
||||
"room_new_message_notification" = "%d neue Nachricht";
|
||||
"room_new_messages_notification" = "%d neue Nachrichten";
|
||||
"room_one_user_is_typing" = "%@ tippt…";
|
||||
@@ -159,7 +159,7 @@
|
||||
"room_offline_notification" = "Verbindung zum Server wurde unterbrochen.";
|
||||
"room_unsent_messages_notification" = "Nachrichten wurden nicht gesendet.";
|
||||
"room_unsent_messages_unknown_devices_notification" = "Nachrichten wurden nicht gesendet, da unbekannte Sitzungen vorhanden waren.";
|
||||
"room_prompt_resend" = "alle erneut senden";
|
||||
"room_prompt_resend" = "Alle erneut senden";
|
||||
"room_prompt_cancel" = "Alles abbrechen";
|
||||
"room_resend_unsent_messages" = "Ungesendete Nachrichten erneut senden";
|
||||
"room_delete_unsent_messages" = "Lösche ungesendete Nachrichten";
|
||||
@@ -892,7 +892,7 @@
|
||||
"settings_add_3pid_password_title_msidsn" = "Telefonnummer hinzufügen";
|
||||
"settings_add_3pid_password_message" = "Um fortzufahren, bitte Passwort eingeben";
|
||||
"settings_add_3pid_invalid_password_message" = "Ungültige Anmeldedaten";
|
||||
"identity_server_settings_disconnect_info" = "Eine Trennung von deinem Identitätsserver würde bedeuten, dass du weder von anderen Nutzer gefunden werden, noch diese dich per E-Mail oder Telefonnummer einladen können.";
|
||||
"identity_server_settings_disconnect_info" = "Eine Trennung vom Identitätsserver bedeutet, dass du weder von anderen Nutzer gefunden werden, noch diese dich per E-Mail oder Telefonnummer einladen können.";
|
||||
"error_not_supported_on_mobile" = "Dies ist in der Mobilvariante von %@ nicht möglich.";
|
||||
"settings_integrations" = "INTEGRATIONEN";
|
||||
"settings_integrations_allow_button" = "Integrationen verwalten";
|
||||
@@ -1058,7 +1058,7 @@
|
||||
"key_verification_other_session_title" = "Sitzung verifizieren";
|
||||
"key_verification_new_session_title" = "Neue Sitzung verifizieren";
|
||||
"key_verification_this_session_title" = "Verifiziere diese Sitzung";
|
||||
"device_verification_security_advice_emoji" = "Vergleiche die einzigartigen Emojis und kontrolliere, dass sie in derselben Reihenfolge angezeigt werden.";
|
||||
"device_verification_security_advice_emoji" = "Vergleiche die Emojis und kontrolliere, dass sie in derselben Reihenfolge angezeigt werden.";
|
||||
"device_verification_security_advice_number" = "Vergleiche die Zahlen und stell sicher, dass sie in derselben Reihenfolge angezeigt werden.";
|
||||
"key_verification_self_verify_current_session_alert_title" = "Verifiziere diese Sitzung";
|
||||
"key_verification_self_verify_current_session_alert_message" = "Andere Benutzer vertrauen ihr vielleicht nicht.";
|
||||
@@ -1324,7 +1324,7 @@
|
||||
"callbar_active_and_single_paused" = "1 aktiver Anruf (%1$s) · 1 pausierter Anruf";
|
||||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Laufender Anruf (%@)";
|
||||
"callbar_only_single_active" = "Zurück zum Anruf (%@)";
|
||||
"room_event_action_delete_confirmation_message" = "Möchtest Du die nicht gesendete Nachricht wirklich löschen?";
|
||||
"room_event_action_delete_confirmation_title" = "Nicht gesendete Nachricht löschen";
|
||||
"room_details_integrations" = "Integrationen";
|
||||
@@ -1360,5 +1360,31 @@
|
||||
|
||||
// Chat
|
||||
"room_slide_to_end_group_call" = "Wische, um den Anruf für alle zu beenden";
|
||||
"callbar_only_single_active_group" = "Klicke, um den Anruf beizutreten";
|
||||
"callbar_only_single_active_group" = "Klicke, um den Anruf beizutreten (%@)";
|
||||
"event_formatter_call_answer" = "Annehmen";
|
||||
"side_menu_app_version" = "Version %@";
|
||||
"side_menu_action_feedback" = "Feedback";
|
||||
"side_menu_action_help" = "Hilfe";
|
||||
"side_menu_action_settings" = "Einstellungen";
|
||||
"side_menu_action_invite_friends" = "Freunde einladen";
|
||||
|
||||
// Mark: - Side menu
|
||||
|
||||
"side_menu_reveal_action_accessibility_label" = "Linkes Panel";
|
||||
"user_avatar_view_accessibility_hint" = "Nutzeravatar ändern";
|
||||
|
||||
// Mark: - User avatar view
|
||||
|
||||
"user_avatar_view_accessibility_label" = "Avatar";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "Zum Fortfahren gib deinen Sicherheitsschlüssel ein.";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Zum Forfahren gib deine Passphrase ein.";
|
||||
|
||||
// Success from secure backup
|
||||
"key_backup_setup_success_from_secure_backup_info" = "Deine Schlüssel werden gesichert.";
|
||||
"security_settings_secure_backup_restore" = "Von Backup wiederherstellen";
|
||||
"security_settings_secure_backup_reset" = "Zurücksetzen";
|
||||
"security_settings_secure_backup_info_valid" = "Diese Sitzung sichert deine Schlüssel.";
|
||||
"security_settings_secure_backup_info_checking" = "Überprüfen…";
|
||||
"settings_ui_theme_picker_message_match_system_theme" = "\"Auto\" passt sich an das Systemthema an";
|
||||
"room_recents_unknown_room_error_message" = "Raum kann nicht gefunden werden. Überprüfe bitte, dass er existiert";
|
||||
"room_creation_dm_error" = "Fehler beim Erstellen der Direktnachricht. Bitte überprüfe die eingeladenen Leute und versuche es erneut.";
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
"room_creation_wait_for_creation" = "A room is already being created. Please wait.";
|
||||
"room_creation_invite_another_user" = "Search / invite by User ID, Name or email";
|
||||
"room_creation_error_invite_user_by_email_without_identity_server" = "No identity server is configured so you cannot add a participant with an email.";
|
||||
"room_creation_dm_error" = "We couldn't create your DM. Please check the users you want to invite and try again.";
|
||||
|
||||
// Room recents
|
||||
"room_recents_directory_section" = "ROOM DIRECTORY";
|
||||
@@ -194,6 +195,7 @@
|
||||
"room_recents_join_room" = "Join room";
|
||||
"room_recents_join_room_title" = "Join a room";
|
||||
"room_recents_join_room_prompt" = "Type a room id or a room alias";
|
||||
"room_recents_unknown_room_error_message" = "Can't find this room. Make sure it exists";
|
||||
|
||||
// People tab
|
||||
"people_invites_section" = "INVITES";
|
||||
@@ -519,7 +521,8 @@ Tap the + to start adding people.";
|
||||
"settings_ui_theme_dark" = "Dark";
|
||||
"settings_ui_theme_black" = "Black";
|
||||
"settings_ui_theme_picker_title" = "Select a theme";
|
||||
"settings_ui_theme_picker_message" = "\"Auto\" uses your device \"Invert Colours\" settings";
|
||||
"settings_ui_theme_picker_message_invert_colours" = "\"Auto\" uses your device's \"Invert Colours\" settings";
|
||||
"settings_ui_theme_picker_message_match_system_theme" = "\"Auto\" matches your device's system theme";
|
||||
|
||||
"settings_unignore_user" = "Show all messages from %@?";
|
||||
|
||||
@@ -565,7 +568,7 @@ Tap the + to start adding people.";
|
||||
"settings_key_backup_info" = "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.";
|
||||
"settings_key_backup_info_checking" = "Checking…";
|
||||
"settings_key_backup_info_none" = "Your keys are not being backed up from this session.";
|
||||
"settings_key_backup_info_signout_warning" = "Connect this session to key backup before signing out to avoid losing any keys that may only be on this device.";
|
||||
"settings_key_backup_info_signout_warning" = "Back up your keys before signing out to avoid losing them.";
|
||||
"settings_key_backup_info_version" = "Key Backup Version: %@";
|
||||
"settings_key_backup_info_algorithm" = "Algorithm: %@";
|
||||
"settings_key_backup_info_valid" = "This session is backing up your keys.";
|
||||
@@ -619,10 +622,13 @@ Tap the + to start adding people.";
|
||||
"security_settings_crypto_sessions_description_2" = "If you don’t recognise a login, change your password and reset Secure Backup.";
|
||||
|
||||
"security_settings_secure_backup" = "SECURE BACKUP";
|
||||
"security_settings_secure_backup_description" = "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.";
|
||||
"security_settings_secure_backup_description" = "Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Security Key.";
|
||||
"security_settings_secure_backup_info_checking" = "Checking…";
|
||||
"security_settings_secure_backup_info_valid" = "This session is backing up your keys.";
|
||||
"security_settings_secure_backup_setup" = "Set up";
|
||||
"security_settings_secure_backup_synchronise" = "Synchronise";
|
||||
"security_settings_secure_backup_delete" = "Delete";
|
||||
"security_settings_secure_backup_reset" = "Reset";
|
||||
"security_settings_secure_backup_restore" = "Restore from Backup";
|
||||
"security_settings_secure_backup_delete" = "Delete Backup";
|
||||
|
||||
"security_settings_backup" = "MESSAGE BACKUP";
|
||||
|
||||
@@ -630,9 +636,9 @@ Tap the + to start adding people.";
|
||||
"security_settings_crosssigning_info_not_bootstrapped" = "Cross-signing is not yet set up.";
|
||||
"security_settings_crosssigning_info_exists" = "Your account has a cross-signing identity, but it is not yet trusted by this session. Complete security of this session.";
|
||||
"security_settings_crosssigning_info_trusted" = "Cross-signing is enabled. You can trust other users and your other sessions based on cross-signing but you cannot cross-sign from this session because it does not have cross-signing private keys. Complete security of this session.";
|
||||
"security_settings_crosssigning_info_ok" = "Cross-signing is enabled.";
|
||||
"security_settings_crosssigning_bootstrap" = "Bootstrap cross-signing";
|
||||
"security_settings_crosssigning_reset" = "Reset cross-signing";
|
||||
"security_settings_crosssigning_info_ok" = "Cross-signing is ready for use.";
|
||||
"security_settings_crosssigning_bootstrap" = "Set up";
|
||||
"security_settings_crosssigning_reset" = "Reset";
|
||||
"security_settings_crosssigning_complete_security" = "Complete security";
|
||||
|
||||
"security_settings_cryptography" = "CRYPTOGRAPHY";
|
||||
@@ -896,7 +902,7 @@ Tap the + to start adding people.";
|
||||
|
||||
// Key backup wrong version
|
||||
"e2e_key_backup_wrong_version_title" = "New Key Backup";
|
||||
"e2e_key_backup_wrong_version" = "A new secure message key backup has been detected.\n\nIf this wasn’t you, set a new passphrase in Settings.";
|
||||
"e2e_key_backup_wrong_version" = "A new secure message key backup has been detected.\n\nIf this wasn’t you, set a new Security Phrase in Settings.";
|
||||
"e2e_key_backup_wrong_version_button_settings" = "Settings";
|
||||
"e2e_key_backup_wrong_version_button_wasme" = "It was me";
|
||||
|
||||
@@ -1022,7 +1028,7 @@ Tap the + to start adding people.";
|
||||
"secure_key_backup_setup_intro_use_security_key_title" = "Use a Security Key";
|
||||
"secure_key_backup_setup_intro_use_security_key_info" = "Generate a security key to store somewhere safe like a password manager or a safe.";
|
||||
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Use a Security Passphrase";
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Use a Security Phrase";
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_info" = "Enter a secret phrase only you know, and generate a key for backup.";
|
||||
|
||||
"secure_key_backup_setup_existing_backup_error_title" = "A backup for messages already exists";
|
||||
@@ -1061,66 +1067,69 @@ Tap the + to start adding people.";
|
||||
|
||||
// Passphrase
|
||||
|
||||
"key_backup_setup_passphrase_title" = "Secure your backup with a Passphrase";
|
||||
"key_backup_setup_passphrase_info" = "We'll store an encrypted copy of your keys on our server. Protect your backup with a passphrase to keep it secure.\n\nFor maximum security, this should be different from your account password.";
|
||||
"key_backup_setup_passphrase_title" = "Secure your backup with a Security Phrase";
|
||||
"key_backup_setup_passphrase_info" = "We'll store an encrypted copy of your keys on our server. Protect your backup with a phrase to keep it secure.\n\nFor maximum security, this should be different from your account password.";
|
||||
"key_backup_setup_passphrase_passphrase_title" = "Enter";
|
||||
"key_backup_setup_passphrase_passphrase_placeholder" = "Enter passphrase";
|
||||
"key_backup_setup_passphrase_passphrase_placeholder" = "Enter phrase";
|
||||
"key_backup_setup_passphrase_passphrase_valid" = "Great!";
|
||||
"key_backup_setup_passphrase_passphrase_invalid" = "Try adding a word";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_title" = "Confirm";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "Confirm passphrase";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "Confirm phrase";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_valid" = "Great!";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "Passphrase doesn’t match";
|
||||
"key_backup_setup_passphrase_set_passphrase_action" = "Set Passphrase";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_info" = "Or, secure your backup with a Recovery Key, saving it somewhere safe.";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Advanced) Set up with Recovery Key";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "phrase doesn’t match";
|
||||
"key_backup_setup_passphrase_set_passphrase_action" = "Set Phrase";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_info" = "Or, secure your backup with a Security Key, saving it somewhere safe.";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Advanced) Set up with Security Key";
|
||||
|
||||
// Success
|
||||
|
||||
"key_backup_setup_success_title" = "Success!";
|
||||
|
||||
// Success from passphrase
|
||||
"key_backup_setup_success_from_passphrase_info" = "Your keys are being backed up.\n\nYour recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.\n\nKeep your recovery key somewhere very secure, like a password manager (or a safe).";
|
||||
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Save Recovery Key";
|
||||
"key_backup_setup_success_from_passphrase_info" = "Your keys are being backed up.\n\nYour Security Key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.\n\nKeep your Security Key somewhere very secure, like a password manager (or a safe).";
|
||||
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Save Security Key";
|
||||
"key_backup_setup_success_from_passphrase_done_action" = "Done";
|
||||
|
||||
// Success from recovery key
|
||||
"key_backup_setup_success_from_recovery_key_info" = "Your keys are being backed up.\n\nMake a copy of this recovery key and keep it safe.";
|
||||
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Recovery Key";
|
||||
"key_backup_setup_success_from_recovery_key_info" = "Your keys are being backed up.\n\nMake a copy of this Security Key and keep it safe.";
|
||||
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Security Key";
|
||||
"key_backup_setup_success_from_recovery_key_make_copy_action" = "Make a Copy";
|
||||
"key_backup_setup_success_from_recovery_key_made_copy_action" = "I've made a copy";
|
||||
|
||||
// Success from secure backup
|
||||
"key_backup_setup_success_from_secure_backup_info" = "Your keys are being backed up.";
|
||||
|
||||
// MARK: Key backup recover
|
||||
|
||||
"key_backup_recover_title" = "Secure Messages";
|
||||
|
||||
"key_backup_recover_invalid_passphrase_title" = "Incorrect Recovery Passphrase";
|
||||
"key_backup_recover_invalid_passphrase" = "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.";
|
||||
"key_backup_recover_invalid_recovery_key_title" = "Recovery Key Mismatch";
|
||||
"key_backup_recover_invalid_recovery_key" = "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.";
|
||||
"key_backup_recover_invalid_passphrase_title" = "Incorrect Security Phrase";
|
||||
"key_backup_recover_invalid_passphrase" = "Backup could not be decrypted with this phrase: please verify that you entered the correct Security Phrase.";
|
||||
"key_backup_recover_invalid_recovery_key_title" = "Security Key Mismatch";
|
||||
"key_backup_recover_invalid_recovery_key" = "Backup could not be decrypted with this key: please verify that you entered the correct Security Key.";
|
||||
|
||||
// Recover from private key
|
||||
"key_backup_recover_from_private_key_info" = "Restoring backup…";
|
||||
|
||||
// Recover from passphrase
|
||||
|
||||
"key_backup_recover_from_passphrase_info" = "Use your recovery passphrase to unlock your secure message history";
|
||||
"key_backup_recover_from_passphrase_info" = "Use your Security Phrase to unlock your secure message history";
|
||||
"key_backup_recover_from_passphrase_passphrase_title" = "Enter";
|
||||
"key_backup_recover_from_passphrase_passphrase_placeholder" = "Enter Passphrase";
|
||||
"key_backup_recover_from_passphrase_passphrase_placeholder" = "Enter Phrase";
|
||||
"key_backup_recover_from_passphrase_recover_action" = "Unlock History";
|
||||
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Don’t know your recovery passphrase? You can ";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "use your recovery key";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Don’t know your Security Phrase? You can ";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "use your Security Key";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part3" = ".";
|
||||
|
||||
// Recover from recovery key
|
||||
|
||||
"key_backup_recover_from_recovery_key_info" = "Use your recovery key to unlock your secure message history";
|
||||
"key_backup_recover_from_recovery_key_info" = "Use your Security Key to unlock your secure message history";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_title" = "Enter";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Enter Recovery Key";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Enter Security Key";
|
||||
"key_backup_recover_from_recovery_key_recover_action" = "Unlock History";
|
||||
|
||||
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Lost your recovery key? You can set up a new one in settings.";
|
||||
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Lost your Security Key You can set up a new one in settings.";
|
||||
|
||||
// Success
|
||||
|
||||
@@ -1197,8 +1206,8 @@ Tap the + to start adding people.";
|
||||
"device_verification_self_verify_wait_new_sign_in_title" = "Verify this login";
|
||||
"device_verification_self_verify_wait_information" = "Verify this session from one of your other sessions, granting it access to encrypted messages.\n\nUse the latest Element on your other devices:";
|
||||
"device_verification_self_verify_wait_additional_information" = "This works with Element and other cross-signing capable Matrix clients.";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Use Recovery Key";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Use Recovery Passphrase or Key";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Use Security Key";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Use Security Phrase or Key";
|
||||
"device_verification_self_verify_wait_recover_secrets_additional_information" = "If you can't access an existing session";
|
||||
"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Checking for other verification capabilities ...";
|
||||
|
||||
@@ -1432,38 +1441,40 @@ Tap the + to start adding people.";
|
||||
|
||||
// Recover with passphrase
|
||||
|
||||
"secrets_recovery_with_passphrase_title" = "Recovery Passphrase";
|
||||
"secrets_recovery_with_passphrase_information_default" = "Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery passphrase.";
|
||||
"secrets_recovery_with_passphrase_information_verify_device" = "Use your Recovery Passphrase to verify this device.";
|
||||
"secrets_recovery_with_passphrase_title" = "Security Phrase";
|
||||
"secrets_recovery_with_passphrase_information_default" = "Access your secure message history and your cross-signing identity for verifying other sessions by entering your Security Phrase.";
|
||||
"secrets_recovery_with_passphrase_information_verify_device" = "Use your Security Phrase to verify this device.";
|
||||
"secrets_recovery_with_passphrase_passphrase_title" = "Enter";
|
||||
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Enter Recovery Passphrase";
|
||||
"secrets_recovery_with_passphrase_recover_action" = "Use Passphrase";
|
||||
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Enter Security Phrase";
|
||||
"secrets_recovery_with_passphrase_recover_action" = "Use Phrase";
|
||||
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Don’t know your recovery passphrase? You can ";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "use your recovery key";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Don’t know your Security Phrase? You can ";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "use your Security Key";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
|
||||
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Unable to access secret storage";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Please verify that you entered the correct recovery passphrase.";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Please verify that you entered the correct Security Phrase.";
|
||||
|
||||
// Recover with key
|
||||
|
||||
"secrets_recovery_with_key_title" = "Recovery Key";
|
||||
"secrets_recovery_with_key_information_default" = "Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery key.";
|
||||
"secrets_recovery_with_key_information_verify_device" = "Use your Recovery Key to verify this device.";
|
||||
"secrets_recovery_with_key_title" = "Security Key";
|
||||
"secrets_recovery_with_key_information_default" = "Access your secure message history and your cross-signing identity for verifying other sessions by entering your Security Key.";
|
||||
"secrets_recovery_with_key_information_verify_device" = "Use your Security Key to verify this device.";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Enter your Security Phrase to continue.";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "Enter your Security Key to continue.";
|
||||
"secrets_recovery_with_key_recovery_key_title" = "Enter";
|
||||
"secrets_recovery_with_key_recovery_key_placeholder" = "Enter Recovery Key";
|
||||
"secrets_recovery_with_key_recovery_key_placeholder" = "Enter Security Key";
|
||||
"secrets_recovery_with_key_recover_action" = "Use Key";
|
||||
|
||||
"secrets_recovery_with_key_invalid_recovery_key_title" = "Unable to access secret storage";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "Please verify that you entered the correct recovery key.";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "Please verify that you entered the correct Security Key.";
|
||||
|
||||
// MARK: - Secrets set up
|
||||
|
||||
// Recovery Key
|
||||
|
||||
"secrets_setup_recovery_key_title" = "Save your Security Key";
|
||||
"secrets_setup_recovery_key_information" = "Store your Recovery Key somewhere safe. It can be used to unlock your encrypted messages & data.";
|
||||
"secrets_setup_recovery_key_information" = "Store your Security Key somewhere safe. It can be used to unlock your encrypted messages & data.";
|
||||
"secrets_setup_recovery_key_loading" = "Loading…";
|
||||
"secrets_setup_recovery_key_export_action" = "Save";
|
||||
"secrets_setup_recovery_key_done_action" = "Done";
|
||||
@@ -1480,10 +1491,10 @@ Tap the + to start adding people.";
|
||||
|
||||
"secrets_setup_recovery_passphrase_confirm_information" = "Enter your Security Phrase again to confirm it.";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Confirm";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Confirm passphrase";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Confirm phrase";
|
||||
|
||||
"key_backup_setup_passphrase_confirm_passphrase_valid" = "Great!";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "Passphrase doesn’t match";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "Phrase doesn’t match";
|
||||
|
||||
"secrets_setup_recovery_passphrase_summary_title" = "Save your Security Phrase";
|
||||
"secrets_setup_recovery_passphrase_summary_information" = "Remember your Security Phrase. It can be used to unlock your encrypted messages & data.";
|
||||
@@ -1643,3 +1654,17 @@ Tap the + to start adding people.";
|
||||
"space_beta_announce_title" = "Spaces are coming soon";
|
||||
"space_beta_announce_subtitle" = "The new version of communities";
|
||||
"space_beta_announce_information" = "Spaces are a new way to group rooms and people. They’re not on iOS yet, but you can use them now on Web and Desktop.";
|
||||
|
||||
// Mark: - User avatar view
|
||||
|
||||
"user_avatar_view_accessibility_label" = "avatar";
|
||||
"user_avatar_view_accessibility_hint" = "Change user avatar";
|
||||
|
||||
// Mark: - Side menu
|
||||
|
||||
"side_menu_reveal_action_accessibility_label" = "Left panel";
|
||||
"side_menu_action_invite_friends" = "Invite friends";
|
||||
"side_menu_action_settings" = "Settings";
|
||||
"side_menu_action_help" = "Help";
|
||||
"side_menu_action_feedback" = "Feedback";
|
||||
"side_menu_app_version" = "Version %@";
|
||||
|
||||
@@ -227,11 +227,11 @@
|
||||
"security_settings_coming_soon" = "Vabandust. See tegevus pole veel kasutatav Element iOS rakenduses. Palun kasuta seadistamiseks mõnda muud Matrix'i klienti ning Element iOS oskab seda kasutada.";
|
||||
"major_update_title" = "Riot'i uus nimi on Element";
|
||||
"security_settings_secure_backup_synchronise" = "Sünkroniseeri";
|
||||
"security_settings_secure_backup_delete" = "Kustuta";
|
||||
"security_settings_secure_backup_delete" = "Kustuta varukoopia";
|
||||
"security_settings_backup" = "SÕNUMITE VARUNDUS";
|
||||
"security_settings_crosssigning" = "RISTTUNNUSTAMINE";
|
||||
"security_settings_crosssigning_info_not_bootstrapped" = "Risttunnustamine pole veel seadistatud.";
|
||||
"security_settings_crosssigning_info_ok" = "Risttunnustamine on kasutusel.";
|
||||
"security_settings_crosssigning_info_ok" = "Risttunnustamine on kasutamiseks valmis.";
|
||||
"security_settings_cryptography" = "KRÜPTOGRAAFIA";
|
||||
"security_settings_export_keys_manually" = "Ekspordi võtmed käsitsi";
|
||||
"group_participants_leave_prompt_title" = "Lahku grupist";
|
||||
@@ -636,11 +636,11 @@
|
||||
"room_widget_permission_widget_id_permission" = "Vidina tunnus";
|
||||
"room_widget_permission_room_id_permission" = "Jututoa tunnus";
|
||||
// Success from passphrase
|
||||
"key_backup_setup_success_from_passphrase_info" = "Sinu krüptovõtmed on varundatud.\n\nSinu taastevõti toimib turvavõrguna - juhul, kui sa unustad taastamiseks mõeldud paroolifraasi, siis sa saad seda kasutada taastamaks ligipääsu krüptitud sõnumitele.\n\nHoia taastevõtit turvalises kohas, nagu näiteks salasõnahalduris või vana kooli seifis.";
|
||||
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Salvesta taastevõti";
|
||||
"key_backup_setup_success_from_passphrase_info" = "Sinu krüptovõtmed on varundatud.\n\nSinu turvavõti toimib päästevõrguna - juhul, kui sa unustad taastamiseks mõeldud paroolifraasi, siis sa saad seda kasutada taastamaks ligipääsu krüptitud sõnumitele.\n\nHoia turvavõtit turvalises kohas, nagu näiteks salasõnahalduris või vana kooli seifis.";
|
||||
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Salvesta turvavõti";
|
||||
"key_backup_setup_success_from_passphrase_done_action" = "Valmis";
|
||||
"key_backup_recover_from_passphrase_passphrase_placeholder" = "Sisesta paroolifraas";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Sisesta taastevõti";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Sisesta turvavõti";
|
||||
"sign_out_key_backup_in_progress_alert_discard_key_backup_action" = "Ma ei soovi lugeda oma krüptitud sõnumeid";
|
||||
"sign_out_key_backup_in_progress_alert_cancel_action" = "Ma võin oodata";
|
||||
// MARK: - Device Verification
|
||||
@@ -775,7 +775,7 @@
|
||||
"security_settings_crypto_sessions" = "MINU SESSIOONID";
|
||||
"security_settings_crypto_sessions_description_2" = "Kui sa ei tunne ära mõnda oma sisselogimissessiooni, siis muuda ära oma salasõna ja tee võtmetest uus turvaline varukoopia.";
|
||||
"security_settings_secure_backup" = "TURVALINE VARUNDUS";
|
||||
"security_settings_secure_backup_description" = "Tagamaks, et sa ei kaota ligipääsu krüptitud sõnumitele ja andmetele, varunda krüptimisvõtmed oma serveris.";
|
||||
"security_settings_secure_backup_description" = "Selleks puhuks, kui sa kaotad ligipääsu kõikidele oma sessioonidele, tee varukoopia oma krüptovõtmetest ja kasutajakonto seadistustest. Unikaalse turvavõtmega tagad selle, et sinu varukoopia on kaitstud.";
|
||||
"security_settings_secure_backup_setup" = "Võta kasutusele";
|
||||
"security_settings_crosssigning_info_exists" = "Sinu kontol on olemas risttunnustamise identiteet, kuid seda veel ei loeta antud sessioonis usaldusväärseks. Vormista lõpuni selle sessiooni turvaseadistused.";
|
||||
"e2e_room_key_request_ignore_request" = "Eira päringut";
|
||||
@@ -800,7 +800,7 @@
|
||||
"key_backup_setup_intro_setup_connect_action_with_existing_backup" = "Seo see seade krüptovõtmete varundusega";
|
||||
"key_backup_setup_intro_manual_export_info" = "(Lisaseadistused)";
|
||||
"key_backup_setup_intro_manual_export_action" = "Ekspordi võtmed käsitsi";
|
||||
"key_backup_setup_passphrase_title" = "Krüpti oma varukoopia paroolifraasiga";
|
||||
"key_backup_setup_passphrase_title" = "Krüpti oma varukoopia turvafraasiga";
|
||||
"key_backup_setup_passphrase_info" = "Me salvestame krüptitud varukoopia sinu krüptovõtmetest meie serveris. Tagamaks, et keegi ei saa seda kasutada, krüpti varukoopia paroolifraasiga.\n\n Parima turvalisuse jaoks peaks paroolifraas olema erinev sinu konto salasõnast.";
|
||||
"key_backup_setup_passphrase_passphrase_title" = "Sisesta";
|
||||
"key_backup_setup_passphrase_passphrase_placeholder" = "Sisesta paroolifraas";
|
||||
@@ -854,19 +854,19 @@
|
||||
"key_verification_scan_confirmation_scanned_device_information" = "Kas teine seade kuvab sama kilpi?";
|
||||
"user_verification_start_verify_action" = "Alusta verifitseerimist";
|
||||
"security_settings_crosssigning_info_trusted" = "Risttunnustamine on kasutusel. Selle põhjal saad sa usaldada nii teisi kasutajaid, kui ka oma teisi sessioone, kuid kuna sul siin sessioonis pole risttunnustamise privaatvõtmeid, siis sa siit uusi risttunnustamisi teha. Selle jaoks vormista lõpuni praeguse sessiooni turvaseadistused.";
|
||||
"security_settings_crosssigning_bootstrap" = "Võta risttunnustamine kasutusele";
|
||||
"security_settings_crosssigning_reset" = "Lähtesta risttunnustamine";
|
||||
"security_settings_crosssigning_bootstrap" = "Võta kasutusele";
|
||||
"security_settings_crosssigning_reset" = "Taasta algolek";
|
||||
"security_settings_crosssigning_complete_security" = "Vormista turvaseadistused lõpuni";
|
||||
"security_settings_advanced" = "KEERUKAMAD SEADISTUSED";
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_info" = "Sisesta turvafraas, mida vaid sina tead ning loo võti varukoopia jaoks.";
|
||||
"key_backup_recover_from_passphrase_recover_action" = "Võta ajalugu lukust lahti";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Kas sa ei tea oma taastamiseks mõeldud paroolifraasi? Siis sa võid ";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "kasutada oma taastevõtit";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Kas sa ei tea oma turvafraasi? Siis sa võid ";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "kasutada oma turvavõtit";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part3" = ".";
|
||||
"key_backup_recover_from_recovery_key_info" = "Selleks, et krüptitud sõnumite ajalugu lukust lahti võtta, kasuta oma taastevõtit";
|
||||
"key_backup_recover_from_recovery_key_info" = "Selleks, et krüptitud sõnumite ajalugu lukust lahti võtta, kasuta oma turvavõtit";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_title" = "Sisesta";
|
||||
"key_backup_recover_from_recovery_key_recover_action" = "Võta ajalugu lukust lahti";
|
||||
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Kas sa kaotasid oma taastevõtme? Sa võid seadistustes määrata uue.";
|
||||
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Kas sa kaotasid oma turvavõtme? Sa võid seadistustes määrata uue.";
|
||||
"key_backup_recover_success_info" = "Varukoopiast taastatud!";
|
||||
"key_backup_recover_done_action" = "Valmis";
|
||||
"sign_out_existing_key_backup_alert_title" = "Kas sa oled kindel, et soovid välja logida?";
|
||||
@@ -879,7 +879,7 @@
|
||||
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_sign_out_action" = "Logi välja";
|
||||
"sign_out_non_existing_key_backup_sign_out_confirmation_alert_backup_action" = "Tee varukoopia";
|
||||
"sign_out_key_backup_in_progress_alert_title" = "Parasjagu varundan võtmeid. Kui sa logid nüüd välja, siis sa kaotad ligipääsu kõikidele oma krüptitud sõnumitele.";
|
||||
"secrets_recovery_with_passphrase_title" = "Taastamiseks mõeldud paroolifraas";
|
||||
"secrets_recovery_with_passphrase_title" = "Turvafraas";
|
||||
"pin_protection_choose_pin" = "Turvaliseks ligipääsuks seadista PIN-kood";
|
||||
"pin_protection_confirm_pin" = "Korda PIN-koodi";
|
||||
"pin_protection_confirm_pin_to_disable" = "PIN-koodi kasutuselt eemaldamiseks korda PIN-koodi";
|
||||
@@ -902,14 +902,14 @@
|
||||
"room_participants_action_security_status_complete_security" = "Vormista turvaseadistused lõpuni";
|
||||
"room_warning_about_encryption" = "Läbiv krüptimine on veel testimisjärgus ja ei pruugi veel olla täiesti töökindel.\n\nSeda funktsionaalsust ei saa veel täies mahus usaldada.\n\nSeadmed ei suuda veel dekrüptida jututoa vestlusajalugu, mis pärineb jututoaga liitumise eelsest ajast.\n\nKrüptitud sõnumid pole loetavad klientides ja seadmetes, kus krüptimine pole veel toetatud.";
|
||||
"secure_key_backup_setup_intro_use_security_key_info" = "Loome turvavõtme, mida sa peaksid hoidma turvalises kohas, nagu näiteks arvutis salasõnade halduris või vana kooli seifis.";
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Täiendavaks krüptimiseks kasuta paroolifraasi";
|
||||
"key_backup_recover_from_passphrase_info" = "Selleks, et krüptitud sõnumite ajalugu lukust lahti võtta, kasuta oma taastamiseks mõeldud paroolifraasi";
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_title" = "Täiendavaks krüptimiseks kasuta turvafraasi";
|
||||
"key_backup_recover_from_passphrase_info" = "Selleks, et krüptitud sõnumite ajalugu lukust lahti võtta, kasuta oma taastamiseks mõeldud turvafraasi";
|
||||
"key_backup_recover_from_passphrase_passphrase_title" = "Sisesta";
|
||||
"device_verification_self_verify_wait_title" = "Vormista turvaseadistused lõpuni";
|
||||
"device_verification_self_verify_wait_information" = "Verifitseeri see sessioon oma mõnest muust sessioonist ning anna sellega ka ligipääs oma krüptitud sõnumitele.\n\nKasuta viimast Element'i versiooni oma muudes seadmetes:";
|
||||
"device_verification_self_verify_wait_additional_information" = "See toimib Element'is või mõnes teises Matrix'i kliendis, mis oskab risttunnustamist.";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Kasuta taastevõtit";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Kasuta taastamiseks mõeldud paroolifraasi või võtit";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Kasuta turvavõtit";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Kasuta turvafraasi või turvavõtit";
|
||||
"key_verification_verify_sas_title_emoji" = "Võrdle emoji'sid";
|
||||
"key_verification_verify_sas_title_number" = "Võrdle numbreid";
|
||||
"key_verification_verify_sas_cancel_action" = "Nad ei klapi";
|
||||
@@ -982,7 +982,7 @@
|
||||
"settings_security" = "TURVALISUS";
|
||||
"settings_enable_push_notif" = "Teavitused selles seadmes";
|
||||
"settings_key_backup_info" = "Krüptitud sõnumid kasutavad läbivat krüptimist. Ainult sinul ja saaja(te)l on võtmed selliste sõnumite lugemiseks.";
|
||||
"settings_key_backup_info_signout_warning" = "Enne väljalogimist seo see sessioon krüptovõtmete varundusega. Kui sa seda ei tee, siis võid kaotada võtmed, mida kasutatakse vaid siin seadmes.";
|
||||
"settings_key_backup_info_signout_warning" = "Vältimaks nende kaotamist, varunda krüptovõtmed enne väljalogimist.";
|
||||
"settings_discovery_three_pids_management_information_part2" = "Kasutaja seadistused";
|
||||
"settings_discovery_three_pids_management_information_part3" = ".";
|
||||
"settings_discovery_error_message" = "Ilmnes viga. Palun proovi uuesti.";
|
||||
@@ -1015,19 +1015,19 @@
|
||||
"key_backup_setup_passphrase_confirm_passphrase_valid" = "Tore!";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "Paroolifraasid ei klappi mitte";
|
||||
"key_backup_setup_passphrase_set_passphrase_action" = "Loo paroolifraas";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_info" = "Või krüpti oma varukoopia taastevõtmega ning hoia taastevõtit turvalises kohas.";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_action" = "Võta kasutusele taastevõti";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_info" = "Või krüpti oma varukoopia turvavõtmega ning hoia seda turvalises kohas.";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_action" = "Võta kasutusele turvavõti";
|
||||
"key_backup_setup_success_title" = "Õnnestus!";
|
||||
// Success from recovery key
|
||||
"key_backup_setup_success_from_recovery_key_info" = "Sinu krüptovõtmeid parasjagu varundatakse.\n\nTee taastevõtmest koopia ja hoia seda turvalises kohas.";
|
||||
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Taastevõti";
|
||||
"key_backup_setup_success_from_recovery_key_info" = "Sinu krüptovõtmeid parasjagu varundatakse.\n\nTee turvavõtmest koopia ja hoia seda kaitstud kohas.";
|
||||
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Turvavõti";
|
||||
"key_backup_setup_success_from_recovery_key_make_copy_action" = "Tee koopia";
|
||||
"key_backup_setup_success_from_recovery_key_made_copy_action" = "Ma olen juba teinud koopia";
|
||||
"key_backup_recover_title" = "Krüptitud sõnumid";
|
||||
"key_backup_recover_invalid_passphrase_title" = "Vigane taastamiseks mõeldud paroolifraas";
|
||||
"key_backup_recover_invalid_passphrase" = "Selle paroolifraasiga ei õnnestunud varundust dekrüptida: palun kontrolli, kas sa kasutad õiget taastamiseks mõeldud paroolifraasi.";
|
||||
"key_backup_recover_invalid_recovery_key_title" = "Taastevõtmed ei klapi";
|
||||
"key_backup_recover_invalid_recovery_key" = "Selle taastevõtmega ei õnnestunud varundust dekrüptida: palun kontrolli, kas sa kasutad õiget taastevõtit.";
|
||||
"key_backup_recover_invalid_passphrase_title" = "Vigane turvafraas";
|
||||
"key_backup_recover_invalid_passphrase" = "Selle turvafraasiga ei õnnestunud varundust dekrüptida: palun kontrolli, kas sa kasutad õiget turvafraasi.";
|
||||
"key_backup_recover_invalid_recovery_key_title" = "Turvavõtmed ei klapi";
|
||||
"key_backup_recover_invalid_recovery_key" = "Selle turvavõtmega ei õnnestunud varundust dekrüptida: palun kontrolli, kas sa kasutad õiget turvavõtit.";
|
||||
// Recover from private key
|
||||
"key_backup_recover_from_private_key_info" = "Taastan võtmed varundusest…";
|
||||
"user_verification_session_details_information_untrusted_current_user" = "Verifitseeri see sessioon selleks, et teda võiks lugeda usaldusväärseks ja saaks ligipääsu krüptitud sõnumitele:";
|
||||
@@ -1037,26 +1037,26 @@
|
||||
"user_verification_session_details_verify_action_current_user" = "Verifitseeri interaktiivselt";
|
||||
"user_verification_session_details_verify_action_current_user_manually" = "Verifitseeri käsitsi etteantud teksti abil";
|
||||
"user_verification_session_details_verify_action_other_user" = "Verifitseeri käsitsi";
|
||||
"secrets_recovery_with_passphrase_information_default" = "Sisestades taastamiseks mõeldud paroolifraasi, saad ligipääsu oma turvatud sõnumitele ja risttunnustamisega seotud identiteedile, mis lubab teisi sessioone verifitseerida.";
|
||||
"secrets_recovery_with_passphrase_information_verify_device" = "Kasuta taastamiseks mõeldud paroolifraasi selle seadme verifitseerimiseks.";
|
||||
"secrets_recovery_with_passphrase_information_default" = "Sisestades turvafraasi, saad ligipääsu oma turvatud sõnumitele ja risttunnustamisega seotud identiteedile, mis lubab teisi sessioone verifitseerida.";
|
||||
"secrets_recovery_with_passphrase_information_verify_device" = "Selle seadme verifitseerimiseks kasuta oma turvafraasi.";
|
||||
"secrets_recovery_with_passphrase_passphrase_title" = "Sisesta";
|
||||
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Sisesta taastamise paroolifraas";
|
||||
"secrets_recovery_with_passphrase_recover_action" = "Kasuta paroolifraasi";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Kas sa ei tea oma taastamiseks mõeldud paroolifraasi? Siis sa võid ";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "kasutada oma taastevõtit";
|
||||
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Sisesta turvafraas";
|
||||
"secrets_recovery_with_passphrase_recover_action" = "Kasuta turvafraasi";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Kas sa ei tea oma turvafraasi? Siis sa võid ";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "kasutada oma turvavõtit";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Turvahoidla kasutamine ei õnnestu";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Palun kontrolli, et sa sisestasid õige taastamiseks mõeldud paroolifraasi.";
|
||||
"secrets_recovery_with_key_title" = "Taastevõti";
|
||||
"secrets_recovery_with_key_information_default" = "Sisestades oma taastevõtme, saad ligipääsu oma turvatud sõnumitele ja risttunnustamisega seotud identiteedile, mis lubab teisi sessioone verifitseerida.";
|
||||
"secrets_recovery_with_key_information_verify_device" = "Kasuta taastevõtit selle seadme verifitseerimiseks.";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Palun kontrolli, et sa sisestasid õige turvafraasi.";
|
||||
"secrets_recovery_with_key_title" = "Turvavõti";
|
||||
"secrets_recovery_with_key_information_default" = "Sisestades oma turvavõtme, saad ligipääsu oma krüptitud sõnumitele ja risttunnustamisega seotud identiteedile, mis lubab teisi sessioone verifitseerida.";
|
||||
"secrets_recovery_with_key_information_verify_device" = "Kasuta turvavõtit selle seadme verifitseerimiseks.";
|
||||
"secrets_recovery_with_key_recovery_key_title" = "Sisesta";
|
||||
"secrets_recovery_with_key_recovery_key_placeholder" = "Sisesta taastevõti";
|
||||
"secrets_recovery_with_key_recovery_key_placeholder" = "Sisesta turvavõti";
|
||||
"secrets_recovery_with_key_recover_action" = "Kasuta võtit";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_title" = "Turvahoidla kasutamine ei õnnestu";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "Palun kontrolli, et sa sisestasid õige taastevõtme.";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "Palun kontrolli, et sa sisestasid õige turvavõtme.";
|
||||
"secrets_setup_recovery_key_title" = "Salvesta turvavõti";
|
||||
"secrets_setup_recovery_key_information" = "Salvesta oma taastevõti turvalisse kohta. Seda saab kasutada sinu krüptitud sõnumite ja andmete lugemiseks.";
|
||||
"secrets_setup_recovery_key_information" = "Salvesta oma turvavõti kaitstud kohta. Seda saab kasutada sinu krüptitud sõnumite ja andmete lugemiseks.";
|
||||
"secrets_setup_recovery_key_loading" = "Laadime…";
|
||||
"secrets_setup_recovery_key_export_action" = "Salvesta";
|
||||
"secrets_setup_recovery_key_done_action" = "Valmis";
|
||||
@@ -1068,7 +1068,7 @@
|
||||
"secrets_setup_recovery_passphrase_validate_action" = "Valmis";
|
||||
"secrets_setup_recovery_passphrase_confirm_information" = "Kinnituseks sisesta turvafraas uuesti.";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Kinnita";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Sisesta paroolifraas veel üks kord";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Sisesta turvafraas veel üks kord";
|
||||
"cross_signing_setup_banner_title" = "Seadista krüptimine";
|
||||
"cross_signing_setup_banner_subtitle" = "Verifitseeri oma muud seadmed lihtsamini";
|
||||
"major_update_information" = "Meil on hea meel teatada, et oleme muutnud nime! Sinu rakendus on uuendatud ning sa oled oma kontole sisse logitud.";
|
||||
@@ -1107,7 +1107,7 @@
|
||||
"settings_discovery_three_pid_details_cancel_email_validation_action" = "Tühista e-posti aadressi kinnitamine";
|
||||
"settings_discovery_three_pid_details_enter_sms_code_action" = "Sisesta SMS'iga saadetud aktiveerimiskood";
|
||||
"settings_identity_server_description" = "Kasutades ülalkirjeldatud isikutuvastusserverit saad sa otsida tuttavaid ja lasta neil sind leida.";
|
||||
"e2e_key_backup_wrong_version" = "Tuvastasin uue krüptosõnumite võtmete varukoopia.\n\nKui sina ei teinud seda, siis seadista varukoopiale uus paroolifraas.";
|
||||
"e2e_key_backup_wrong_version" = "Tuvastasin uue krüptosõnumite võtmete varukoopia.\n\nKui sina ei teinud seda, siis seadista varukoopiale uus turvafraas.";
|
||||
"e2e_key_backup_wrong_version_button_settings" = "Seadistused";
|
||||
"e2e_key_backup_wrong_version_button_wasme" = "See olin mina";
|
||||
// Bug report
|
||||
@@ -1322,3 +1322,30 @@
|
||||
// Mark: - Spaces
|
||||
|
||||
"space_feature_unavailable_title" = "Kogukonnakeskuseid ei saa veel siin rakenduses kasutada";
|
||||
"side_menu_app_version" = "Versioon %@";
|
||||
"side_menu_action_feedback" = "Tagasiside";
|
||||
"side_menu_action_help" = "Abiteave";
|
||||
"side_menu_action_settings" = "Seadistused";
|
||||
"side_menu_action_invite_friends" = "Kutsu sõpru";
|
||||
|
||||
// Mark: - Side menu
|
||||
|
||||
"side_menu_reveal_action_accessibility_label" = "Vasak paneel";
|
||||
"user_avatar_view_accessibility_hint" = "Muuda kasutaja tunnuspilti ehk avatari";
|
||||
|
||||
// Mark: - User avatar view
|
||||
|
||||
"user_avatar_view_accessibility_label" = "tunnuspilt";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "Jätkamiseks kasuta turvavõtit.";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Jätkamaks sisesta oma salafraas.";
|
||||
|
||||
// Success from secure backup
|
||||
"key_backup_setup_success_from_secure_backup_info" = "Sinu krüptovõtmeid parasjagu varundatakse.";
|
||||
"security_settings_secure_backup_restore" = "Taasta varukoopiast";
|
||||
"security_settings_secure_backup_reset" = "Taasta algolek";
|
||||
"security_settings_secure_backup_info_valid" = "See sessioon varundab sinu krüptovõtmeid.";
|
||||
"security_settings_secure_backup_info_checking" = "Kontrollin…";
|
||||
"settings_ui_theme_picker_message_match_system_theme" = "Automaatne valik kasutab sinu seadme süsteemset teemat";
|
||||
"settings_ui_theme_picker_message_invert_colours" = "Automaatne valik kasutab sinu seadme pööratud värvide seadistust";
|
||||
"room_recents_unknown_room_error_message" = "Ei leia sellist jututuba. Palun kontrolli, et ta ikka olemas on";
|
||||
"room_creation_dm_error" = "Otsevestluse loomine ei õnnestunud. Palun kontrolli, et kasutajanimed oleks õiged ja proovi uuesti.";
|
||||
|
||||
@@ -15,3 +15,6 @@
|
||||
"continue" = "ادامه";
|
||||
"close" = "بستن";
|
||||
"back" = "بازگشت";
|
||||
"store_full_description" = "المنت یک پیامرسان جدید و ابزاری برای همکاری افراد است که:\n\n۱. امکانات کنترلی لازم برای حفاظت از حریم خصوصی را در اختیار شما قرار میدهد\n۲. امکان برقراری ارتباط با هر کسی را بر بستر شبکهی ماتریکس و حتی فراتر از آن، امکان برقراری ارتباط با برنامههای دیگر نظیر Slack را در اختیار شما قرار میدهد\n۳. شما را در برابر تبلیغات، کندوکاو دادههایتان، در پشتی و همچنین یک زیستبوم بسته و محصور محافظت میکند\n۴. شما را از طریق رمزنگاری سرتاسر و همچنین امضاء متقابل برای تائيد دیگران، امن میکند\n\nالمنت یک پیامرسان و ابزار ارتباطی کاملا متفاوت است، چرا که از معماری غیرمتمرکز بهره برده و متنباز است.\n\nالمنت امکان استقرار محلی - یا انتخاب هر میزبان دلخواهی - را به شما داده و از این طریق حریم خصوصی، مالکیت و کنترل دادهها و گفتگوهایتان برای شما به ارمغان میآورد. همچنین دسترسی به یک شبکهی باز را برای شما فراهم کرده، به طوری که مجبور نیستید فقط با کاربران المنت به گفتگو و صحبت بپردازید. در کنار همهی اینها، بسیار امن است.\n\nپشتوانهی قابلیتهای بالا، استفاده از ماتریکس است - یک استاندارد برای ارتباطات غیرمحدود و متمرکز.\n\nالمنت به شما اختیار میدهد سرور گفتگوهای خود را انتخاب کنید. در برنامه المنت، به طرق مختلف میتوانید سرور مورد نظر خود را انتخاب کنید:\n\n۱. ساختن یک حسابکاربری رایگان بر روی سرور عمومی matrix.org\n۲. استقرار محلی و راهاندازی سرور بر روی سختافزار خودتان و ایجاد حساب کاربری بر روی آن\n۳. ایجاد حساب کاربری بر روی یک سرور دلخواه از طریق عضویت در پلتفورم استقرار Element Matrix Services\n\nچرا المنت گزینهی جذابی است؟\n\nمالک حقیقی دادههای خود باشید: شما تصمیم بگیرید دادهها و پیامهایتان کجا ذخیره شوند. المنت مانند برخی MEGACORPها، در دادههای شما کاوش نکرده و آنها را در اختیار نفر هویت ثالثی قرار نمیدهد.\n\nپیامرسانی و ارتباطات باز: شما میتوانید با هر کسی بر بستر ماتریکس ارتباط بگیرید، فارغ از اینکه از کدام کلاینت ماتریکسی استفاده میکنند؛ حتی فراتر، شما میتوانید افراد بر بستر سازوکارهای پیامرسانی دیگر نظیر Slack، XMPP و یا IRC نیز ارتباط برقرار نمائید.\n\nفوقالعاده امن: رمزنگاری سرتاسر واقعی (فقط افرادی که در جریان گفتگو هستند امکان رمزگشایی پیامها را دارند)، به همراه قابلیت امضاء متقابل برای تائید دستگاه و هویت طرفهای گفتگو.\n\nپکیج ارتباطی کامل: پیامرسانی، تماسهای صوتی و تصویری، ارسال فایل، به اشتراکگذاری صفحه نمایش و یک طیف گستردهای از یکپارچهسازیها، باتها و ابزارکها. اتاقها و فضاهای کاری مختلف بسازید و برای به سرانجام رسیدن امور، در ارتباط باشید.\n\nحاضر در همه جا: هرجا و هر زمان در دسترس بوده و پیامهای خود را به صورت همگامسازیشده بر روی دستگاههای مختلف در اختیار داشته باشید.";
|
||||
// String for App Store
|
||||
"store_short_description" = "ارتباط امن غیرمتمرکز";
|
||||
|
||||
@@ -622,7 +622,7 @@
|
||||
"key_backup_recover_banner_title_part1" = "Lancer la récupération de messages sécurisée";
|
||||
"key_backup_recover_banner_title_part2" = " pour lire l'historique des messages chiffrés sur cet appareil";
|
||||
"settings_key_backup_info" = "Les messages chiffrés sont sécurisés avec un chiffrement de bout en bout. Seuls vous et le(s) destinataire(s) avez les clés pour lire ces messages.";
|
||||
"settings_key_backup_info_signout_warning" = "Connectez cette session à la sauvegarde de clés avant de vous déconnecter pour éviter de perdre les clés qui ne seraient que sur cet appareil.";
|
||||
"settings_key_backup_info_signout_warning" = "Sauvegardez vos clés avant de vous déconnecter pour éviter de les perdre.";
|
||||
"settings_key_backup_button_use" = "Utiliser la sauvegarde de clés";
|
||||
"key_backup_setup_intro_setup_action_without_existing_backup" = "Commencer à utiliser la sauvegarde de clés";
|
||||
"key_backup_setup_intro_setup_action_with_existing_backup" = "Utiliser la sauvegarde de clés";
|
||||
@@ -1050,9 +1050,9 @@
|
||||
"security_settings_crosssigning_info_not_bootstrapped" = "La signature croisée n’est pas encore configurée.";
|
||||
"security_settings_crosssigning_info_exists" = "Votre compte a une identité de signature croisée, mais cette session ne lui fait pas encore confiance. Améliorez la sécurité de cette session.";
|
||||
"security_settings_crosssigning_info_trusted" = "La signature croisée est activée. Vous pouvez faire confiance à d’autres utilisateurs et à vos autres sessions selon la signature croisée mais vous ne pouvez pas effectuer des signatures croisées depuis cette session car elle n’a pas de clés privées de signature croisée. Améliorez la sécurité de cette session.";
|
||||
"security_settings_crosssigning_info_ok" = "La signature croisée est activée.";
|
||||
"security_settings_crosssigning_bootstrap" = "Configurer la signature croisée";
|
||||
"security_settings_crosssigning_reset" = "Réinitialiser la signature croisée";
|
||||
"security_settings_crosssigning_info_ok" = "La signature croisée est prête à être utilisée.";
|
||||
"security_settings_crosssigning_bootstrap" = "Configurer";
|
||||
"security_settings_crosssigning_reset" = "Réinitialiser";
|
||||
"security_settings_crosssigning_complete_security" = "Compléter la sécurité";
|
||||
"security_settings_complete_security_alert_title" = "Améliorer la sécurité";
|
||||
"security_settings_complete_security_alert_message" = "Vous devriez d’abord améliorer la sécurité de votre session actuelle.";
|
||||
@@ -1148,10 +1148,10 @@
|
||||
"secure_backup_setup_banner_subtitle" = "Protection afin d’éviter de perdre l’accès aux messages et données chiffrés";
|
||||
"security_settings_crypto_sessions_description_2" = "Si vous ne reconnaissez pas une connexion, changez votre mot de passe et réinitialisez la sauvegarde sécurisée.";
|
||||
"security_settings_secure_backup" = "SAUVEGARDE SÉCURISÉE";
|
||||
"security_settings_secure_backup_description" = "Protection afin d’éviter de perdre l’accès aux messages et données chiffrés en sauvegardant les clés de chiffrement sur votre serveur.";
|
||||
"security_settings_secure_backup_description" = "Sauvegardez vos clés de chiffrement et les données de votre compte au où vous perdriez l’accès à vos sessions. Vos clés seront protégées par une clé de sécurité unique.";
|
||||
"security_settings_secure_backup_setup" = "Configurer";
|
||||
"security_settings_secure_backup_synchronise" = "Synchroniser";
|
||||
"security_settings_secure_backup_delete" = "Supprimer";
|
||||
"security_settings_secure_backup_delete" = "Supprimer la sauvegarde";
|
||||
"security_settings_user_password_description" = "Confirmez votre identité en saisissant le mot de passe de votre compte";
|
||||
"secure_key_backup_setup_existing_backup_error_title" = "Une sauvegarde pour les messages existe déjà";
|
||||
"secure_key_backup_setup_existing_backup_error_info" = "Déverrouillez-la pour la réutiliser dans la sauvegarde sécurisée ou supprimez-la pour créer une nouvelle sauvegarde de messages dans la sauvegarde sécurisée.";
|
||||
@@ -1399,3 +1399,30 @@
|
||||
// Mark: - Spaces
|
||||
|
||||
"space_feature_unavailable_title" = "Les espaces ne sont pas encore pris en charge";
|
||||
"side_menu_app_version" = "Version %@";
|
||||
"side_menu_action_feedback" = "Remarques";
|
||||
"side_menu_action_help" = "Aide";
|
||||
"side_menu_action_settings" = "Paramètres";
|
||||
"side_menu_action_invite_friends" = "Inviter des amis";
|
||||
|
||||
// Mark: - Side menu
|
||||
|
||||
"side_menu_reveal_action_accessibility_label" = "Panneau de gauche";
|
||||
"user_avatar_view_accessibility_hint" = "Change l’avatar de l’utilisateur";
|
||||
|
||||
// Mark: - User avatar view
|
||||
|
||||
"user_avatar_view_accessibility_label" = "avatar";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "Saisissez votre clé de sécurité pour poursuivre.";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Saisissez votre phrase secrète de récupération pour poursuivre.";
|
||||
|
||||
// Success from secure backup
|
||||
"key_backup_setup_success_from_secure_backup_info" = "Vos clés sont en cours de sauvegarde.";
|
||||
"security_settings_secure_backup_restore" = "Restaurer depuis une sauvegarde";
|
||||
"security_settings_secure_backup_reset" = "Réinitialiser";
|
||||
"security_settings_secure_backup_info_valid" = "Cette session sauvegarde vos clés.";
|
||||
"security_settings_secure_backup_info_checking" = "Vérification…";
|
||||
"settings_ui_theme_picker_message_match_system_theme" = "« Auto » s’aligne avec le thème de votre appareil";
|
||||
"settings_ui_theme_picker_message_invert_colours" = "« Auto » utilise le paramètre « Inverser les couleurs » de l’appreil";
|
||||
"room_recents_unknown_room_error_message" = "Aucun résultat dans ce salon. Assurez vous de son existence";
|
||||
"room_creation_dm_error" = "Nous n’avons pas pu créer votre message direct. Merci de vérifier les utilisateurs que vous voulez inviter et réessayer.";
|
||||
|
||||
@@ -599,7 +599,7 @@
|
||||
"key_backup_setup_passphrase_confirm_passphrase_title" = "Megerősítés";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "Jelmondat megerősítése";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_valid" = "Szuper!";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "A jelmondatok nem egyeznek meg";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "a jelmondatok nem egyeznek meg";
|
||||
"key_backup_setup_passphrase_set_passphrase_action" = "Jelmondat beállítása";
|
||||
"key_backup_setup_recovery_key_info" = "Erről a Visszaállítási Kulcsról készíts egy másolatot és őrizd meg biztonságos helyen.\n\nEz egy további biztosíték, amivel újra hozzáférhetsz a titkosított üzeneteidhez ha elfelejtenéd a Visszaállítási Jelmondatot.";
|
||||
"key_backup_setup_recovery_key_recovery_key_title" = "Visszaállítási Kulcs";
|
||||
@@ -608,18 +608,18 @@
|
||||
"key_backup_recover_title" = "Biztonságos Üzenetek";
|
||||
"key_backup_recover_empty_backup_title" = "Üres mentés";
|
||||
"key_backup_recover_empty_backup_message" = "Nincs mentendő kulcs";
|
||||
"key_backup_recover_from_passphrase_info" = "Használd a visszaállítási jelmondatot, hogy újra hozzáférj a biztonságos üzeneteidhez";
|
||||
"key_backup_recover_from_passphrase_info" = "Használd a Biztonsági jelmondatot, hogy újra hozzáférj a biztonságos üzeneteidhez";
|
||||
"key_backup_recover_from_passphrase_passphrase_title" = "Bevitel";
|
||||
"key_backup_recover_from_passphrase_passphrase_placeholder" = "Jelmondat bevitele";
|
||||
"key_backup_recover_from_passphrase_recover_action" = "Újra hozzáférés a régi üzenetekhez";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Nem emlékszel a visszaállítási jelmondatodra? Használhatod a ";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "visszaállítási kulcsot";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Nem emlékszel a Biztonsági jelmondatodra? Használhatod a ";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "Biztonsági kulcsot";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part3" = ".";
|
||||
"key_backup_recover_from_recovery_key_info" = "Használd a visszaállítási kulcsod, hogy újra hozzáférhess a biztonságos üzeneteidhez";
|
||||
"key_backup_recover_from_recovery_key_info" = "Használd a Biztonsági kulcsod, hogy újra hozzáférhess a biztonságos üzeneteidhez";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_title" = "Bevitel";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Visszaállítási Kulcs megadása";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Biztonsági Kulcs megadása";
|
||||
"key_backup_recover_from_recovery_key_recover_action" = "Hozzáférés a régi üzenetekhez";
|
||||
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Elvesztetted a visszaállítási kulcsod? A beállításokban készíthetsz egy újat.";
|
||||
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Elvesztetted a Biztonsági kulcsod? A beállításokban készíthetsz egy újat.";
|
||||
"key_backup_recover_success_info" = "Mentés visszaállítva!";
|
||||
"key_backup_recover_done_action" = "Kész";
|
||||
"key_backup_setup_banner_title_part1" = "Biztonságos Üzenet Visszaállítás beállítása";
|
||||
@@ -627,27 +627,27 @@
|
||||
"key_backup_recover_banner_title_part1" = "Biztonságos Üzenet Visszaállítás futtatása";
|
||||
"key_backup_recover_banner_title_part2" = " , hogy elolvashasd a titkosított üzeneteidet ezen az eszközön";
|
||||
"settings_key_backup_info" = "Titkosított üzenetek végponttól-végpontig vannak titkosítva. Csak te és a címzettek rendelkeznek a visszafejtéshez szükséges kulcsokkal.";
|
||||
"settings_key_backup_info_signout_warning" = "Állítsd be ezen az munkameneten a Kulcs Mentést kijelentkezés előtt, hogy ne veszíts el olyan kulcsot ami csak ezen az eszközön van meg.";
|
||||
"settings_key_backup_info_signout_warning" = "Töltsd fel kulcsaidat a szerverre mielőtt kijelentkezel, hogy ne veszítsd el őket.";
|
||||
"settings_key_backup_button_use" = "Kulcs mentés használata";
|
||||
"key_backup_setup_intro_setup_action_without_existing_backup" = "Kulcs mentés használata";
|
||||
"key_backup_setup_intro_setup_action_with_existing_backup" = "Használd a Kulcs mentést";
|
||||
"key_backup_setup_passphrase_title" = "Védd a mentést jelmondattal";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_info" = "Vagy védd a mentést egy Visszaállítási Kulccsal és tedd el egy biztonságos helyre.";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Haladó) Visszaállítási Kulcs beállítása";
|
||||
"key_backup_setup_passphrase_title" = "Védd a mentést Biztonsági jelmondattal";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_info" = "Vagy védd a mentést egy Biztonsági Kulccsal és tedd el egy biztonságos helyre.";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_action" = "(Haladó) Biztonsági Kulcs beállítása";
|
||||
"key_backup_setup_success_title" = "Sikerült!";
|
||||
// Success from passphrase
|
||||
"key_backup_setup_success_from_passphrase_info" = "A kulcsaid elmentésre kerülnek.\n\nA Visszaállítási Kulcs egy olyan biztonsági elem amivel akkor is visszaállíthatod a hozzáférésed a titkosított üzenetekhez ha a jelmondatot elfelejted.\n\nA Visszaállítási kulcsot biztonságos helyen tárold, mint pl. egy jelszókezelőben (vagy széfben).";
|
||||
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Visszaállítási Kulcs beállítása";
|
||||
"key_backup_setup_success_from_passphrase_info" = "A kulcsaid elmentésre kerülnek.\n\nA Biztonsági Kulcs egy olyan biztonsági elem amivel akkor is visszaállíthatod a hozzáférésed a titkosított üzenetekhez ha a jelmondatot elfelejted.\n\nA Biztonsági kulcsot biztonságos helyen tárold, mint pl. egy jelszókezelőben (vagy széfben).";
|
||||
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Biztonsági Kulcs beállítása";
|
||||
"key_backup_setup_success_from_passphrase_done_action" = "Kész";
|
||||
// Success from recovery key
|
||||
"key_backup_setup_success_from_recovery_key_info" = "A kulcsaid elmentésre kerülnek.\n\nMásold ki a Visszaállítási Kulcsot és tárold biztonságos helyen.";
|
||||
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Visszaállítási Kulcs";
|
||||
"key_backup_setup_success_from_recovery_key_info" = "A kulcsaid elmentésre kerülnek.\n\nMásold ki a Biztonsági Kulcsot és tárold biztonságos helyen.";
|
||||
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Biztonsági Kulcs";
|
||||
"key_backup_setup_success_from_recovery_key_make_copy_action" = "Készíts másolatot";
|
||||
"key_backup_setup_success_from_recovery_key_made_copy_action" = "Készítettem másolatot";
|
||||
"key_backup_recover_invalid_passphrase_title" = "Helytelen Visszaállítási Jelmondat";
|
||||
"key_backup_recover_invalid_passphrase" = "A mentést nem lehet visszafejteni ezzel a jelmondattal: kérlek ellenőrizd, hogy a megfelelő visszaállítási jelmondatot adtad-e meg.";
|
||||
"key_backup_recover_invalid_recovery_key_title" = "A Visszaállítási Kulcsok nem egyeznek meg";
|
||||
"key_backup_recover_invalid_recovery_key" = "A mentést nem lehet ezzel a kulccsal visszafejteni: kérlek ellenőrizd, hogy a megfelelő kulcsot adtad-e meg.";
|
||||
"key_backup_recover_invalid_passphrase_title" = "Helytelen Biztonsági Jelmondat";
|
||||
"key_backup_recover_invalid_passphrase" = "A mentést nem lehet visszafejteni ezzel a jelmondattal: kérlek ellenőrizd, hogy a megfelelő Biztonsági jelmondatot adtad-e meg.";
|
||||
"key_backup_recover_invalid_recovery_key_title" = "A Biztonsági Kulcsok nem egyeznek meg";
|
||||
"key_backup_recover_invalid_recovery_key" = "A mentést nem lehet ezzel a kulccsal visszafejteni: kérlek ellenőrizd, hogy a megfelelő Biztonsági kulcsot adtad-e meg.";
|
||||
"key_backup_setup_banner_title" = "Soha ne veszítsd el a titkosított üzeneteidet";
|
||||
"key_backup_setup_banner_subtitle" = "Kulcs mentés használata";
|
||||
"key_backup_recover_banner_title" = "Soha ne veszítsd el a titkosított üzeneteidet";
|
||||
@@ -1057,9 +1057,9 @@
|
||||
"security_settings_crosssigning_info_not_bootstrapped" = "Az eszközök közötti hitelesítés nincs még beállítva.";
|
||||
"security_settings_crosssigning_info_exists" = "A fiókodban az eszközök közötti aláírás be van állítva, de ebben a munkamenetben még nem ellenőrizted. Végezd el a munkamenet biztonsági beállításait.";
|
||||
"security_settings_crosssigning_info_trusted" = "Eszközök közötti hitelesítés engedélyezve van. Megbízhatsz más felhasználókban és a munkameneteidben az aláírást felhasználva de ebből a munkamenetből nem tudsz aláírni mert az eszközök közötti aláíráshoz hiányzik a privát kulcs. Fejezd be a munkamenet biztonsági beállításait.";
|
||||
"security_settings_crosssigning_info_ok" = "Eszközök közti hitelesítés engedélyezve.";
|
||||
"security_settings_crosssigning_bootstrap" = "Eszközök közötti hitelesítés beállítása";
|
||||
"security_settings_crosssigning_reset" = "Eszközök közötti hitelesítés alaphelyzetbe állítása";
|
||||
"security_settings_crosssigning_info_ok" = "Eszközök közötti hitelesítés kész a használatra.";
|
||||
"security_settings_crosssigning_bootstrap" = "Beállítás";
|
||||
"security_settings_crosssigning_reset" = "Visszaállít";
|
||||
"security_settings_crosssigning_complete_security" = "Biztonsági beállítás befejezése";
|
||||
"security_settings_complete_security_alert_title" = "Biztonsági beállítás befejezése";
|
||||
"security_settings_complete_security_alert_message" = "Először be kell fejezned ennek a munkamenetnek a biztonsági beállítását.";
|
||||
@@ -1100,32 +1100,32 @@
|
||||
"key_verification_manually_verify_device_additional_information" = "Ha nem egyeznek akkor a kommunikációtok biztonsága veszélyben lehet.";
|
||||
"key_verification_manually_verify_device_validate_action" = "Ellenőriz";
|
||||
"user_verification_session_details_verify_action_current_user_manually" = "Manuális szöveges ellenőrzés";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Használd a Visszaállítási Kulcsot";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Használd a Visszaállítási Jelmondatot vagy Kulcsot";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Használd a Biztonsági Kulcsot";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Használd a Biztonsági Jelmondatot vagy Kulcsot";
|
||||
"device_verification_self_verify_wait_recover_secrets_additional_information" = "Ha nem érsz el létező munkamenetet";
|
||||
"secrets_recovery_with_passphrase_title" = "Visszaállítási Jelmondat";
|
||||
"secrets_recovery_with_passphrase_information_default" = "A visszaállítási jelmondat megadásával hozzáférhetsz a titkosított üzeneteidhez és az eszközök közötti aláírásnál használt személyazonosságodhoz hogy más munkameneteket ellenőrizhess.";
|
||||
"secrets_recovery_with_passphrase_information_verify_device" = "Használd a visszaállítási jelmondatot az eszköz ellenőrzésére.";
|
||||
"secrets_recovery_with_passphrase_title" = "Biztonsági Jelmondat";
|
||||
"secrets_recovery_with_passphrase_information_default" = "A Biztonsági jelmondat megadásával hozzáférhetsz a titkosított üzeneteidhez és az eszközök közötti aláírásnál használt személyazonosságodhoz hogy más munkameneteket ellenőrizhess.";
|
||||
"secrets_recovery_with_passphrase_information_verify_device" = "Használd a Biztonsági jelmondatot az eszköz ellenőrzésére.";
|
||||
"secrets_recovery_with_passphrase_passphrase_title" = "Bevitel";
|
||||
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Visszaállítási jelmondat megadása";
|
||||
"secrets_recovery_with_passphrase_passphrase_placeholder" = "Biztonsági jelmondat megadása";
|
||||
"secrets_recovery_with_passphrase_recover_action" = "Használd a jelmondatot";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Nem emlékszel a visszaállítási jelmondatodra? Használhatod a ";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "visszaállítási kulcs használata";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Nem emlékszel a Biztonsági jelmondatodra? Használhatod a ";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "Biztonsági kulcs használata";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "A biztonsági tárolót nem sikerült elérni";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Kérlek ellenőrizd, hogy a visszaállítási jelmondatot helyesen írtad be.";
|
||||
"secrets_recovery_with_key_title" = "Visszaállítási Kulcs";
|
||||
"secrets_recovery_with_key_information_default" = "A visszaállítási kulcs megadásával hozzáférhetsz a biztonságos üzeneteidhez és az eszközök közötti hitelesítéshez használt személyazonosságodhoz, hogy más munkameneteket hitelesíthess.";
|
||||
"secrets_recovery_with_key_information_verify_device" = "Használd a visszaállítási kulcsot az eszköz ellenőrzésére.";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Kérlek ellenőrizd, hogy a Biztonsági jelmondatot helyesen írtad be.";
|
||||
"secrets_recovery_with_key_title" = "Biztonsági Kulcs";
|
||||
"secrets_recovery_with_key_information_default" = "A Biztonsági kulcs megadásával hozzáférhetsz a biztonságos üzeneteidhez és az eszközök közötti hitelesítéshez használt személyazonosságodhoz, hogy más munkameneteket hitelesíthess.";
|
||||
"secrets_recovery_with_key_information_verify_device" = "Használd a Biztonsági kulcsot az eszköz ellenőrzésére.";
|
||||
"secrets_recovery_with_key_recovery_key_title" = "Bevitel";
|
||||
"secrets_recovery_with_key_recovery_key_placeholder" = "Visszaállítási Kulcs megadása";
|
||||
"secrets_recovery_with_key_recovery_key_placeholder" = "Biztonsági Kulcs megadása";
|
||||
"secrets_recovery_with_key_recover_action" = "Használd a kulcsot";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_title" = "A biztonsági tárolót nem sikerült elérni";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "Kérlek ellenőrizd, hogy a visszaállítási kulcsot helyesen írtad be.";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "Kérlek ellenőrizd, hogy a Biztonsági kulcsot helyesen írtad be.";
|
||||
"security_settings_secure_backup" = "BIZTONSÁGI MENTÉS";
|
||||
"security_settings_secure_backup_setup" = "Beállítás";
|
||||
"security_settings_secure_backup_synchronise" = "Szinkronizál";
|
||||
"security_settings_secure_backup_delete" = "Töröl";
|
||||
"security_settings_secure_backup_delete" = "Mentés törlése";
|
||||
"security_settings_user_password_description" = "A fiók jelszó megadásával erősítsd meg a személyazonosságodat";
|
||||
"secure_key_backup_setup_intro_title" = "Biztonsági Mentés";
|
||||
"secure_key_backup_setup_intro_info" = "A titkosított üzenetekhez és adatokhoz való hozzáférés elvesztése esetén használható biztonsági tartalék a titkosított kulcsok a szerveredre való elmentésével.";
|
||||
@@ -1154,7 +1154,7 @@
|
||||
"cross_signing_setup_banner_title" = "Titkosítás beállítása";
|
||||
"cross_signing_setup_banner_subtitle" = "A többi eszközödet ellenőrizd egyszerűen";
|
||||
"security_settings_crypto_sessions_description_2" = "Ha ez a bejelentkezés nem ismerős, akkor változtasd meg a jelszavad és újra állítsd be a Biztonsági Mentést.";
|
||||
"security_settings_secure_backup_description" = "A titkosított üzenetekhez és adatokhoz való hozzáférés elvesztése esetén használható biztonsági tartalék a titkosított kulcsok a szerveredre való elmentésével.";
|
||||
"security_settings_secure_backup_description" = "Mentsd el a titkosítási kulcsokat a fiókadatokkal arra az esetre ha elvesztenéd a hozzáférést a munkameneteidhez. A kulcsok egy egyedi Biztonsági Kulccsal lesznek védve.";
|
||||
// AuthenticatedSessionViewControllerFactory
|
||||
"authenticated_session_flow_not_supported" = "Ez az alkalmazás nem támogatja a matrix szervered azonosítási mechanizmusát.";
|
||||
// Events formatter with you
|
||||
@@ -1164,7 +1164,7 @@
|
||||
"event_formatter_jitsi_widget_removed_by_you" = "Törölted a VoIP konferenciát";
|
||||
"secure_key_backup_setup_intro_use_security_passphrase_info" = "Adj meg olyan biztonsági jelmondatot amit csak te ismersz és generálj egy kulcsot a mentéshez.";
|
||||
"secure_key_backup_setup_existing_backup_error_info" = "Old fel, hogy a biztonsági mentéshez tudd használni vagy töröld, hogy új üzenet mentést állíthass be a biztonsági mentésben.";
|
||||
"secrets_setup_recovery_key_information" = "A Visszaállítási Kulcsot tárold valahol biztonságos helyen. Felhasználható a titkosított üzenetek és adatok hozzáféréshez.";
|
||||
"secrets_setup_recovery_key_information" = "A Biztonsági Kulcsot tárold valahol biztonságos helyen. Felhasználható a titkosított üzenetek és adatok hozzáféréshez.";
|
||||
"secrets_setup_recovery_key_storage_alert_message" = "✓Nyomtasd ki és tárold biztonságos helyen\n✓Mentsd egy USB kulcsra vagy biztonsági mentésbe\n✓Másold a saját felhő tárhelyedre";
|
||||
"secrets_setup_recovery_passphrase_information" = "Add meg a biztonsági jelmondatot amit csak te tudsz és a titkok biztosításához használod a szervereden.";
|
||||
"major_update_title" = "Riot mostantól Element";
|
||||
@@ -1385,3 +1385,30 @@
|
||||
// Mark: - Spaces
|
||||
|
||||
"space_feature_unavailable_title" = "A Terek még nem érhetők el";
|
||||
"side_menu_app_version" = "Verzió %@";
|
||||
"side_menu_action_feedback" = "Visszajelzés";
|
||||
"side_menu_action_help" = "Segítség";
|
||||
"side_menu_action_settings" = "Beállítások";
|
||||
"side_menu_action_invite_friends" = "Ismerősök meghívása";
|
||||
|
||||
// Mark: - Side menu
|
||||
|
||||
"side_menu_reveal_action_accessibility_label" = "Bal panel";
|
||||
"user_avatar_view_accessibility_hint" = "Felhasználó profilkép megváltoztatása";
|
||||
|
||||
// Mark: - User avatar view
|
||||
|
||||
"user_avatar_view_accessibility_label" = "profilkép";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "Add meg a Biztonsági kulcsot a folytatáshoz.";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Add meg a Biztonsági jelmondatot a továbblépéshez.";
|
||||
|
||||
// Success from secure backup
|
||||
"key_backup_setup_success_from_secure_backup_info" = "A kulcsaid mentésre kerülnek.";
|
||||
"security_settings_secure_backup_restore" = "Visszaállítás mentésből";
|
||||
"security_settings_secure_backup_reset" = "Visszaállít";
|
||||
"security_settings_secure_backup_info_valid" = "Ez a munkamenet elmenti a kulcsaidat.";
|
||||
"security_settings_secure_backup_info_checking" = "Ellenőrzés…";
|
||||
"settings_ui_theme_picker_message_match_system_theme" = "„Auto” megfelel az eszközöd rendszer témájának";
|
||||
"settings_ui_theme_picker_message_invert_colours" = "„Autó” az eszközöd „invertált színek” beállítását használja";
|
||||
"room_recents_unknown_room_error_message" = "A szoba nem található. Győződj meg róla, hogy létezik";
|
||||
"room_creation_dm_error" = "Nem lehet elkészíteni a közvetlen beszélgetést. Ellenőrizd a meghívni kívánt felhasználót és próbáld újra.";
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
|
||||
"auth_invalid_login_param" = "Nama pengguna dan/atau kata sandi tidak benar";
|
||||
"auth_identity_server_placeholder" = "URL (contoh https://vector.im)";
|
||||
"auth_home_server_placeholder" = "URL (contoh https://matrix.org)";
|
||||
"auth_repeat_new_password_placeholder" = "Konfirmasi kata sandi baru Anda";
|
||||
"auth_repeat_password_placeholder" = "Ulangi kata sandi";
|
||||
"auth_phone_placeholder" = "Nomor telepon";
|
||||
"auth_optional_phone_placeholder" = "Nomor telepon (opsional)";
|
||||
"auth_email_placeholder" = "Alamat surel";
|
||||
"auth_optional_email_placeholder" = "Alamat surel (opsional)";
|
||||
"auth_user_name_placeholder" = "Nama pengguna";
|
||||
"auth_new_password_placeholder" = "Kata sandi baru";
|
||||
"auth_password_placeholder" = "Kata sandi";
|
||||
"auth_user_id_placeholder" = "Surel atau nama pengguna";
|
||||
"auth_return_to_login" = "Kembali ke layar masuk";
|
||||
"auth_login_single_sign_on" = "Masuk";
|
||||
"auth_skip" = "Lewati";
|
||||
"auth_register" = "Daftar";
|
||||
|
||||
// Authentication
|
||||
"auth_login" = "Masuk";
|
||||
"callbar_return" = "Kembali";
|
||||
"callbar_only_multiple_paused" = "%@ panggilan dijeda";
|
||||
"callbar_only_single_paused" = "Panggilan dijeda";
|
||||
"callbar_active_and_multiple_paused" = "1 panggilan aktif (%@) • %@ panggilan dijeda";
|
||||
"callbar_active_and_single_paused" = "1 panggilan aktif (%@) • 1 panggilan dijeda";
|
||||
|
||||
// Call Bar
|
||||
"callbar_only_single_active" = "Ketuk untuk kembali ke panggilan (%@)";
|
||||
"less" = "Lebih sedikit";
|
||||
"more" = "Lebih banyak";
|
||||
"switch" = "Beralih";
|
||||
"skip" = "Lewati";
|
||||
"close" = "Tutup";
|
||||
"sending" = "Mengirim";
|
||||
"send_to" = "Kirim ke %@";
|
||||
"rename" = "Ubah nama";
|
||||
"later" = "Nanti";
|
||||
"active_call_details" = "Panggilan Aktif (%@)";
|
||||
"active_call" = "Panggilan Aktif";
|
||||
"video" = "Video";
|
||||
"voice" = "Suara";
|
||||
"camera" = "Kamera";
|
||||
"preview" = "Tinjauan";
|
||||
"accept" = "Terima";
|
||||
"decline" = "Tolak";
|
||||
"join" = "Bergabung";
|
||||
"save" = "Simpan";
|
||||
"cancel" = "Batal";
|
||||
"off" = "Nonaktif";
|
||||
"on" = "Aktif";
|
||||
"retry" = "Coba lagi";
|
||||
"invite" = "Undang";
|
||||
"remove" = "Hapus";
|
||||
"leave" = "Tinggalkan";
|
||||
"start" = "Mulai";
|
||||
"create" = "Buat";
|
||||
"continue" = "Lanjut";
|
||||
"back" = "Kembali";
|
||||
"next" = "Selanjutnya";
|
||||
|
||||
// Actions
|
||||
"view" = "Lihat";
|
||||
"warning" = "Peringatan";
|
||||
"title_groups" = "Komunitas-komunitas";
|
||||
"title_rooms" = "Ruangan-ruangan";
|
||||
"title_people" = "Orang-orang";
|
||||
"title_favourites" = "Favorit";
|
||||
|
||||
// Titles
|
||||
"title_home" = "Beranda";
|
||||
@@ -589,7 +589,7 @@
|
||||
"settings_key_backup_info" = "Versleutelde berichten worden beveiligd met eind-tot-eind-versleuteling. Enkel de ontvanger(s) en u hebben de sleutels om deze berichten te lezen.";
|
||||
"settings_key_backup_info_checking" = "Bezig met controleren…";
|
||||
"settings_key_backup_info_none" = "Uw sleutels worden niet geback-upt vanaf dit apparaat.";
|
||||
"settings_key_backup_info_signout_warning" = "Verbind dit apparaat met de sleutelback-up vooraleer u zich afmeldt om sleutels die enkel op dit apparaat staat niet te verliezen.";
|
||||
"settings_key_backup_info_signout_warning" = "Maak een back-up van uw sleutels voordat u zich afmeldt om ze niet te verliezen.";
|
||||
"settings_key_backup_info_version" = "Sleutelback-upversie: %@";
|
||||
"settings_key_backup_info_algorithm" = "Algoritme: %@";
|
||||
"settings_key_backup_info_valid" = "Dit apparaat maakt een back-up van uw sleutels.";
|
||||
@@ -1485,3 +1485,30 @@
|
||||
// Mark: - Spaces
|
||||
|
||||
"space_feature_unavailable_title" = "Spaces is nog niet klaar";
|
||||
"side_menu_app_version" = "Versie %@";
|
||||
"side_menu_action_feedback" = "Feedback";
|
||||
"side_menu_action_help" = "Help";
|
||||
"side_menu_action_settings" = "Instellingen";
|
||||
"side_menu_action_invite_friends" = "Vrienden uitnodigen";
|
||||
|
||||
// Mark: - Side menu
|
||||
|
||||
"side_menu_reveal_action_accessibility_label" = "Linkerpaneel";
|
||||
"user_avatar_view_accessibility_hint" = "Avatar veranderen";
|
||||
|
||||
// Mark: - User avatar view
|
||||
|
||||
"user_avatar_view_accessibility_label" = "avatar";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "Voor uw veiligheidssleutel in om door te gaan.";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Voer uw veiligheidswachtwoord in om door te gaan.";
|
||||
|
||||
// Success from secure backup
|
||||
"key_backup_setup_success_from_secure_backup_info" = "Uw sleutels worden geback-upt.";
|
||||
"security_settings_secure_backup_restore" = "Uit back-up herstellen";
|
||||
"security_settings_secure_backup_reset" = "Opnieuw instellen";
|
||||
"security_settings_secure_backup_info_valid" = "Deze sessie maakt een back-up van uw sleutels.";
|
||||
"security_settings_secure_backup_info_checking" = "Controleren…";
|
||||
"settings_ui_theme_picker_message_match_system_theme" = "'Automatisch' gebruikt uw apparaat thema instelling";
|
||||
"settings_ui_theme_picker_message_invert_colours" = "‘Automatisch’ gebruikt de instelling ‘Kleurweergave omkeren’ van uw apparaat";
|
||||
"room_recents_unknown_room_error_message" = "Dit gesprek is niet gevonden. Controleer of het bestaat";
|
||||
"room_creation_dm_error" = "Uw direct gesprek kon niet aangemaakt worden. Controleer de gebruikers die u wilt uitnodigen en probeer het opnieuw.";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Permissions usage explanations
|
||||
"NSCameraUsageDescription" = "A câmera será usada para tirar fotos e vídeos, e também para fazer chamadas de vídeo.";
|
||||
"NSPhotoLibraryUsageDescription" = "A galeria é usada para enviar fotos e vídeos.";
|
||||
"NSMicrophoneUsageDescription" = "O microfone é usado para gravar vídeos e fazer chamadas, tanto de áudio como de vídeo.";
|
||||
"NSContactsUsageDescription" = "Para encontrar contatos que já usam o Matrix, o Element pode enviar endereços de e-mail e números de celular do seu catálogo de endereços para o servidor de identidade Matrix. Se possível, as informações pessoais serão criptografadas antes do envio. Para mais informações, consulte a política de privacidade do seu servidor de identidade.";
|
||||
"NSCalendarsUsageDescription" = "Veja suas reuniões agendadas no aplicativo.";
|
||||
"NSFaceIDUsageDescription" = "O Face ID é usado para acessar seu aplicativo.";
|
||||
"NSCameraUsageDescription" = "A câmera é usada para tirar fotos e vídeos, fazer chamadas de vídeo.";
|
||||
"NSPhotoLibraryUsageDescription" = "A biblioteca de fotos é usada para enviar fotos e vídeos.";
|
||||
"NSMicrophoneUsageDescription" = "O microfone é usado para tirar vídeos, fazer chamadas.";
|
||||
"NSContactsUsageDescription" = "Para descobrir contatos já usando Matrix, Element pode enviar endereços de email e números de telefone em seu livro de endereços para seu servidor de identidade Matrix escolhido. Onde suportado, dados pessoais são hashados antes do envio - por favor cheque a política de privacidade de seu servidor de identidade para mais detalhes.";
|
||||
"NSCalendarsUsageDescription" = "Ver suas reuniões agendadas no app.";
|
||||
"NSFaceIDUsageDescription" = "Face ID é usada para acessar seu app.";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* New message from a specific person, not referencing a room */
|
||||
"MSG_FROM_USER" = "%@ enviou uma mensagem";
|
||||
/* New message from a specific person in a named room */
|
||||
"MSG_FROM_USER_IN_ROOM" = "%@ enviou mensagem em %@";
|
||||
"MSG_FROM_USER_IN_ROOM" = "%@ postou em %@";
|
||||
/* New message from a specific person, not referencing a room. Content included. */
|
||||
"MSG_FROM_USER_WITH_CONTENT" = "%@: %@";
|
||||
/* New message from a specific person in a named room. Content included. */
|
||||
@@ -9,56 +9,62 @@
|
||||
/* New action message from a specific person, not referencing a room. */
|
||||
"ACTION_FROM_USER" = "* %@ %@";
|
||||
/* New action message from a specific person in a named room. */
|
||||
"ACTION_FROM_USER_IN_ROOM" = "%@ : * %@ %@";
|
||||
"ACTION_FROM_USER_IN_ROOM" = "%@: * %@ %@";
|
||||
/* New action message from a specific person, not referencing a room. */
|
||||
"IMAGE_FROM_USER" = "%@ enviou uma imagem %@";
|
||||
/* New action message from a specific person in a named room. */
|
||||
"IMAGE_FROM_USER_IN_ROOM" = "%@ enviou uma imagem %@ na sala %@";
|
||||
"IMAGE_FROM_USER_IN_ROOM" = "%@ postou uma imagem %@ em %@";
|
||||
/* A single unread message in a room */
|
||||
"SINGLE_UNREAD_IN_ROOM" = "Você recebeu uma mensagem na sala %@";
|
||||
"SINGLE_UNREAD_IN_ROOM" = "Você recebeu uma mensagem em %@";
|
||||
/* A single unread message */
|
||||
"SINGLE_UNREAD" = "Você recebeu uma mensagem";
|
||||
/* Multiple unread messages in a room */
|
||||
"UNREAD_IN_ROOM" = "%@ novas mensagens na sala %@";
|
||||
"UNREAD_IN_ROOM" = "%@ novas mensagens em %@";
|
||||
/* Multiple unread messages from a specific person, not referencing a room */
|
||||
"MSGS_FROM_USER" = "%@ novas mensagens de %@";
|
||||
"MSGS_FROM_USER" = "%@ novas mensagens em %@";
|
||||
/* Multiple unread messages from two people */
|
||||
"MSGS_FROM_TWO_USERS" = "%@ novas mensagens de %@ e %@";
|
||||
/* Multiple unread messages from three people */
|
||||
"MSGS_FROM_THREE_USERS" = "%@ novas mensagens de %@, %@ e %@";
|
||||
/* Multiple unread messages from two plus people (ie. for 4+ people: 'others' replaces the third person) */
|
||||
"MSGS_FROM_TWO_PLUS_USERS" = "%@ novas mensagens de %@, %@ e outras/os";
|
||||
"MSGS_FROM_TWO_PLUS_USERS" = "%@ novas mensagens de %@, %@ e outras(os)";
|
||||
/* Multiple messages in two rooms */
|
||||
"MSGS_IN_TWO_ROOMS" = "%@ novas mensagens nas salas %@ e %@";
|
||||
"MSGS_IN_TWO_ROOMS" = "%@ novas mensagens em %@ e %@";
|
||||
/* Look, stuff's happened, alright? Just open the app. */
|
||||
"MSGS_IN_TWO_PLUS_ROOMS" = "%@ novas mensagens nas salas %@ e %@, dentre outras";
|
||||
"MSGS_IN_TWO_PLUS_ROOMS" = "%@ novas mensagens em %@, %@ e outras";
|
||||
/* A user has invited you to a chat */
|
||||
"USER_INVITE_TO_CHAT" = "%@ convidou você para conversar";
|
||||
"USER_INVITE_TO_CHAT" = "%@ tem conviado você para fazer chat";
|
||||
/* A user has invited you to an (unamed) group chat */
|
||||
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ convidou você para uma conversa em grupo";
|
||||
"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ tem convidado você para um chat de grupo";
|
||||
/* A user has invited you to a named room */
|
||||
"USER_INVITE_TO_NAMED_ROOM" = "%@ convidou você para a sala %@";
|
||||
"USER_INVITE_TO_NAMED_ROOM" = "%@ tem convidado você para %@";
|
||||
/* Incoming one-to-one voice call */
|
||||
"VOICE_CALL_FROM_USER" = "Chamada de %@";
|
||||
/* Incoming one-to-one video call */
|
||||
"VIDEO_CALL_FROM_USER" = "Chamada de vídeo de %@";
|
||||
/* Incoming unnamed voice conference invite from a specific person */
|
||||
"VOICE_CONF_FROM_USER" = "Chamada de voz em grupo de %@";
|
||||
"VOICE_CONF_FROM_USER" = "Chamada de grupo de %@";
|
||||
/* Incoming unnamed video conference invite from a specific person */
|
||||
"VIDEO_CONF_FROM_USER" = "Chamada de vídeo em grupo de %@";
|
||||
"VIDEO_CONF_FROM_USER" = "Chamada de vídeo de grupo de %@";
|
||||
/* Incoming named voice conference invite from a specific person */
|
||||
"VOICE_CONF_NAMED_FROM_USER" = "Chamada de vídeo em grupo de %@: '%@'";
|
||||
"VOICE_CONF_NAMED_FROM_USER" = "Chamada de grupo de %@: '%@'";
|
||||
/* Incoming named video conference invite from a specific person */
|
||||
"VIDEO_CONF_NAMED_FROM_USER" = "Chamada de vídeo em grupo de %@: '%@'";
|
||||
"VIDEO_CONF_NAMED_FROM_USER" = "Chamada de vídeo de grupo de %@: '%@'";
|
||||
/* Message title for a specific person in a named room */
|
||||
"MSG_FROM_USER_IN_ROOM_TITLE" = "%@ em %@";
|
||||
/* Sticker from a specific person, not referencing a room. */
|
||||
"STICKER_FROM_USER" = "%@ enviou uma figurinha";
|
||||
"STICKER_FROM_USER" = "%@ enviou um sticker";
|
||||
/* New message indicator on unknown room */
|
||||
"MESSAGE" = "Mensagem";
|
||||
/* New message indicator from a DM */
|
||||
"MESSAGE_FROM_X" = "Mensagem de %@";
|
||||
/* New message indicator on a room */
|
||||
"MESSAGE_IN_X" = "Mensagem em %@";
|
||||
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ solicita confirmação";
|
||||
"MESSAGE_PROTECTED" = "Nova mensagem";
|
||||
"KEY_VERIFICATION_REQUEST_FROM_USER" = "%@ quer verificar";
|
||||
"MESSAGE_PROTECTED" = "Nova Mensagem";
|
||||
|
||||
/* Group call from user, CallKit caller name */
|
||||
"GROUP_CALL_FROM_USER" = "%@ (Chamada de grupo)";
|
||||
|
||||
/* A user added a Jitsi call to a room */
|
||||
"GROUP_CALL_STARTED" = "Chamada de grupo começada";
|
||||
|
||||
@@ -612,7 +612,7 @@
|
||||
"settings_ui_theme_picker_message" = "\"Auto\" använder dina enhetsinställningar för \"Invertera färger\"";
|
||||
"settings_olm_version" = "Olm-version %@";
|
||||
"settings_crypto_device_key" = "\nSessionsnyckel:\n";
|
||||
"settings_key_backup_info_signout_warning" = "Anslut den här sessionen till nyckelsäkerhetskopiering innan du loggar ut för att undvika förlust av någon nyckel som endast finns på den här enheten.";
|
||||
"settings_key_backup_info_signout_warning" = "Säkerhetskopiera dina nycklar innan du loggar ut för att undvika att du förlorar dem.";
|
||||
"settings_discovery_no_identity_server" = "Du använder för närvarande ingen identitetsserver. Lägg till en för att kunna upptäckas av befintliga kontakter du känner.";
|
||||
"settings_discovery_terms_not_signed" = "Acceptera identitetsserverns (%@) användarvillkor för att låta dig själv vara upptäckbar med e-postadress eller telefonnummer.";
|
||||
"security_settings_crypto_sessions_loading" = "Laddar sessioner…";
|
||||
@@ -1321,3 +1321,7 @@
|
||||
// Mark: - Spaces
|
||||
|
||||
"space_feature_unavailable_title" = "Utrymmen är inte här än";
|
||||
"settings_ui_theme_picker_message_match_system_theme" = "\"Auto\" matchar din enhets systemtema";
|
||||
"settings_ui_theme_picker_message_invert_colours" = "\"Auto\" använder din enhets \"Invertera färger\"-inställning";
|
||||
"room_recents_unknown_room_error_message" = "Kan inte hitta det här rummet. Se till att det finns";
|
||||
"room_creation_dm_error" = "Vi kunde inte skapa din DM. Vänligen kolla användarna du vill bjuda in och försök igen.";
|
||||
|
||||
@@ -126,3 +126,43 @@
|
||||
"room_new_messages_notification" = "%d ข้อความใหม่";
|
||||
"room_new_message_notification" = "%d ข้อความใหม่";
|
||||
"room_participants_action_ignore" = "ซ่อนข้อความทั้งหมดจากผู้ใช้นี้";
|
||||
"room_event_action_share" = "แบ่งปัน";
|
||||
"room_event_action_more" = "เพิ่มเติม";
|
||||
"room_event_action_redact" = "เอาออก";
|
||||
"room_event_action_copy" = "คัดลอก";
|
||||
"auth_password_dont_match" = "รหัสผ่านไม่ตรงกัน";
|
||||
"retry" = "ลองใหม่";
|
||||
|
||||
// Room Title
|
||||
"room_title_new_room" = "ห้องใหม่";
|
||||
"room_action_reply" = "ตอบกลับ";
|
||||
"room_message_edits_history_title" = "การแก้ไขข้อความ";
|
||||
"room_accessibility_search" = "ค้นหา";
|
||||
"room_accessibility_call" = "โทร";
|
||||
"room_accessibility_upload" = "อัปโหลด";
|
||||
"room_event_action_cancel_download" = "ยกเลิกการดาวน์โหลด";
|
||||
"room_event_action_cancel_send" = "ยกเลิกการส่ง";
|
||||
"room_event_action_reaction_show_less" = "แสดงน้อยลง";
|
||||
"room_event_action_reaction_show_all" = "แสดงทั้งหมด";
|
||||
"room_event_action_edit" = "แก้ไข";
|
||||
"room_event_action_reply" = "ตอบกลับ";
|
||||
"room_ongoing_conference_call_close" = "ปิด";
|
||||
"room_participants_security_loading" = "กำลังโหลด…";
|
||||
"room_participants_action_security_status_loading" = "กำลังโหลด…";
|
||||
"room_participants_action_mention" = "การกล่าวถึง";
|
||||
"room_participants_multi_participants" = "%d ผู้เข้าร่วม";
|
||||
"room_participants_one_participant" = "1 ผู้เข้าร่วม";
|
||||
"room_participants_add_participant" = "เพิ่มผู้เข้าร่วม";
|
||||
|
||||
// Chat participants
|
||||
"room_participants_title" = "ผู้เข้าร่วม";
|
||||
"contacts_user_directory_offline_section" = "ไดเรกทอรีผู้ใช้ (ออฟไลน์)";
|
||||
"contacts_user_directory_section" = "ไดเรกทอรีผู้ใช้";
|
||||
"directory_search_results_more_than" = "พบ >%tu ผลลัพธ์สำหรับ %@";
|
||||
"directory_search_results" = "พบ %tu ผลลัพธ์สำหรับ %@";
|
||||
"switch" = "สลับ";
|
||||
"auth_invalid_login_param" = "ชื่อผู้ใช้และ/หรือรหัสผ่านไม่ถูกต้อง";
|
||||
"sending" = "กำลังส่ง";
|
||||
"send_to" = "ส่งไปยัง %@";
|
||||
"less" = "น้อยลง";
|
||||
"more" = "เพิ่มเติม";
|
||||
|
||||
@@ -1663,7 +1663,32 @@
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
<br/><br/>
|
||||
</li>
|
||||
<li>
|
||||
<b>SideMenu</b> (<a href="https://github.com/jonkykong/SideMenu/">https://github.com/jonkykong/SideMenu/</a>)
|
||||
<br/><br/>
|
||||
Copyright (c) 2015 Jonathan Kent <contact@jonkent.me>
|
||||
<br/><br/>
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
<br/><br/>
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
<br/><br/>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
<br/><br/>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -285,7 +285,7 @@
|
||||
"secrets_setup_recovery_key_export_action" = "Зберегти";
|
||||
"room_event_action_save" = "Зберегти";
|
||||
"room_event_action_delete" = "Видалити";
|
||||
"security_settings_secure_backup_delete" = "Видалити";
|
||||
"security_settings_secure_backup_delete" = "Видалити резервну копію";
|
||||
"security_settings_secure_backup_synchronise" = "Синхронізувати";
|
||||
"security_settings_secure_backup_setup" = "Налаштувати";
|
||||
"people_empty_view_information" = "Безпечно спілкуйтеся з будь-ким. Торкніться +, щоб додати співрозмовників.";
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
"room_creation_appearance_picture" = "聊天图片(可选)";
|
||||
"room_creation_privacy" = "因此";
|
||||
"room_creation_private_room" = "此聊天是私密的";
|
||||
"room_creation_public_room" = "此聊天是公开的";
|
||||
"room_creation_public_room" = "此聊天室为公开聊天室";
|
||||
"room_creation_make_public" = "使其公开";
|
||||
"room_creation_make_public_prompt_title" = "要让此聊天公开吗?";
|
||||
"room_creation_make_public_prompt_msg" = "你确认要让此聊天公开吗?任何人都可以读到您的消息并加入此聊天。";
|
||||
@@ -535,7 +535,7 @@
|
||||
"settings_key_backup_info" = "消息已被端对端安全加密。只有您和持有密钥的接收方可以阅读这些消息。";
|
||||
"settings_key_backup_info_checking" = "正在检查…";
|
||||
"settings_key_backup_info_none" = "您的密钥未从此会话备份。";
|
||||
"settings_key_backup_info_signout_warning" = "在登出账号之前把此会话关联到密钥备份以免丢失仅在此设备上的所有密钥。";
|
||||
"settings_key_backup_info_signout_warning" = "在退出账号之前备份你的密钥以避免丢失它们。";
|
||||
"settings_key_backup_info_version" = "密钥备份版本:%@";
|
||||
"settings_key_backup_info_algorithm" = "算法:%@";
|
||||
"settings_key_backup_info_valid" = "此会话正在备份密钥。";
|
||||
@@ -562,7 +562,7 @@
|
||||
"call_incoming_video" = "收到视频通话…";
|
||||
// Key backup wrong version
|
||||
"e2e_key_backup_wrong_version_title" = "新建密钥备份";
|
||||
"e2e_key_backup_wrong_version" = "一个新的安全消息密钥备份已被删除。\n\n如果这不是您的操作,请在设置中设定一个新的密码。";
|
||||
"e2e_key_backup_wrong_version" = "一个新的安全消息密钥备份已被删除。\n\n如果这不是您的操作,请在设置中设定一个新的密码口令 (phrase)。";
|
||||
"e2e_key_backup_wrong_version_button_settings" = "设置";
|
||||
"e2e_key_backup_wrong_version_button_wasme" = "那是我操作的";
|
||||
"widget_sticker_picker_no_stickerpacks_alert" = "您目前并未启用任何贴纸包。";
|
||||
@@ -599,46 +599,46 @@
|
||||
"key_backup_setup_intro_setup_action_with_existing_backup" = "使用密钥备份";
|
||||
"key_backup_setup_intro_manual_export_info" = "(高级)";
|
||||
"key_backup_setup_intro_manual_export_action" = "手动导出密钥";
|
||||
"key_backup_setup_passphrase_title" = "使用一段密码保护您的备份";
|
||||
"key_backup_setup_passphrase_info" = "我们将会在主服务器上保存一份您的密钥的加密拷贝。设置一个密码来保护您的备份的安全。\n\n为了最大的安全性,这个密码应当与您的账号密码不同。";
|
||||
"key_backup_setup_passphrase_title" = "使用一段安全口令保护您的备份";
|
||||
"key_backup_setup_passphrase_info" = "我们将会在主服务器上保存一份您的密钥的加密拷贝。设置一个密码口令来保护您的备份的安全。\n\n为了最大的安全性,这个密码应当与您的账号密码不同。";
|
||||
"key_backup_setup_passphrase_passphrase_title" = "输入";
|
||||
"key_backup_setup_passphrase_passphrase_placeholder" = "输入密码";
|
||||
"key_backup_setup_passphrase_passphrase_placeholder" = "输入密码口令";
|
||||
"key_backup_setup_passphrase_passphrase_valid" = "太棒了!";
|
||||
"key_backup_setup_passphrase_passphrase_invalid" = "尝试添加一个字符";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_title" = "确认";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "确认密码";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "确认密码口令";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_valid" = "太棒了!";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "密码不匹配";
|
||||
"key_backup_setup_passphrase_set_passphrase_action" = "设置密码";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_info" = "或者使用恢复密钥来保护您的备份,将密钥保存在一个安全的地方。";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_action" = "(高级)设置恢复密钥";
|
||||
"key_backup_setup_passphrase_confirm_passphrase_invalid" = "密码口令不匹配";
|
||||
"key_backup_setup_passphrase_set_passphrase_action" = "设置密码口令";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_info" = "或者使用安全密钥来保护您的备份,将密钥保存在一个安全的地方。";
|
||||
"key_backup_setup_passphrase_setup_recovery_key_action" = "(高级) 使用安全密钥进行设置";
|
||||
"key_backup_setup_success_title" = "成功!";
|
||||
// Success from passphrase
|
||||
"key_backup_setup_success_from_passphrase_info" = "您的密钥已备份。\n\n您的恢复密钥是一张安全网 - 如果您忘记了密码您可以利用它重获您的已加密信息的访问权。\n\n请将您的恢复密钥保存在一个非常安全的地方,比如密码管理器中 (或保险箱里)。";
|
||||
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "保存恢复密钥";
|
||||
"key_backup_setup_success_from_passphrase_info" = "您的密钥已备份。\n\n您的安全密钥是一张安全网 - 如果您忘记了密码您可以利用它重获您的已加密信息的访问权。\n\n请将您的安全密钥保存在一个非常安全的地方,比如密码管理器中 (或保险箱里)。";
|
||||
"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "保存安全密钥";
|
||||
"key_backup_setup_success_from_passphrase_done_action" = "完成";
|
||||
// Success from recovery key
|
||||
"key_backup_setup_success_from_recovery_key_info" = "您的密钥已备份。\n\n制作此恢复密钥的副本并确保其安全。";
|
||||
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "恢复密钥";
|
||||
"key_backup_setup_success_from_recovery_key_info" = "您的密钥已备份。\n\n制作此安全密钥的副本并确保其安全。";
|
||||
"key_backup_setup_success_from_recovery_key_recovery_key_title" = "安全密钥";
|
||||
"key_backup_setup_success_from_recovery_key_make_copy_action" = "制作副本";
|
||||
"key_backup_setup_success_from_recovery_key_made_copy_action" = "我已制作一份副本";
|
||||
"key_backup_recover_title" = "安全消息";
|
||||
"key_backup_recover_invalid_passphrase_title" = "恢复密码不正确";
|
||||
"key_backup_recover_invalid_passphrase" = "备份无法用此密码解密:请检查您输入的恢复密码是否正确。";
|
||||
"key_backup_recover_invalid_recovery_key_title" = "恢复密钥不匹配";
|
||||
"key_backup_recover_invalid_recovery_key" = "备份无法用此密钥解密:请检查您输入的恢复密钥是否正确。";
|
||||
"key_backup_recover_from_passphrase_info" = "使用恢复密钥解锁您的安全消息历史";
|
||||
"key_backup_recover_invalid_passphrase_title" = "密码口令不正确";
|
||||
"key_backup_recover_invalid_passphrase" = "备份无法用此密码口令解密:请检查您输入的安全口令是否正确。";
|
||||
"key_backup_recover_invalid_recovery_key_title" = "安全密钥不匹配";
|
||||
"key_backup_recover_invalid_recovery_key" = "备份无法用此密钥解密:请检查您输入的安全密钥是否正确。";
|
||||
"key_backup_recover_from_passphrase_info" = "使用安全口令解锁您的安全消息历史";
|
||||
"key_backup_recover_from_passphrase_passphrase_title" = "输入";
|
||||
"key_backup_recover_from_passphrase_passphrase_placeholder" = "输入密码";
|
||||
"key_backup_recover_from_passphrase_passphrase_placeholder" = "输入密码口令";
|
||||
"key_backup_recover_from_passphrase_recover_action" = "解锁历史";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "忘记了您的恢复密码?您可以 ";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "使用恢复密钥";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "忘记了您的安全口令?您可以 ";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "使用你的安全密钥";
|
||||
"key_backup_recover_from_passphrase_lost_passphrase_action_part3" = "。";
|
||||
"key_backup_recover_from_recovery_key_info" = "使用恢复密钥解锁您的安全消息历史";
|
||||
"key_backup_recover_from_recovery_key_info" = "使用安全密钥解锁您的安全消息历史";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_title" = "输入";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "输入恢复密钥";
|
||||
"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "输入安全密钥";
|
||||
"key_backup_recover_from_recovery_key_recover_action" = "解锁历史";
|
||||
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "丢失了恢复密钥?您可以在设置中新设一个。";
|
||||
"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "丢失了安全密钥?您可以在设置中新设一个。";
|
||||
"key_backup_recover_success_info" = "备份已恢复!";
|
||||
"key_backup_recover_done_action" = "完成";
|
||||
"key_backup_setup_banner_title" = "永不丢失加密消息";
|
||||
@@ -1001,9 +1001,9 @@
|
||||
"room_member_power_level_custom_in" = "自定义(%@)(%@)";
|
||||
"room_member_power_level_short_custom" = "自定义";
|
||||
"security_settings_crosssigning_info_trusted" = "已启用交叉签名。您可以基于交叉签名信任其他用户和其他会话,但不能从此会话交叉签名,因为它没有交叉签名私钥。此会话完全安全。";
|
||||
"security_settings_crosssigning_info_ok" = "交叉签名还没有被设置。";
|
||||
"security_settings_crosssigning_bootstrap" = "引导交叉签名";
|
||||
"security_settings_crosssigning_reset" = "重置交叉签名";
|
||||
"security_settings_crosssigning_info_ok" = "交叉登录已准备就绪。";
|
||||
"security_settings_crosssigning_bootstrap" = "设置";
|
||||
"security_settings_crosssigning_reset" = "重置";
|
||||
"security_settings_crosssigning_complete_security" = "完整安全性";
|
||||
"security_settings_cryptography" = "加密";
|
||||
"security_settings_complete_security_alert_title" = "绝对安全";
|
||||
@@ -1034,8 +1034,8 @@
|
||||
"device_verification_self_verify_wait_new_sign_in_title" = "验证此登录名";
|
||||
"device_verification_self_verify_wait_information" = "从您的其他会话之一验证此会话,授予它访问加密消息的权限。\n\n在您的其他设备上使用最新版的Element:";
|
||||
"device_verification_self_verify_wait_additional_information" = "这适用于Element和其他支持交叉签名的Matrix客户端。";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "使用恢复密钥";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "使用恢复密码或密钥";
|
||||
"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "使用安全密钥";
|
||||
"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "使用安全口令或密钥";
|
||||
"device_verification_self_verify_wait_recover_secrets_additional_information" = "如果您无法访问一个现有会话";
|
||||
"key_verification_verify_sas_title_emoji" = "比较emoji";
|
||||
"key_verification_verify_sas_title_number" = "比较数字";
|
||||
@@ -1075,25 +1075,25 @@
|
||||
"key_verification_scan_confirmation_scanned_user_information" = "是否%@显示相同的盾牌?";
|
||||
"key_verification_scan_confirmation_scanned_device_information" = "另一台设备是否显示相同的盾牌?";
|
||||
"user_verification_session_details_verify_action_current_user_manually" = "通过文本手动验证";
|
||||
"secrets_recovery_with_passphrase_title" = "恢复密码";
|
||||
"secrets_recovery_with_passphrase_information_default" = "通过输入恢复密码,访问您的安全信息历史记录和交叉签名身份,以验证其他会话。";
|
||||
"secrets_recovery_with_passphrase_information_verify_device" = "使用您的恢复密码验证此设备。";
|
||||
"secrets_recovery_with_passphrase_title" = "安全口令";
|
||||
"secrets_recovery_with_passphrase_information_default" = "通过输入安全口令,访问您的安全信息历史记录和交叉登录身份,以验证其他会话。";
|
||||
"secrets_recovery_with_passphrase_information_verify_device" = "使用您的安全口令验证此设备。";
|
||||
"secrets_recovery_with_passphrase_passphrase_title" = "输入";
|
||||
"secrets_recovery_with_passphrase_passphrase_placeholder" = "输入恢复密码";
|
||||
"secrets_recovery_with_passphrase_recover_action" = "使用密码短语";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "忘记了您的恢复密码?您可以 ";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "使用您的恢复密钥";
|
||||
"secrets_recovery_with_passphrase_passphrase_placeholder" = "输入安全口令";
|
||||
"secrets_recovery_with_passphrase_recover_action" = "使用密码口令";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "忘记了您的安全口令?您可以 ";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "使用您的安全密钥";
|
||||
"secrets_recovery_with_passphrase_lost_passphrase_action_part3" = ".";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_title" = "无法访问机密存储";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "请验证您输入的恢复密码是否正确。";
|
||||
"secrets_recovery_with_key_title" = "恢复密钥";
|
||||
"secrets_recovery_with_key_information_default" = "通过输入恢复密钥访问安全信息历史记录和交叉签名身份,以验证其他会话。";
|
||||
"secrets_recovery_with_key_information_verify_device" = "使用您的恢复密码验证此设备。";
|
||||
"secrets_recovery_with_passphrase_invalid_passphrase_message" = "请验证您输入的安全口令是否正确。";
|
||||
"secrets_recovery_with_key_title" = "安全密钥";
|
||||
"secrets_recovery_with_key_information_default" = "通过输入安全密钥访问安全信息历史记录和交叉登录身份,以验证其他会话。";
|
||||
"secrets_recovery_with_key_information_verify_device" = "使用您的安全密钥验证此设备。";
|
||||
"secrets_recovery_with_key_recovery_key_title" = "输入";
|
||||
"secrets_recovery_with_key_recovery_key_placeholder" = "输入恢复密钥";
|
||||
"secrets_recovery_with_key_recovery_key_placeholder" = "输入安全密钥";
|
||||
"secrets_recovery_with_key_recover_action" = "使用密钥";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_title" = "无法访问机密存储";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "请验证您输入的恢复密钥是否正确。";
|
||||
"secrets_recovery_with_key_invalid_recovery_key_message" = "请验证您输入的安全密钥是否正确。";
|
||||
"rooms_empty_view_information" = "房间非常适合任何群聊,无论是私人的还是公共的。点击+以查找现有房间,或新建房间。";
|
||||
"security_settings_user_password_description" = "通过输入您的帐户密码确认您的身份";
|
||||
"rooms_empty_view_title" = "聊天室";
|
||||
@@ -1113,10 +1113,10 @@
|
||||
// Social login
|
||||
|
||||
"social_login_list_title_continue" = "以其他方式登录";
|
||||
"security_settings_secure_backup_delete" = "删除";
|
||||
"security_settings_secure_backup_delete" = "删除备份";
|
||||
"security_settings_secure_backup_synchronise" = "同步";
|
||||
"security_settings_secure_backup_setup" = "设置";
|
||||
"security_settings_secure_backup_description" = "通过在您的服务器上备份加密密钥,防止失去对加密信息和数据的访问。";
|
||||
"security_settings_secure_backup_description" = "备份你的帐户数据备份和加密密钥,以防你无法访问会话。 你的密钥将受到唯一的安全密钥保护。";
|
||||
"security_settings_crypto_sessions_description_2" = "如果您未曾发起登录,请更改密码并重置安全备份。";
|
||||
"settings_show_NSFW_public_rooms" = "显示 NSFW 公共聊天室";
|
||||
"external_link_confirmation_message" = "此链接 %@ 会将您带至另一个网站:%@\n\n是否前往?";
|
||||
@@ -1223,7 +1223,7 @@
|
||||
"major_update_title" = "Riot 现已成为 Element";
|
||||
"secrets_reset_reset_action" = "重置";
|
||||
"secrets_setup_recovery_passphrase_summary_title" = "保存您的安全密语";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "确认安全密语";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "确认口令";
|
||||
"secrets_setup_recovery_passphrase_confirm_passphrase_title" = "确认";
|
||||
"secrets_setup_recovery_passphrase_additional_information" = "不要使用你的账号密码。";
|
||||
"secrets_setup_recovery_passphrase_validate_action" = "完成";
|
||||
@@ -1313,7 +1313,7 @@
|
||||
"secrets_setup_recovery_passphrase_information" = "输入只有您知道的安全口令,用于保护您的服务器上的秘密。";
|
||||
"secrets_setup_recovery_key_storage_alert_message" = "✓ 把它打印出来,储存在一个安全的地方\n✓ 把它保存在 USB 钥匙或备份驱动器上\n✓ 把它复制到你的个人云存储";
|
||||
"secrets_setup_recovery_key_storage_alert_title" = "保持安全";
|
||||
"secrets_setup_recovery_key_information" = "将恢复密钥保存在安全的地方。它可以用来解锁你的加密信息和数据。";
|
||||
"secrets_setup_recovery_key_information" = "将安全密钥保存在安全的地方。它可以用来解锁你的加密信息和数据。";
|
||||
"secrets_recovery_reset_action_part_2" = "全部重置";
|
||||
|
||||
// MARK: - Secrets recovery
|
||||
@@ -1400,3 +1400,30 @@
|
||||
// Chat
|
||||
"room_slide_to_end_group_call" = "滑动结束所有人的通话";
|
||||
"callbar_only_single_active_group" = "轻点加入群组通话(%@)";
|
||||
"side_menu_app_version" = "版本号 %@";
|
||||
"side_menu_action_feedback" = "反馈";
|
||||
"side_menu_action_help" = "帮助";
|
||||
"side_menu_action_settings" = "设置";
|
||||
"side_menu_action_invite_friends" = "邀请好友";
|
||||
|
||||
// Mark: - Side menu
|
||||
|
||||
"side_menu_reveal_action_accessibility_label" = "左面板";
|
||||
"user_avatar_view_accessibility_hint" = "更改用户头像";
|
||||
|
||||
// Mark: - User avatar view
|
||||
|
||||
"user_avatar_view_accessibility_label" = "头像";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "输入您的安全密钥以继续。";
|
||||
"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "输入您的安全口令以继续。";
|
||||
|
||||
// Success from secure backup
|
||||
"key_backup_setup_success_from_secure_backup_info" = "正在备份您的密钥。";
|
||||
"security_settings_secure_backup_restore" = "从备份文件还原";
|
||||
"security_settings_secure_backup_reset" = "重置";
|
||||
"security_settings_secure_backup_info_valid" = "此会话正在备份您的密钥。";
|
||||
"security_settings_secure_backup_info_checking" = "检查中…";
|
||||
"settings_ui_theme_picker_message_match_system_theme" = "“自动”匹配您设备的系统主题";
|
||||
"settings_ui_theme_picker_message_invert_colours" = "“自动”使用您设备的“反转颜色”设置";
|
||||
"room_recents_unknown_room_error_message" = "找不到这个房间。 确保它存在";
|
||||
"room_creation_dm_error" = "我们无法创建您的 DM。 请检查您要邀请的用户,然后重试。";
|
||||
|
||||
@@ -44,4 +44,7 @@ Return the homeserver configuration based on HS Well-Known or BuildSettings prop
|
||||
*/
|
||||
- (BOOL)vc_canSetupSecureBackup;
|
||||
|
||||
// TODO: Move to SDK
|
||||
- (MXRoom*)vc_roomWithIdOrAlias:(NSString*)roomIdOrAlias;
|
||||
|
||||
@end
|
||||
|
||||
@@ -92,4 +92,15 @@
|
||||
== crossSigningServiceSecrets.count);
|
||||
}
|
||||
|
||||
- (MXRoom*)vc_roomWithIdOrAlias:(NSString*)roomIdOrAlias
|
||||
{
|
||||
if ([MXTools isMatrixRoomIdentifier:roomIdOrAlias]) {
|
||||
return [self roomWithRoomId:roomIdOrAlias];
|
||||
} else if ([MXTools isMatrixRoomAlias:roomIdOrAlias]) {
|
||||
return [self roomWithAlias:roomIdOrAlias];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -40,4 +40,15 @@ extension UIButton {
|
||||
let image = UIImage.vc_image(from: color)
|
||||
self.setBackgroundImage(image, for: state)
|
||||
}
|
||||
|
||||
/// Shortcut to button label property `adjustsFontForContentSizeCategory`
|
||||
@IBInspectable
|
||||
var vc_adjustsFontForContentSizeCategory: Bool {
|
||||
get {
|
||||
return self.titleLabel?.adjustsFontForContentSizeCategory ?? false
|
||||
}
|
||||
set {
|
||||
self.titleLabel?.adjustsFontForContentSizeCategory = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,13 @@ extension UIView {
|
||||
}
|
||||
}
|
||||
|
||||
@objc func vc_setupAccessibilityTraitsImage(withTitle title: String) {
|
||||
self.isAccessibilityElement = false
|
||||
self.accessibilityLabel = title
|
||||
self.accessibilityHint = nil
|
||||
self.accessibilityTraits = .image
|
||||
}
|
||||
|
||||
@objc func vc_addShadow(withColor color: UIColor, offset: CGSize, radius: CGFloat, opacity: CGFloat) {
|
||||
layer.shadowColor = color.cgColor
|
||||
layer.shadowOpacity = Float(opacity)
|
||||
|
||||
@@ -158,6 +158,11 @@ internal enum Asset {
|
||||
internal static let secretsResetWarning = ImageAsset(name: "secrets_reset_warning")
|
||||
internal static let removeIconPink = ImageAsset(name: "remove_icon_pink")
|
||||
internal static let settingsIcon = ImageAsset(name: "settings_icon")
|
||||
internal static let sideMenuActionIconFeedback = ImageAsset(name: "side_menu_action_icon_feedback")
|
||||
internal static let sideMenuActionIconHelp = ImageAsset(name: "side_menu_action_icon_help")
|
||||
internal static let sideMenuActionIconSettings = ImageAsset(name: "side_menu_action_icon_settings")
|
||||
internal static let sideMenuActionIconShare = ImageAsset(name: "side_menu_action_icon_share")
|
||||
internal static let sideMenuIcon = ImageAsset(name: "side_menu_icon")
|
||||
internal static let featureUnavaibleArtwork = ImageAsset(name: "feature_unavaible_artwork")
|
||||
internal static let featureUnavaibleArtworkDark = ImageAsset(name: "feature_unavaible_artwork_dark")
|
||||
internal static let tabFavourites = ImageAsset(name: "tab_favourites")
|
||||
|
||||
@@ -97,6 +97,11 @@ internal enum StoryboardScene {
|
||||
|
||||
internal static let initialScene = InitialSceneType<Riot.KeyBackupSetupSuccessFromRecoveryKeyViewController>(storyboard: KeyBackupSetupSuccessFromRecoveryKeyViewController.self)
|
||||
}
|
||||
internal enum KeyBackupSetupSuccessFromSecureBackupViewController: StoryboardType {
|
||||
internal static let storyboardName = "KeyBackupSetupSuccessFromSecureBackupViewController"
|
||||
|
||||
internal static let initialScene = InitialSceneType<Riot.KeyBackupSetupSuccessFromSecureBackupViewController>(storyboard: KeyBackupSetupSuccessFromSecureBackupViewController.self)
|
||||
}
|
||||
internal enum KeyVerificationDataLoadingViewController: StoryboardType {
|
||||
internal static let storyboardName = "KeyVerificationDataLoadingViewController"
|
||||
|
||||
@@ -224,6 +229,11 @@ internal enum StoryboardScene {
|
||||
|
||||
internal static let searchableDirectoryViewController = SceneType<Riot.ShowDirectoryViewController>(storyboard: ShowDirectoryViewController.self, identifier: "SearchableDirectoryViewController")
|
||||
}
|
||||
internal enum SideMenuViewController: StoryboardType {
|
||||
internal static let storyboardName = "SideMenuViewController"
|
||||
|
||||
internal static let initialScene = InitialSceneType<Riot.SideMenuViewController>(storyboard: SideMenuViewController.self)
|
||||
}
|
||||
internal enum SimpleScreenTemplateViewController: StoryboardType {
|
||||
internal static let storyboardName = "SimpleScreenTemplateViewController"
|
||||
|
||||
|
||||
@@ -1034,11 +1034,11 @@ internal enum VectorL10n {
|
||||
internal static var deviceVerificationSelfVerifyWaitRecoverSecretsCheckingAvailability: String {
|
||||
return VectorL10n.tr("Vector", "device_verification_self_verify_wait_recover_secrets_checking_availability")
|
||||
}
|
||||
/// Use Recovery Passphrase or Key
|
||||
/// Use Security Phrase or Key
|
||||
internal static var deviceVerificationSelfVerifyWaitRecoverSecretsWithPassphrase: String {
|
||||
return VectorL10n.tr("Vector", "device_verification_self_verify_wait_recover_secrets_with_passphrase")
|
||||
}
|
||||
/// Use Recovery Key
|
||||
/// Use Security Key
|
||||
internal static var deviceVerificationSelfVerifyWaitRecoverSecretsWithoutPassphrase: String {
|
||||
return VectorL10n.tr("Vector", "device_verification_self_verify_wait_recover_secrets_without_passphrase")
|
||||
}
|
||||
@@ -1142,7 +1142,7 @@ internal enum VectorL10n {
|
||||
internal static var e2eEnablingOnAppUpdate: String {
|
||||
return VectorL10n.tr("Vector", "e2e_enabling_on_app_update")
|
||||
}
|
||||
/// A new secure message key backup has been detected.\n\nIf this wasn’t you, set a new passphrase in Settings.
|
||||
/// A new secure message key backup has been detected.\n\nIf this wasn’t you, set a new Security Phrase in Settings.
|
||||
internal static var e2eKeyBackupWrongVersion: String {
|
||||
return VectorL10n.tr("Vector", "e2e_key_backup_wrong_version")
|
||||
}
|
||||
@@ -1614,15 +1614,15 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupRecoverDoneAction: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_done_action")
|
||||
}
|
||||
/// Use your recovery passphrase to unlock your secure message history
|
||||
/// Use your Security Phrase to unlock your secure message history
|
||||
internal static var keyBackupRecoverFromPassphraseInfo: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_passphrase_info")
|
||||
}
|
||||
/// Don’t know your recovery passphrase? You can
|
||||
/// Don’t know your Security Phrase? You can
|
||||
internal static var keyBackupRecoverFromPassphraseLostPassphraseActionPart1: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_passphrase_lost_passphrase_action_part1")
|
||||
}
|
||||
/// use your recovery key
|
||||
/// use your Security Key
|
||||
internal static var keyBackupRecoverFromPassphraseLostPassphraseActionPart2: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_passphrase_lost_passphrase_action_part2")
|
||||
}
|
||||
@@ -1630,7 +1630,7 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupRecoverFromPassphraseLostPassphraseActionPart3: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_passphrase_lost_passphrase_action_part3")
|
||||
}
|
||||
/// Enter Passphrase
|
||||
/// Enter Phrase
|
||||
internal static var keyBackupRecoverFromPassphrasePassphrasePlaceholder: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_passphrase_passphrase_placeholder")
|
||||
}
|
||||
@@ -1646,11 +1646,11 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupRecoverFromPrivateKeyInfo: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_private_key_info")
|
||||
}
|
||||
/// Use your recovery key to unlock your secure message history
|
||||
/// Use your Security Key to unlock your secure message history
|
||||
internal static var keyBackupRecoverFromRecoveryKeyInfo: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_recovery_key_info")
|
||||
}
|
||||
/// Lost your recovery key? You can set up a new one in settings.
|
||||
/// Lost your Security Key You can set up a new one in settings.
|
||||
internal static var keyBackupRecoverFromRecoveryKeyLostRecoveryKeyAction: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_recovery_key_lost_recovery_key_action")
|
||||
}
|
||||
@@ -1658,7 +1658,7 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupRecoverFromRecoveryKeyRecoverAction: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_recovery_key_recover_action")
|
||||
}
|
||||
/// Enter Recovery Key
|
||||
/// Enter Security Key
|
||||
internal static var keyBackupRecoverFromRecoveryKeyRecoveryKeyPlaceholder: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_recovery_key_recovery_key_placeholder")
|
||||
}
|
||||
@@ -1666,19 +1666,19 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupRecoverFromRecoveryKeyRecoveryKeyTitle: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_from_recovery_key_recovery_key_title")
|
||||
}
|
||||
/// Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.
|
||||
/// Backup could not be decrypted with this phrase: please verify that you entered the correct Security Phrase.
|
||||
internal static var keyBackupRecoverInvalidPassphrase: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_invalid_passphrase")
|
||||
}
|
||||
/// Incorrect Recovery Passphrase
|
||||
/// Incorrect Security Phrase
|
||||
internal static var keyBackupRecoverInvalidPassphraseTitle: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_invalid_passphrase_title")
|
||||
}
|
||||
/// Backup could not be decrypted with this key: please verify that you entered the correct recovery key.
|
||||
/// Backup could not be decrypted with this key: please verify that you entered the correct Security Key.
|
||||
internal static var keyBackupRecoverInvalidRecoveryKey: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_invalid_recovery_key")
|
||||
}
|
||||
/// Recovery Key Mismatch
|
||||
/// Security Key Mismatch
|
||||
internal static var keyBackupRecoverInvalidRecoveryKeyTitle: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_recover_invalid_recovery_key_title")
|
||||
}
|
||||
@@ -1714,11 +1714,11 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupSetupIntroTitle: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_intro_title")
|
||||
}
|
||||
/// Passphrase doesn’t match
|
||||
/// Phrase doesn’t match
|
||||
internal static var keyBackupSetupPassphraseConfirmPassphraseInvalid: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_confirm_passphrase_invalid")
|
||||
}
|
||||
/// Confirm passphrase
|
||||
/// Confirm phrase
|
||||
internal static var keyBackupSetupPassphraseConfirmPassphrasePlaceholder: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_confirm_passphrase_placeholder")
|
||||
}
|
||||
@@ -1730,7 +1730,7 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupSetupPassphraseConfirmPassphraseValid: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_confirm_passphrase_valid")
|
||||
}
|
||||
/// We'll store an encrypted copy of your keys on our server. Protect your backup with a passphrase to keep it secure.\n\nFor maximum security, this should be different from your account password.
|
||||
/// We'll store an encrypted copy of your keys on our server. Protect your backup with a phrase to keep it secure.\n\nFor maximum security, this should be different from your account password.
|
||||
internal static var keyBackupSetupPassphraseInfo: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_info")
|
||||
}
|
||||
@@ -1738,7 +1738,7 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupSetupPassphrasePassphraseInvalid: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_passphrase_invalid")
|
||||
}
|
||||
/// Enter passphrase
|
||||
/// Enter phrase
|
||||
internal static var keyBackupSetupPassphrasePassphrasePlaceholder: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_passphrase_placeholder")
|
||||
}
|
||||
@@ -1750,19 +1750,19 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupSetupPassphrasePassphraseValid: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_passphrase_valid")
|
||||
}
|
||||
/// Set Passphrase
|
||||
/// Set Phrase
|
||||
internal static var keyBackupSetupPassphraseSetPassphraseAction: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_set_passphrase_action")
|
||||
}
|
||||
/// (Advanced) Set up with Recovery Key
|
||||
/// (Advanced) Set up with Security Key
|
||||
internal static var keyBackupSetupPassphraseSetupRecoveryKeyAction: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_setup_recovery_key_action")
|
||||
}
|
||||
/// Or, secure your backup with a Recovery Key, saving it somewhere safe.
|
||||
/// Or, secure your backup with a Security Key, saving it somewhere safe.
|
||||
internal static var keyBackupSetupPassphraseSetupRecoveryKeyInfo: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_setup_recovery_key_info")
|
||||
}
|
||||
/// Secure your backup with a Passphrase
|
||||
/// Secure your backup with a Security Phrase
|
||||
internal static var keyBackupSetupPassphraseTitle: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_passphrase_title")
|
||||
}
|
||||
@@ -1782,15 +1782,15 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupSetupSuccessFromPassphraseDoneAction: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_success_from_passphrase_done_action")
|
||||
}
|
||||
/// Your keys are being backed up.\n\nYour recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.\n\nKeep your recovery key somewhere very secure, like a password manager (or a safe).
|
||||
/// Your keys are being backed up.\n\nYour Security Key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.\n\nKeep your Security Key somewhere very secure, like a password manager (or a safe).
|
||||
internal static var keyBackupSetupSuccessFromPassphraseInfo: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_success_from_passphrase_info")
|
||||
}
|
||||
/// Save Recovery Key
|
||||
/// Save Security Key
|
||||
internal static var keyBackupSetupSuccessFromPassphraseSaveRecoveryKeyAction: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_success_from_passphrase_save_recovery_key_action")
|
||||
}
|
||||
/// Your keys are being backed up.\n\nMake a copy of this recovery key and keep it safe.
|
||||
/// Your keys are being backed up.\n\nMake a copy of this Security Key and keep it safe.
|
||||
internal static var keyBackupSetupSuccessFromRecoveryKeyInfo: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_success_from_recovery_key_info")
|
||||
}
|
||||
@@ -1802,10 +1802,14 @@ internal enum VectorL10n {
|
||||
internal static var keyBackupSetupSuccessFromRecoveryKeyMakeCopyAction: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_success_from_recovery_key_make_copy_action")
|
||||
}
|
||||
/// Recovery Key
|
||||
/// Security Key
|
||||
internal static var keyBackupSetupSuccessFromRecoveryKeyRecoveryKeyTitle: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_success_from_recovery_key_recovery_key_title")
|
||||
}
|
||||
/// Your keys are being backed up.
|
||||
internal static var keyBackupSetupSuccessFromSecureBackupInfo: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_success_from_secure_backup_info")
|
||||
}
|
||||
/// Success!
|
||||
internal static var keyBackupSetupSuccessTitle: String {
|
||||
return VectorL10n.tr("Vector", "key_backup_setup_success_title")
|
||||
@@ -2402,6 +2406,10 @@ internal enum VectorL10n {
|
||||
internal static var roomCreationAppearancePicture: String {
|
||||
return VectorL10n.tr("Vector", "room_creation_appearance_picture")
|
||||
}
|
||||
/// We couldn't create your DM. Please check the users you want to invite and try again.
|
||||
internal static var roomCreationDmError: String {
|
||||
return VectorL10n.tr("Vector", "room_creation_dm_error")
|
||||
}
|
||||
/// No identity server is configured so you cannot add a participant with an email.
|
||||
internal static var roomCreationErrorInviteUserByEmailWithoutIdentityServer: String {
|
||||
return VectorL10n.tr("Vector", "room_creation_error_invite_user_by_email_without_identity_server")
|
||||
@@ -3350,6 +3358,10 @@ internal enum VectorL10n {
|
||||
internal static var roomRecentsStartChatWith: String {
|
||||
return VectorL10n.tr("Vector", "room_recents_start_chat_with")
|
||||
}
|
||||
/// Can't find this room. Make sure it exists
|
||||
internal static var roomRecentsUnknownRoomErrorMessage: String {
|
||||
return VectorL10n.tr("Vector", "room_recents_unknown_room_error_message")
|
||||
}
|
||||
/// This room has been replaced and is no longer active.
|
||||
internal static var roomReplacementInformation: String {
|
||||
return VectorL10n.tr("Vector", "room_replacement_information")
|
||||
@@ -3546,15 +3558,23 @@ internal enum VectorL10n {
|
||||
internal static var secretsRecoveryResetActionPart2: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_reset_action_part_2")
|
||||
}
|
||||
/// Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery key.
|
||||
/// Access your secure message history and your cross-signing identity for verifying other sessions by entering your Security Key.
|
||||
internal static var secretsRecoveryWithKeyInformationDefault: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_information_default")
|
||||
}
|
||||
/// Use your Recovery Key to verify this device.
|
||||
/// Enter your Security Key to continue.
|
||||
internal static var secretsRecoveryWithKeyInformationUnlockSecureBackupWithKey: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_information_unlock_secure_backup_with_key")
|
||||
}
|
||||
/// Enter your Security Phrase to continue.
|
||||
internal static var secretsRecoveryWithKeyInformationUnlockSecureBackupWithPhrase: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_information_unlock_secure_backup_with_phrase")
|
||||
}
|
||||
/// Use your Security Key to verify this device.
|
||||
internal static var secretsRecoveryWithKeyInformationVerifyDevice: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_information_verify_device")
|
||||
}
|
||||
/// Please verify that you entered the correct recovery key.
|
||||
/// Please verify that you entered the correct Security Key.
|
||||
internal static var secretsRecoveryWithKeyInvalidRecoveryKeyMessage: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_invalid_recovery_key_message")
|
||||
}
|
||||
@@ -3566,7 +3586,7 @@ internal enum VectorL10n {
|
||||
internal static var secretsRecoveryWithKeyRecoverAction: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_recover_action")
|
||||
}
|
||||
/// Enter Recovery Key
|
||||
/// Enter Security Key
|
||||
internal static var secretsRecoveryWithKeyRecoveryKeyPlaceholder: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_recovery_key_placeholder")
|
||||
}
|
||||
@@ -3574,19 +3594,19 @@ internal enum VectorL10n {
|
||||
internal static var secretsRecoveryWithKeyRecoveryKeyTitle: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_recovery_key_title")
|
||||
}
|
||||
/// Recovery Key
|
||||
/// Security Key
|
||||
internal static var secretsRecoveryWithKeyTitle: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_key_title")
|
||||
}
|
||||
/// Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery passphrase.
|
||||
/// Access your secure message history and your cross-signing identity for verifying other sessions by entering your Security Phrase.
|
||||
internal static var secretsRecoveryWithPassphraseInformationDefault: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_information_default")
|
||||
}
|
||||
/// Use your Recovery Passphrase to verify this device.
|
||||
/// Use your Security Phrase to verify this device.
|
||||
internal static var secretsRecoveryWithPassphraseInformationVerifyDevice: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_information_verify_device")
|
||||
}
|
||||
/// Please verify that you entered the correct recovery passphrase.
|
||||
/// Please verify that you entered the correct Security Phrase.
|
||||
internal static var secretsRecoveryWithPassphraseInvalidPassphraseMessage: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_invalid_passphrase_message")
|
||||
}
|
||||
@@ -3594,11 +3614,11 @@ internal enum VectorL10n {
|
||||
internal static var secretsRecoveryWithPassphraseInvalidPassphraseTitle: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_invalid_passphrase_title")
|
||||
}
|
||||
/// Don’t know your recovery passphrase? You can
|
||||
/// Don’t know your Security Phrase? You can
|
||||
internal static var secretsRecoveryWithPassphraseLostPassphraseActionPart1: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_lost_passphrase_action_part1")
|
||||
}
|
||||
/// use your recovery key
|
||||
/// use your Security Key
|
||||
internal static var secretsRecoveryWithPassphraseLostPassphraseActionPart2: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_lost_passphrase_action_part2")
|
||||
}
|
||||
@@ -3606,7 +3626,7 @@ internal enum VectorL10n {
|
||||
internal static var secretsRecoveryWithPassphraseLostPassphraseActionPart3: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_lost_passphrase_action_part3")
|
||||
}
|
||||
/// Enter Recovery Passphrase
|
||||
/// Enter Security Phrase
|
||||
internal static var secretsRecoveryWithPassphrasePassphrasePlaceholder: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_passphrase_placeholder")
|
||||
}
|
||||
@@ -3614,11 +3634,11 @@ internal enum VectorL10n {
|
||||
internal static var secretsRecoveryWithPassphrasePassphraseTitle: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_passphrase_title")
|
||||
}
|
||||
/// Use Passphrase
|
||||
/// Use Phrase
|
||||
internal static var secretsRecoveryWithPassphraseRecoverAction: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_recover_action")
|
||||
}
|
||||
/// Recovery Passphrase
|
||||
/// Security Phrase
|
||||
internal static var secretsRecoveryWithPassphraseTitle: String {
|
||||
return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_title")
|
||||
}
|
||||
@@ -3654,7 +3674,7 @@ internal enum VectorL10n {
|
||||
internal static var secretsSetupRecoveryKeyExportAction: String {
|
||||
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_export_action")
|
||||
}
|
||||
/// Store your Recovery Key somewhere safe. It can be used to unlock your encrypted messages & data.
|
||||
/// Store your Security Key somewhere safe. It can be used to unlock your encrypted messages & data.
|
||||
internal static var secretsSetupRecoveryKeyInformation: String {
|
||||
return VectorL10n.tr("Vector", "secrets_setup_recovery_key_information")
|
||||
}
|
||||
@@ -3682,7 +3702,7 @@ internal enum VectorL10n {
|
||||
internal static var secretsSetupRecoveryPassphraseConfirmInformation: String {
|
||||
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_confirm_information")
|
||||
}
|
||||
/// Confirm passphrase
|
||||
/// Confirm phrase
|
||||
internal static var secretsSetupRecoveryPassphraseConfirmPassphrasePlaceholder: String {
|
||||
return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_confirm_passphrase_placeholder")
|
||||
}
|
||||
@@ -3762,7 +3782,7 @@ internal enum VectorL10n {
|
||||
internal static var secureKeyBackupSetupIntroUseSecurityPassphraseInfo: String {
|
||||
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_use_security_passphrase_info")
|
||||
}
|
||||
/// Use a Security Passphrase
|
||||
/// Use a Security Phrase
|
||||
internal static var secureKeyBackupSetupIntroUseSecurityPassphraseTitle: String {
|
||||
return VectorL10n.tr("Vector", "secure_key_backup_setup_intro_use_security_passphrase_title")
|
||||
}
|
||||
@@ -3798,7 +3818,7 @@ internal enum VectorL10n {
|
||||
internal static var securitySettingsCrosssigning: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_crosssigning")
|
||||
}
|
||||
/// Bootstrap cross-signing
|
||||
/// Set up
|
||||
internal static var securitySettingsCrosssigningBootstrap: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_crosssigning_bootstrap")
|
||||
}
|
||||
@@ -3814,7 +3834,7 @@ internal enum VectorL10n {
|
||||
internal static var securitySettingsCrosssigningInfoNotBootstrapped: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_crosssigning_info_not_bootstrapped")
|
||||
}
|
||||
/// Cross-signing is enabled.
|
||||
/// Cross-signing is ready for use.
|
||||
internal static var securitySettingsCrosssigningInfoOk: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_crosssigning_info_ok")
|
||||
}
|
||||
@@ -3822,7 +3842,7 @@ internal enum VectorL10n {
|
||||
internal static var securitySettingsCrosssigningInfoTrusted: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_crosssigning_info_trusted")
|
||||
}
|
||||
/// Reset cross-signing
|
||||
/// Reset
|
||||
internal static var securitySettingsCrosssigningReset: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_crosssigning_reset")
|
||||
}
|
||||
@@ -3850,22 +3870,34 @@ internal enum VectorL10n {
|
||||
internal static var securitySettingsSecureBackup: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup")
|
||||
}
|
||||
/// Delete
|
||||
/// Delete Backup
|
||||
internal static var securitySettingsSecureBackupDelete: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup_delete")
|
||||
}
|
||||
/// Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.
|
||||
/// Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Security Key.
|
||||
internal static var securitySettingsSecureBackupDescription: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup_description")
|
||||
}
|
||||
/// Checking…
|
||||
internal static var securitySettingsSecureBackupInfoChecking: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup_info_checking")
|
||||
}
|
||||
/// This session is backing up your keys.
|
||||
internal static var securitySettingsSecureBackupInfoValid: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup_info_valid")
|
||||
}
|
||||
/// Reset
|
||||
internal static var securitySettingsSecureBackupReset: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup_reset")
|
||||
}
|
||||
/// Restore from Backup
|
||||
internal static var securitySettingsSecureBackupRestore: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup_restore")
|
||||
}
|
||||
/// Set up
|
||||
internal static var securitySettingsSecureBackupSetup: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup_setup")
|
||||
}
|
||||
/// Synchronise
|
||||
internal static var securitySettingsSecureBackupSynchronise: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_secure_backup_synchronise")
|
||||
}
|
||||
/// Security
|
||||
internal static var securitySettingsTitle: String {
|
||||
return VectorL10n.tr("Vector", "security_settings_title")
|
||||
@@ -4242,7 +4274,7 @@ internal enum VectorL10n {
|
||||
internal static var settingsKeyBackupInfoProgressDone: String {
|
||||
return VectorL10n.tr("Vector", "settings_key_backup_info_progress_done")
|
||||
}
|
||||
/// Connect this session to key backup before signing out to avoid losing any keys that may only be on this device.
|
||||
/// Back up your keys before signing out to avoid losing them.
|
||||
internal static var settingsKeyBackupInfoSignoutWarning: String {
|
||||
return VectorL10n.tr("Vector", "settings_key_backup_info_signout_warning")
|
||||
}
|
||||
@@ -4454,9 +4486,13 @@ internal enum VectorL10n {
|
||||
internal static var settingsUiThemeLight: String {
|
||||
return VectorL10n.tr("Vector", "settings_ui_theme_light")
|
||||
}
|
||||
/// "Auto" uses your device "Invert Colours" settings
|
||||
internal static var settingsUiThemePickerMessage: String {
|
||||
return VectorL10n.tr("Vector", "settings_ui_theme_picker_message")
|
||||
/// "Auto" uses your device's "Invert Colours" settings
|
||||
internal static var settingsUiThemePickerMessageInvertColours: String {
|
||||
return VectorL10n.tr("Vector", "settings_ui_theme_picker_message_invert_colours")
|
||||
}
|
||||
/// "Auto" matches your device's system theme
|
||||
internal static var settingsUiThemePickerMessageMatchSystemTheme: String {
|
||||
return VectorL10n.tr("Vector", "settings_ui_theme_picker_message_match_system_theme")
|
||||
}
|
||||
/// Select a theme
|
||||
internal static var settingsUiThemePickerTitle: String {
|
||||
@@ -4486,6 +4522,30 @@ internal enum VectorL10n {
|
||||
internal static var shareExtensionFailedToEncrypt: String {
|
||||
return VectorL10n.tr("Vector", "share_extension_failed_to_encrypt")
|
||||
}
|
||||
/// Feedback
|
||||
internal static var sideMenuActionFeedback: String {
|
||||
return VectorL10n.tr("Vector", "side_menu_action_feedback")
|
||||
}
|
||||
/// Help
|
||||
internal static var sideMenuActionHelp: String {
|
||||
return VectorL10n.tr("Vector", "side_menu_action_help")
|
||||
}
|
||||
/// Invite friends
|
||||
internal static var sideMenuActionInviteFriends: String {
|
||||
return VectorL10n.tr("Vector", "side_menu_action_invite_friends")
|
||||
}
|
||||
/// Settings
|
||||
internal static var sideMenuActionSettings: String {
|
||||
return VectorL10n.tr("Vector", "side_menu_action_settings")
|
||||
}
|
||||
/// Version %@
|
||||
internal static func sideMenuAppVersion(_ p1: String) -> String {
|
||||
return VectorL10n.tr("Vector", "side_menu_app_version", p1)
|
||||
}
|
||||
/// Left panel
|
||||
internal static var sideMenuRevealActionAccessibilityLabel: String {
|
||||
return VectorL10n.tr("Vector", "side_menu_reveal_action_accessibility_label")
|
||||
}
|
||||
/// Sign out
|
||||
internal static var signOutExistingKeyBackupAlertSignOutAction: String {
|
||||
return VectorL10n.tr("Vector", "sign_out_existing_key_backup_alert_sign_out_action")
|
||||
@@ -4662,6 +4722,14 @@ internal enum VectorL10n {
|
||||
internal static var unknownDevicesVerify: String {
|
||||
return VectorL10n.tr("Vector", "unknown_devices_verify")
|
||||
}
|
||||
/// Change user avatar
|
||||
internal static var userAvatarViewAccessibilityHint: String {
|
||||
return VectorL10n.tr("Vector", "user_avatar_view_accessibility_hint")
|
||||
}
|
||||
/// avatar
|
||||
internal static var userAvatarViewAccessibilityLabel: String {
|
||||
return VectorL10n.tr("Vector", "user_avatar_view_accessibility_label")
|
||||
}
|
||||
/// If you didn’t sign in to this session, your account may be compromised.
|
||||
internal static var userVerificationSessionDetailsAdditionalInformationUntrustedCurrentUser: String {
|
||||
return VectorL10n.tr("Vector", "user_verification_session_details_additional_information_untrusted_current_user")
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Used to handle the application information
|
||||
@objcMembers
|
||||
final class AppInfo: NSObject {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
/// Current application information
|
||||
static var current: AppInfo {
|
||||
let appDisplayName = BuildSettings.bundleDisplayName
|
||||
let buildInfo: BuildInfo = BuildInfo()
|
||||
|
||||
return AppInfo(displayName: appDisplayName,
|
||||
appVersion: AppVersion.current,
|
||||
buildInfo: buildInfo)
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// App display name
|
||||
let displayName: String
|
||||
|
||||
/// Current app version
|
||||
let appVersion: AppVersion?
|
||||
|
||||
/// Compilation build info
|
||||
let buildInfo: BuildInfo
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(displayName: String,
|
||||
appVersion: AppVersion?,
|
||||
buildInfo: BuildInfo) {
|
||||
self.displayName = displayName
|
||||
self.appVersion = appVersion
|
||||
self.buildInfo = buildInfo
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// BuildInfo gives build information made at compilation time.
|
||||
@interface BuildInfo : NSObject
|
||||
|
||||
/// Git branch name. If GIT_BRANCH was provided during compilation in command line argument.
|
||||
@property (nonatomic, copy, readonly, nullable) NSString *buildNumber;
|
||||
|
||||
/// Git branch name. If BUILD_NUMBER was provided during compilation in command line argument.
|
||||
@property (nonatomic, copy, readonly, nullable) NSString *buildBranch;
|
||||
|
||||
/// Readable build version
|
||||
@property (nonatomic, copy, readonly) NSString *readableBuildVersion;
|
||||
|
||||
/// Convenience init. Check whether GIT_BRANCH and BUILD_NUMBER were provided during compilation in command line argument.
|
||||
- (instancetype)init;
|
||||
|
||||
/// Designated initializer to give input properties values
|
||||
- (instancetype)initWithBuildBranch:(nullable NSString*)buildBranch buildNumber:(nullable NSString*)buildNumber NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "BuildInfo.h"
|
||||
|
||||
#define MAKE_STRING(x) #x
|
||||
#define MAKE_NS_STRING(x) @MAKE_STRING(x)
|
||||
|
||||
@interface BuildInfo()
|
||||
|
||||
@property (nonatomic, copy, readwrite, nullable) NSString *buildNumber;
|
||||
@property (nonatomic, copy, readwrite, nullable) NSString *buildBranch;
|
||||
@property (nonatomic, copy, readwrite) NSString *readableBuildVersion;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BuildInfo
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
NSString *buildBranch;
|
||||
NSString *buildNumber;
|
||||
|
||||
// Check whether GIT_BRANCH was provided during compilation in command line argument.
|
||||
#ifdef GIT_BRANCH
|
||||
buildBranch = MAKE_NS_STRING(GIT_BRANCH);
|
||||
#endif
|
||||
|
||||
// Check whether BUILD_NUMBER was provided during compilation in command line argument.
|
||||
#ifdef BUILD_NUMBER
|
||||
buildNumber = [NSString stringWithFormat:@"#%@", @(BUILD_NUMBER)];
|
||||
#endif
|
||||
|
||||
self = [self initWithBuildBranch:buildBranch buildNumber:buildNumber];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBuildBranch:(NSString*)buildBranch buildNumber:(NSString*)buildNumber
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
_buildBranch = buildBranch;
|
||||
_buildNumber = buildNumber;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*)readableBuildVersion
|
||||
{
|
||||
if (!_readableBuildVersion)
|
||||
{
|
||||
NSString *buildBranch = self.buildBranch;
|
||||
NSString *buildNumber = self.buildNumber;
|
||||
|
||||
if (buildBranch && buildNumber)
|
||||
{
|
||||
_readableBuildVersion = [NSString stringWithFormat:@"%@ %@", buildBranch, buildNumber];
|
||||
}
|
||||
else if (buildNumber)
|
||||
{
|
||||
_readableBuildVersion = buildNumber;
|
||||
}
|
||||
else if (buildBranch)
|
||||
{
|
||||
_readableBuildVersion = buildBranch;
|
||||
}
|
||||
else
|
||||
{
|
||||
_readableBuildVersion = NSLocalizedStringFromTable(@"settings_config_no_build_info", @"Vector", nil);
|
||||
}
|
||||
}
|
||||
return _readableBuildVersion;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -48,13 +48,11 @@ class CallPresenter: NSObject {
|
||||
updateOnHoldCall()
|
||||
}
|
||||
}
|
||||
private weak var inBarCallVC: UIViewController?
|
||||
private weak var pipCallVC: UIViewController?
|
||||
/// UI operation queue for various UI operations
|
||||
private var uiOperationQueue: OperationQueue = .main
|
||||
/// Flag to indicate whether the presenter is active.
|
||||
private var isStarted: Bool = false
|
||||
private var callTimer: Timer?
|
||||
#if canImport(JitsiMeetSDK)
|
||||
private var widgetEventsListener: Any?
|
||||
/// Jitsi calls map. Keys are CallKit call UUIDs, values are corresponding widgets.
|
||||
@@ -121,7 +119,6 @@ class CallPresenter: NSObject {
|
||||
MXLog.debug("[CallPresenter] start")
|
||||
|
||||
addCallObservers()
|
||||
startCallTimer()
|
||||
}
|
||||
|
||||
/// Stop the service
|
||||
@@ -129,22 +126,6 @@ class CallPresenter: NSObject {
|
||||
MXLog.debug("[CallPresenter] stop")
|
||||
|
||||
removeCallObservers()
|
||||
stopCallTimer()
|
||||
}
|
||||
|
||||
/// Method to be called when the call status bar is tapped.
|
||||
func callStatusBarTapped() {
|
||||
MXLog.debug("[CallPresenter] callStatusBarTapped")
|
||||
|
||||
if let callVC = (inBarCallVC ?? activeCallVC) as? CallViewController {
|
||||
dismissCallBar(for: callVC)
|
||||
presentCallVC(callVC)
|
||||
return
|
||||
}
|
||||
if let jitsiVC = jitsiVC {
|
||||
dismissCallBar(for: jitsiVC)
|
||||
presentCallVC(jitsiVC)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK - Group Calls
|
||||
@@ -412,17 +393,12 @@ class CallPresenter: NSObject {
|
||||
if let oldCallVC = self.callVCs.values.first,
|
||||
self.presentedCallVC == nil,
|
||||
!self.uiOperationQueue.containsPresentCallVCOperation,
|
||||
!self.uiOperationQueue.containsPresentCallBarOperation {
|
||||
// present the call bar after dismissing this one
|
||||
self.presentCallBar(for: oldCallVC)
|
||||
!self.uiOperationQueue.containsEnterPiPOperation {
|
||||
// present the call screen after dismissing this one
|
||||
self.presentCallVC(oldCallVC)
|
||||
}
|
||||
}
|
||||
|
||||
if inBarCallVC == callVC {
|
||||
// this call currently in the status bar,
|
||||
// first present it and then dismiss it
|
||||
presentCallVC(callVC)
|
||||
}
|
||||
if pipCallVC == callVC {
|
||||
// this call currently in the PiP mode,
|
||||
// first present it by exiting PiP mode and then dismiss it
|
||||
@@ -446,36 +422,6 @@ class CallPresenter: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Timer
|
||||
|
||||
private func startCallTimer() {
|
||||
callTimer = Timer.scheduledTimer(timeInterval: 1.0,
|
||||
target: self,
|
||||
selector: #selector(callTimerFired(_:)),
|
||||
userInfo: nil,
|
||||
repeats: true)
|
||||
}
|
||||
|
||||
private func stopCallTimer() {
|
||||
callTimer?.invalidate()
|
||||
callTimer = nil
|
||||
}
|
||||
|
||||
@objc private func callTimerFired(_ timer: Timer) {
|
||||
if let inBarCallVC = inBarCallVC as? CallViewController {
|
||||
guard let call = inBarCallVC.mxCall else {
|
||||
return
|
||||
}
|
||||
guard call.state != .ended else {
|
||||
return
|
||||
}
|
||||
|
||||
updateCallBar()
|
||||
} else if inBarCallVC as? JitsiViewController != nil {
|
||||
updateCallBar()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Observers
|
||||
|
||||
private func addCallObservers() {
|
||||
@@ -614,14 +560,11 @@ class CallPresenter: NSObject {
|
||||
}
|
||||
case .connected:
|
||||
MXLog.debug("[CallPresenter] callStateChanged: call connected: \(call.callId)")
|
||||
callTimer?.fire()
|
||||
case .onHold:
|
||||
MXLog.debug("[CallPresenter] callStateChanged: call holded: \(call.callId)")
|
||||
callTimer?.fire()
|
||||
callHolded(withCallId: call.callId)
|
||||
case .remotelyOnHold:
|
||||
MXLog.debug("[CallPresenter] callStateChanged: call remotely holded: \(call.callId)")
|
||||
callTimer?.fire()
|
||||
callHolded(withCallId: call.callId)
|
||||
case .ended:
|
||||
MXLog.debug("[CallPresenter] callStateChanged: call ended: \(call.callId)")
|
||||
@@ -716,10 +659,6 @@ class CallPresenter: NSObject {
|
||||
// do not use PiP transitions here, as we really want to present the screen
|
||||
callVC.transitioningDelegate = nil
|
||||
|
||||
if let inBarCallVC = inBarCallVC {
|
||||
dismissCallBar(for: inBarCallVC)
|
||||
}
|
||||
|
||||
if let presentedCallVC = presentedCallVC {
|
||||
dismissCallVC(presentedCallVC)
|
||||
}
|
||||
@@ -781,42 +720,6 @@ class CallPresenter: NSObject {
|
||||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
// MARK: - Call Bar
|
||||
|
||||
private func presentCallBar(for callVC: UIViewController, completion: (() -> Void)? = nil) {
|
||||
logCallVC(callVC, log: "presentCallBar")
|
||||
|
||||
let activeCallVC = self.activeCallVC
|
||||
|
||||
let operation = CallBarPresentOperation(presenter: self, activeCallVC: activeCallVC, numberOfPausedCalls: numberOfPausedCalls) { [weak self] in
|
||||
// active calls are more prior to paused ones.
|
||||
// So, if user taps the bar when we have one active and one paused call, we navigate to the active one.
|
||||
self?.inBarCallVC = activeCallVC ?? callVC
|
||||
completion?()
|
||||
}
|
||||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
private func updateCallBar() {
|
||||
let activeCallVC = self.activeCallVC
|
||||
|
||||
let operation = CallBarUpdateOperation(presenter: self, activeCallVC: activeCallVC, numberOfPausedCalls: numberOfPausedCalls)
|
||||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
private func dismissCallBar(for callVC: UIViewController, completion: (() -> Void)? = nil) {
|
||||
logCallVC(callVC, log: "dismissCallBar")
|
||||
|
||||
let operation = CallBarDismissOperation(presenter: self) { [weak self] in
|
||||
if callVC == self?.inBarCallVC {
|
||||
self?.inBarCallVC = nil
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
|
||||
uiOperationQueue.addOperation(operation)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - MXKCallViewControllerDelegate
|
||||
@@ -834,13 +737,8 @@ extension CallPresenter: MXKCallViewControllerDelegate {
|
||||
// wait for the call state changes, will be handled there
|
||||
return
|
||||
} else {
|
||||
if callVC.mxCall.isVideoCall {
|
||||
// go to pip mode here
|
||||
enterPipCallVC(callVC, completion: completion)
|
||||
} else {
|
||||
dismissCallVC(callVC)
|
||||
self.presentCallBar(for: callVC, completion: completion)
|
||||
}
|
||||
// go to pip mode here
|
||||
enterPipCallVC(callVC, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -902,8 +800,8 @@ extension OperationQueue {
|
||||
return containsOperation(ofType: CallVCPresentOperation.self)
|
||||
}
|
||||
|
||||
var containsPresentCallBarOperation: Bool {
|
||||
return containsOperation(ofType: CallBarPresentOperation.self)
|
||||
var containsEnterPiPOperation: Bool {
|
||||
return containsOperation(ofType: CallVCEnterPipOperation.self)
|
||||
}
|
||||
|
||||
private func containsOperation(ofType type: Operation.Type) -> Bool {
|
||||
|
||||
@@ -26,17 +26,6 @@ protocol CallPresenterDelegate: class {
|
||||
dismissCallViewController viewController: UIViewController,
|
||||
completion:(() -> Void)?)
|
||||
|
||||
// Call Bar
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
presentCallBarFor activeCallViewController: UIViewController?,
|
||||
numberOfPausedCalls: UInt,
|
||||
completion:(() -> Void)?)
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
updateCallBarFor activeCallViewController: UIViewController?,
|
||||
numberOfPausedCalls: UInt)
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
dismissCallBar completion:(() -> Void)?)
|
||||
|
||||
// PiP
|
||||
func callPresenter(_ presenter: CallPresenter,
|
||||
enterPipForCallViewController viewController: UIViewController,
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
//
|
||||
// Copyright 2020 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class CallBarPresentOperation: AsyncOperation {
|
||||
|
||||
private var presenter: CallPresenter
|
||||
private var activeCallVC: UIViewController?
|
||||
private var numberOfPausedCalls: UInt
|
||||
private var completion: (() -> Void)?
|
||||
|
||||
init(presenter: CallPresenter,
|
||||
activeCallVC: UIViewController?,
|
||||
numberOfPausedCalls: UInt,
|
||||
completion: (() -> Void)? = nil) {
|
||||
self.presenter = presenter
|
||||
self.activeCallVC = activeCallVC
|
||||
self.numberOfPausedCalls = numberOfPausedCalls
|
||||
self.completion = completion
|
||||
}
|
||||
|
||||
override func main() {
|
||||
presenter.delegate?.callPresenter(presenter, presentCallBarFor: activeCallVC, numberOfPausedCalls: numberOfPausedCalls, completion: {
|
||||
self.finish()
|
||||
// wait for the next life cycle to detect status bar layout updates
|
||||
DispatchQueue.main.async {
|
||||
self.completion?()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
//
|
||||
// Copyright 2020 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class CallBarUpdateOperation: AsyncOperation {
|
||||
|
||||
private var presenter: CallPresenter
|
||||
private var activeCallVC: UIViewController?
|
||||
private var numberOfPausedCalls: UInt
|
||||
|
||||
init(presenter: CallPresenter,
|
||||
activeCallVC: UIViewController?,
|
||||
numberOfPausedCalls: UInt) {
|
||||
self.presenter = presenter
|
||||
self.activeCallVC = activeCallVC
|
||||
self.numberOfPausedCalls = numberOfPausedCalls
|
||||
}
|
||||
|
||||
override func main() {
|
||||
presenter.delegate?.callPresenter(presenter, updateCallBarFor: activeCallVC, numberOfPausedCalls: numberOfPausedCalls)
|
||||
self.finish()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,8 +31,15 @@ class CallVCPresentOperation: AsyncOperation {
|
||||
}
|
||||
|
||||
override func main() {
|
||||
if let pipable = callVC as? PictureInPicturable {
|
||||
pipable.willExitPiP?()
|
||||
}
|
||||
presenter.delegate?.callPresenter(presenter, presentCallViewController: callVC, completion: {
|
||||
self.finish()
|
||||
if let pipable = self.callVC as? PictureInPicturable {
|
||||
pipable.didExitPiP?()
|
||||
self.callVC.view.isUserInteractionEnabled = true
|
||||
}
|
||||
self.completion?()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ class PiPAnimator: NSObject {
|
||||
return
|
||||
}
|
||||
|
||||
if let pipable = fromVC as? PictureInPicturable {
|
||||
pipable.willEnterPiP?()
|
||||
}
|
||||
|
||||
fromVC.willMove(toParent: nil)
|
||||
// TODO: find a way to call this at the end of animation
|
||||
context.completeTransition(true)
|
||||
@@ -65,6 +69,7 @@ class PiPAnimator: NSObject {
|
||||
let scale = Constants.pipViewSize.width/pipView.frame.width
|
||||
let transform = CGAffineTransform(scaleX: scale, y: scale)
|
||||
let targetSize = Constants.pipViewSize
|
||||
pipView.cornerRadius = pipView.cornerRadius / scale
|
||||
|
||||
let animator = UIViewPropertyAnimator(duration: animationDuration, dampingRatio: 1) {
|
||||
pipView.transform = transform
|
||||
@@ -75,7 +80,7 @@ class PiPAnimator: NSObject {
|
||||
|
||||
animator.addCompletion { (position) in
|
||||
if let pipable = fromVC as? PictureInPicturable {
|
||||
pipable.enterPiP?()
|
||||
pipable.didEnterPiP?()
|
||||
}
|
||||
fromVC.dismiss(animated: false, completion: nil)
|
||||
}
|
||||
@@ -89,8 +94,16 @@ class PiPAnimator: NSObject {
|
||||
return
|
||||
}
|
||||
|
||||
guard let toVC = context.viewController(forKey: .to),
|
||||
let snapshot = toVC.view.snapshotView(afterScreenUpdates: true) else {
|
||||
guard let toVC = context.viewController(forKey: .to) else {
|
||||
context.completeTransition(false)
|
||||
return
|
||||
}
|
||||
|
||||
if let pipable = toVC as? PictureInPicturable {
|
||||
pipable.willExitPiP?()
|
||||
}
|
||||
|
||||
guard let snapshot = toVC.view.snapshotView(afterScreenUpdates: true) else {
|
||||
context.completeTransition(false)
|
||||
return
|
||||
}
|
||||
@@ -122,7 +135,7 @@ class PiPAnimator: NSObject {
|
||||
|
||||
snapshot.removeFromSuperview()
|
||||
if let pipable = toVC as? PictureInPicturable {
|
||||
pipable.exitPiP?()
|
||||
pipable.didExitPiP?()
|
||||
}
|
||||
|
||||
context.completeTransition(!context.transitionWasCancelled)
|
||||
|
||||
@@ -18,7 +18,10 @@ import Foundation
|
||||
|
||||
@objc protocol PictureInPicturable {
|
||||
|
||||
@objc optional func enterPiP()
|
||||
@objc optional func exitPiP()
|
||||
@objc optional func willEnterPiP()
|
||||
@objc optional func didEnterPiP()
|
||||
|
||||
@objc optional func willExitPiP()
|
||||
@objc optional func didExitPiP()
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ class EncryptionKeyManager: NSObject, MXKeyProviderDelegate {
|
||||
private static let accountIv: KeyValueStoreKey = "accountIv"
|
||||
private static let accountAesKey: KeyValueStoreKey = "accountAesKey"
|
||||
private static let cryptoOlmPickleKey: KeyValueStoreKey = "cryptoOlmPickleKey"
|
||||
private static let roomLastMessageIv: KeyValueStoreKey = "roomLastMessageIv"
|
||||
private static let roomLastMessageAesKey: KeyValueStoreKey = "roomLastMessageAesKey"
|
||||
|
||||
private let keychainStore: KeyValueStore = KeychainStore(withKeychain: Keychain(service: keychainService, accessGroup: BuildSettings.keychainAccessGroup))
|
||||
|
||||
@@ -43,12 +45,16 @@ class EncryptionKeyManager: NSObject, MXKeyProviderDelegate {
|
||||
generateIvIfNotExists(forKey: EncryptionKeyManager.contactsIv)
|
||||
generateAesKeyIfNotExists(forKey: EncryptionKeyManager.contactsAesKey)
|
||||
generateKeyIfNotExists(forKey: EncryptionKeyManager.cryptoOlmPickleKey, size: 32)
|
||||
generateIvIfNotExists(forKey: EncryptionKeyManager.roomLastMessageIv)
|
||||
generateAesKeyIfNotExists(forKey: EncryptionKeyManager.roomLastMessageAesKey)
|
||||
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.contactsIv), "[EncryptionKeyManager] initKeys: Failed to generate IV for acount")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.contactsAesKey), "[EncryptionKeyManager] initKeys: Failed to generate AES Key for acount")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.contactsIv), "[EncryptionKeyManager] initKeys: Failed to generate IV for contacts")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.contactsAesKey), "[EncryptionKeyManager] initKeys: Failed to generate AES Key for contacts")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.cryptoOlmPickleKey), "[EncryptionKeyManager] initKeys: Failed to generate Key for olm pickle key")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.roomLastMessageIv), "[EncryptionKeyManager] initKeys: Failed to generate IV for room last message")
|
||||
assert(keychainStore.containsObject(forKey: EncryptionKeyManager.roomLastMessageAesKey), "[EncryptionKeyManager] initKeys: Failed to generate AES Key for room last message encryption")
|
||||
}
|
||||
|
||||
// MARK: - MXKeyProviderDelegate
|
||||
@@ -57,6 +63,7 @@ class EncryptionKeyManager: NSObject, MXKeyProviderDelegate {
|
||||
return dataType == MXKContactManagerDataType
|
||||
|| dataType == MXKAccountManagerDataType
|
||||
|| dataType == MXCryptoOlmPickleKeyDataType
|
||||
|| dataType == MXRoomLastMessageDataType
|
||||
}
|
||||
|
||||
func hasKeyForData(ofType dataType: String) -> Bool {
|
||||
@@ -67,6 +74,9 @@ class EncryptionKeyManager: NSObject, MXKeyProviderDelegate {
|
||||
return keychainStore.containsObject(forKey: EncryptionKeyManager.accountIv) && keychainStore.containsObject(forKey: EncryptionKeyManager.accountAesKey)
|
||||
case MXCryptoOlmPickleKeyDataType:
|
||||
return keychainStore.containsObject(forKey: EncryptionKeyManager.cryptoOlmPickleKey)
|
||||
case MXRoomLastMessageDataType:
|
||||
return keychainStore.containsObject(forKey: EncryptionKeyManager.roomLastMessageIv) &&
|
||||
keychainStore.containsObject(forKey: EncryptionKeyManager.roomLastMessageAesKey)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -88,6 +98,11 @@ class EncryptionKeyManager: NSObject, MXKeyProviderDelegate {
|
||||
if let key = try? keychainStore.data(forKey: EncryptionKeyManager.cryptoOlmPickleKey) {
|
||||
return MXRawDataKey(key: key)
|
||||
}
|
||||
case MXRoomLastMessageDataType:
|
||||
if let ivKey = try? keychainStore.data(forKey: EncryptionKeyManager.roomLastMessageIv),
|
||||
let aesKey = try? keychainStore.data(forKey: EncryptionKeyManager.roomLastMessageAesKey) {
|
||||
return MXAesKeyData(iv: ivKey, key: aesKey)
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -178,16 +178,17 @@ Matrix session observer used to detect new opened sessions.
|
||||
{
|
||||
[[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications];
|
||||
[[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:nil];
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground
|
||||
{
|
||||
if (_pushNotificationStore.pushKitToken)
|
||||
{
|
||||
self.shouldReceiveVoIPPushes = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive
|
||||
{
|
||||
[[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications];
|
||||
@@ -227,6 +228,8 @@ Matrix session observer used to detect new opened sessions.
|
||||
{
|
||||
_shouldReceiveVoIPPushes = shouldReceiveVoIPPushes;
|
||||
|
||||
MXLogDebug(@"[PushNotificationService] setShouldReceiveVoIPPushes: %u", _shouldReceiveVoIPPushes)
|
||||
|
||||
if (_shouldReceiveVoIPPushes && _pushNotificationStore.pushKitToken)
|
||||
{
|
||||
MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject;
|
||||
@@ -256,16 +259,25 @@ Matrix session observer used to detect new opened sessions.
|
||||
}
|
||||
else
|
||||
{
|
||||
_pushRegistry.delegate = nil;
|
||||
[self deconfigurePushKit];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)configurePushKit
|
||||
{
|
||||
MXLogDebug(@"[PushNotificationService] configurePushKit")
|
||||
|
||||
_pushRegistry.delegate = self;
|
||||
_pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
|
||||
}
|
||||
|
||||
- (void)deconfigurePushKit
|
||||
{
|
||||
MXLogDebug(@"[PushNotificationService] deconfigurePushKit")
|
||||
|
||||
_pushRegistry.delegate = nil;
|
||||
}
|
||||
|
||||
- (void)removePusher:(MXPusher*)pusher inSession:(MXSession*)session
|
||||
{
|
||||
MXLogDebug(@"[PushNotificationService][Push] removePusher: %@", pusher.appId);
|
||||
@@ -547,83 +559,83 @@ Matrix session observer used to detect new opened sessions.
|
||||
[[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications];
|
||||
[[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:roomId];
|
||||
|
||||
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
|
||||
if (@available(iOS 13.0, *))
|
||||
{
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is in bg");
|
||||
// for iOS 13, we'll just report the incoming call in the same runloop. It means we cannot call an async API here.
|
||||
MXEvent *callInvite = [_pushNotificationStore callInviteForEventId:eventId];
|
||||
// remove event
|
||||
[_pushNotificationStore removeCallInviteWithEventId:eventId];
|
||||
MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject;
|
||||
// when we have a VoIP push while the application is killed, session.callManager will not be ready yet. Configure it.
|
||||
[[AppDelegate theDelegate] configureCallManagerIfRequiredForSession:session];
|
||||
|
||||
if (@available(iOS 13.0, *))
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13+, callInvite: %@", callInvite);
|
||||
|
||||
if (callInvite)
|
||||
{
|
||||
// for iOS 13, we'll just report the incoming call in the same runloop. It means we cannot call an async API here.
|
||||
MXEvent *callInvite = [_pushNotificationStore callInviteForEventId:eventId];
|
||||
// remove event
|
||||
[_pushNotificationStore removeCallInviteWithEventId:eventId];
|
||||
MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject;
|
||||
// when we have a VoIP push while the application is killed, session.callManager will not be ready yet. Configure it.
|
||||
[[AppDelegate theDelegate] configureCallManagerIfRequiredForSession:session];
|
||||
// We're using this dispatch_group to continue event stream after cache fully processed.
|
||||
dispatch_group_t dispatchGroup = dispatch_group_create();
|
||||
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: callInvite: %@", callInvite);
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
// Not continuing in completion block here, because PushKit mandates reporting a new call in the same run loop.
|
||||
// 'handleBackgroundSyncCacheIfRequiredWithCompletion' is processing to-device events synchronously.
|
||||
[session handleBackgroundSyncCacheIfRequiredWithCompletion:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
}];
|
||||
|
||||
if (callInvite)
|
||||
if (callInvite.eventType == MXEventTypeCallInvite)
|
||||
{
|
||||
// We're using this dispatch_group to continue event stream after cache fully processed.
|
||||
dispatch_group_t dispatchGroup = dispatch_group_create();
|
||||
|
||||
dispatch_group_enter(dispatchGroup);
|
||||
// Not continuing in completion block here, because PushKit mandates reporting a new call in the same run loop.
|
||||
// 'handleBackgroundSyncCacheIfRequiredWithCompletion' is processing to-device events synchronously.
|
||||
[session handleBackgroundSyncCacheIfRequiredWithCompletion:^{
|
||||
dispatch_group_leave(dispatchGroup);
|
||||
}];
|
||||
|
||||
if (callInvite.eventType == MXEventTypeCallInvite)
|
||||
// process the call invite synchronously
|
||||
[session.callManager handleCallEvent:callInvite];
|
||||
MXCallInviteEventContent *content = [MXCallInviteEventContent modelFromJSON:callInvite.content];
|
||||
MXCall *call = [session.callManager callWithCallId:content.callId];
|
||||
if (call)
|
||||
{
|
||||
// process the call invite synchronously
|
||||
[session.callManager handleCallEvent:callInvite];
|
||||
MXCallInviteEventContent *content = [MXCallInviteEventContent modelFromJSON:callInvite.content];
|
||||
MXCall *call = [session.callManager callWithCallId:content.callId];
|
||||
if (call)
|
||||
{
|
||||
[session.callManager.callKitAdapter reportIncomingCall:call];
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId);
|
||||
|
||||
// Wait for the sync response in cache to be processed for data integrity.
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
// After reporting the call, we can continue async. Launch a background sync to handle call answers/declines on other devices of the user.
|
||||
[self launchBackgroundSync];
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId);
|
||||
}
|
||||
}
|
||||
else if ([callInvite.type isEqualToString:kWidgetMatrixEventTypeString] ||
|
||||
[callInvite.type isEqualToString:kWidgetModularEventTypeString])
|
||||
{
|
||||
[[AppDelegate theDelegate].callPresenter processWidgetEvent:callInvite
|
||||
inSession:session];
|
||||
[session.callManager.callKitAdapter reportIncomingCall:call];
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId);
|
||||
|
||||
// Wait for the sync response in cache to be processed for data integrity.
|
||||
dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
|
||||
// After reporting the call, we can continue async. Launch a background sync to handle call answers/declines on other devices of the user.
|
||||
[self launchBackgroundSync];
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a serious error. There is nothing to avoid iOS to kill us here.
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: We have an unknown type of event for %@. There is something wrong.", eventId);
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId);
|
||||
}
|
||||
}
|
||||
else if ([callInvite.type isEqualToString:kWidgetMatrixEventTypeString] ||
|
||||
[callInvite.type isEqualToString:kWidgetModularEventTypeString])
|
||||
{
|
||||
[[AppDelegate theDelegate].callPresenter processWidgetEvent:callInvite
|
||||
inSession:session];
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's a serious error. There is nothing to avoid iOS to kill us here.
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13 and in bg, but we don't have the callInvite event for the eventId: %@. There is something wrong.", eventId);
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: We have an unknown type of event for %@. There is something wrong.", eventId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// below iOS 13, we can call an async API. After background sync, we'll hopefully fetch the call invite and report a new call to the CallKit.
|
||||
[self launchBackgroundSync];
|
||||
// It's a serious error. There is nothing to avoid iOS to kill us here.
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13+, but we don't have the callInvite event for the eventId: %@.", eventId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is not in bg. There is something wrong.");
|
||||
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
|
||||
{
|
||||
// below iOS 13, we don't have to report a call immediately.
|
||||
// We can wait for a call invite from event stream and process.
|
||||
MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Below iOS 13 and active app. Do nothing.");
|
||||
completion();
|
||||
return;
|
||||
}
|
||||
|
||||
// below iOS 13, we can call an async API. After background sync, we'll hopefully fetch the call invite and report a new call to the CallKit.
|
||||
[self launchBackgroundSync];
|
||||
}
|
||||
|
||||
completion();
|
||||
|
||||
@@ -70,6 +70,18 @@ class UserSessionsService: NSObject {
|
||||
self.removeUserSession(relatedToAccount: account, postNotification: true)
|
||||
}
|
||||
|
||||
func removeUserSession(relatedToMatrixSession matrixSession: MXSession) {
|
||||
let foundUserSession = self.userSessions.first { (userSession) -> Bool in
|
||||
userSession.matrixSession == matrixSession
|
||||
}
|
||||
|
||||
guard let userSessionToRemove = foundUserSession else {
|
||||
return
|
||||
}
|
||||
|
||||
self.removeUserSession(relatedToAccount: userSessionToRemove.account)
|
||||
}
|
||||
|
||||
func isUserSessionExists(withUserId userId: String) -> Bool {
|
||||
return self.userSessions.contains { (userSession) -> Bool in
|
||||
return userSession.userId == userId
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class AppAlertPresenter: AlertPresentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// swiftlint:disable weak_delegate
|
||||
private let legacyAppDelegate: LegacyAppDelegate
|
||||
// swiftlint:enable weak_delegate
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(legacyAppDelegate: LegacyAppDelegate) {
|
||||
self.legacyAppDelegate = legacyAppDelegate
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func showError(_ error: Error, animated: Bool, completion: (() -> Void)?) {
|
||||
// FIXME: Present an error on coordinator.toPresentable()
|
||||
self.legacyAppDelegate.showError(asAlert: error)
|
||||
}
|
||||
|
||||
func show(title: String?, message: String?, animated: Bool, completion: (() -> Void)?) {
|
||||
// FIXME: Present an error on coordinator.toPresentable()
|
||||
self.legacyAppDelegate.showAlert(withTitle: title, message: message)
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
import Foundation
|
||||
import Intents
|
||||
|
||||
#if DEBUG
|
||||
import FLEX
|
||||
#endif
|
||||
|
||||
/// The AppCoordinator is responsible of screen navigation and data injection at root application level. It decides if authentication or home screen should be shown and inject data needed for these flows, it changes the navigation stack on deep link, displays global warning.
|
||||
/// This class should avoid to contain too many data management code not related to screen navigation logic. For example `MXSession` or push notification management should be handled in dedicated classes and report only navigation changes to the AppCoordinator.
|
||||
final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
@@ -30,11 +34,16 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
// MARK: Private
|
||||
|
||||
private let rootRouter: RootRouterType
|
||||
// swiftlint:disable weak_delegate
|
||||
private let legacyAppDelegate: LegacyAppDelegate = AppDelegate.theDelegate()
|
||||
// swiftlint:disable weak_delegate
|
||||
fileprivate let legacyAppDelegate: LegacyAppDelegate = AppDelegate.theDelegate()
|
||||
// swiftlint:enable weak_delegate
|
||||
|
||||
private lazy var appNavigator: AppNavigatorProtocol = {
|
||||
return AppNavigator(appCoordinator: self)
|
||||
}()
|
||||
|
||||
private weak var splitViewCoordinator: SplitViewCoordinatorType?
|
||||
fileprivate weak var sideMenuCoordinator: SideMenuCoordinatorType?
|
||||
|
||||
private let userSessionsService: UserSessionsService
|
||||
|
||||
@@ -49,16 +58,26 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(router: RootRouterType) {
|
||||
init(router: RootRouterType, window: UIWindow) {
|
||||
self.rootRouter = router
|
||||
self.customSchemeURLParser = CustomSchemeURLParser()
|
||||
self.userSessionsService = UserSessionsService()
|
||||
|
||||
super.init()
|
||||
|
||||
setupFlexDebuggerOnWindow(window)
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
func start() {
|
||||
// NOTE: When split view is shown there can be no Matrix sessions ready. Keep this behavior or use a loading screen before showing the spit view.
|
||||
self.setupTheme()
|
||||
|
||||
if BuildSettings.enableSideMenu {
|
||||
self.addSideMenu()
|
||||
}
|
||||
|
||||
// NOTE: When split view is shown there can be no Matrix sessions ready. Keep this behavior or use a loading screen before showing the split view.
|
||||
self.showSplitView()
|
||||
MXLog.debug("[AppCoordinator] Showed split view")
|
||||
}
|
||||
@@ -77,6 +96,10 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func setupTheme() {
|
||||
ThemeService.shared().themeId = RiotSettings.shared.userInterfaceTheme
|
||||
}
|
||||
|
||||
private func showAuthentication() {
|
||||
// TODO: Implement
|
||||
}
|
||||
@@ -90,7 +113,7 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
}
|
||||
|
||||
private func showSplitView() {
|
||||
let coordinatorParameters = SplitViewCoordinatorParameters(router: self.rootRouter, userSessionsService: self.userSessionsService)
|
||||
let coordinatorParameters = SplitViewCoordinatorParameters(router: self.rootRouter, userSessionsService: self.userSessionsService, appNavigator: self.appNavigator)
|
||||
|
||||
let splitViewCoordinator = SplitViewCoordinator(parameters: coordinatorParameters)
|
||||
splitViewCoordinator.delegate = self
|
||||
@@ -99,13 +122,19 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
self.splitViewCoordinator = splitViewCoordinator
|
||||
}
|
||||
|
||||
private func checkAppVersion() {
|
||||
// TODO: Implement
|
||||
private func addSideMenu() {
|
||||
let appInfo = AppInfo.current
|
||||
let coordinatorParameters = SideMenuCoordinatorParameters(userSessionsService: self.userSessionsService, appInfo: appInfo)
|
||||
|
||||
let coordinator = SideMenuCoordinator(parameters: coordinatorParameters)
|
||||
coordinator.delegate = self
|
||||
coordinator.start()
|
||||
self.add(childCoordinator: coordinator)
|
||||
self.sideMenuCoordinator = coordinator
|
||||
}
|
||||
|
||||
private func showError(_ error: Error) {
|
||||
// FIXME: Present an error on coordinator.toPresentable()
|
||||
self.legacyAppDelegate.showError(asAlert: error)
|
||||
private func checkAppVersion() {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
private func handleDeepLinkOption(_ deepLinkOption: DeepLinkOption) -> Bool {
|
||||
@@ -119,6 +148,21 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
|
||||
return canOpenLink
|
||||
}
|
||||
|
||||
private func setupFlexDebuggerOnWindow(_ window: UIWindow) {
|
||||
#if DEBUG
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showFlexDebugger))
|
||||
tapGestureRecognizer.numberOfTouchesRequired = 2
|
||||
tapGestureRecognizer.numberOfTapsRequired = 2
|
||||
window.addGestureRecognizer(tapGestureRecognizer)
|
||||
#endif
|
||||
}
|
||||
|
||||
@objc private func showFlexDebugger() {
|
||||
#if DEBUG
|
||||
FLEXManager.shared.showExplorer()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - LegacyAppDelegateDelegate
|
||||
@@ -139,6 +183,8 @@ extension AppCoordinator: LegacyAppDelegateDelegate {
|
||||
}
|
||||
|
||||
func legacyAppDelegate(_ legacyAppDelegate: LegacyAppDelegate!, didRemoveMatrixSession session: MXSession!) {
|
||||
// Handle user session removal on clear cache. On clear cache the account has his session closed but the account is not removed.
|
||||
self.userSessionsService.removeUserSession(relatedToMatrixSession: session)
|
||||
}
|
||||
|
||||
func legacyAppDelegate(_ legacyAppDelegate: LegacyAppDelegate!, didAdd account: MXKAccount!) {
|
||||
@@ -156,3 +202,33 @@ extension AppCoordinator: SplitViewCoordinatorDelegate {
|
||||
self.legacyAppDelegate.authenticationDidComplete()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SideMenuCoordinatorDelegate
|
||||
extension AppCoordinator: SideMenuCoordinatorDelegate {
|
||||
func sideMenuCoordinator(_ coordinator: SideMenuCoordinatorType, didTapMenuItem menuItem: SideMenuItem, fromSourceView sourceView: UIView) {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - AppNavigator
|
||||
|
||||
// swiftlint:disable private_over_fileprivate
|
||||
fileprivate class AppNavigator: AppNavigatorProtocol {
|
||||
// swiftlint:enable private_over_fileprivate
|
||||
|
||||
private unowned let appCoordinator: AppCoordinator
|
||||
|
||||
let alert: AlertPresentable
|
||||
|
||||
lazy var sideMenu: SideMenuPresentable = {
|
||||
guard let sideMenuCoordinator = appCoordinator.sideMenuCoordinator else {
|
||||
fatalError("sideMenuCoordinator is not initialized")
|
||||
}
|
||||
|
||||
return SideMenuPresenter(sideMenuCoordinator: sideMenuCoordinator)
|
||||
}()
|
||||
|
||||
init(appCoordinator: AppCoordinator) {
|
||||
self.appCoordinator = appCoordinator
|
||||
self.alert = AppAlertPresenter(legacyAppDelegate: appCoordinator.legacyAppDelegate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
|
||||
// Setup window
|
||||
let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
self.window = window
|
||||
@@ -64,7 +62,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
// Create AppCoordinator
|
||||
self.rootRouter = RootRouter(window: window)
|
||||
|
||||
let appCoordinator = AppCoordinator(router: self.rootRouter)
|
||||
let appCoordinator = AppCoordinator(router: self.rootRouter, window: window)
|
||||
appCoordinator.start()
|
||||
self.legacyAppDelegate.delegate = appCoordinator
|
||||
|
||||
|
||||
@@ -256,14 +256,6 @@ UINavigationControllerDelegate
|
||||
*/
|
||||
@property (nonatomic, readonly) JitsiViewController *jitsiViewController;
|
||||
|
||||
#pragma mark - Call status handling
|
||||
|
||||
/**
|
||||
Call status window displayed when user goes back to app during a call.
|
||||
*/
|
||||
@property (nonatomic, readonly) UIWindow* callStatusBarWindow;
|
||||
@property (nonatomic, readonly) CallBar* callBar;
|
||||
|
||||
#pragma mark - App version management
|
||||
|
||||
/**
|
||||
|
||||
@@ -78,9 +78,6 @@
|
||||
|
||||
#define CALL_STATUS_BAR_HEIGHT 44
|
||||
|
||||
#define MAKE_STRING(x) #x
|
||||
#define MAKE_NS_STRING(x) @MAKE_STRING(x)
|
||||
|
||||
NSString *const kAppDelegateDidTapStatusBarNotification = @"kAppDelegateDidTapStatusBarNotification";
|
||||
NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateNetworkStatusDidChangeNotification";
|
||||
|
||||
@@ -90,7 +87,7 @@ NSString *const AppDelegateDidValidateEmailNotificationClientSecretKey = @"AppDe
|
||||
|
||||
NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUniversalLinkDidChangeNotification";
|
||||
|
||||
@interface LegacyAppDelegate () <GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate, PushNotificationServiceDelegate, SetPinCoordinatorBridgePresenterDelegate, CallPresenterDelegate, CallBarDelegate>
|
||||
@interface LegacyAppDelegate () <GDPRConsentViewControllerDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, ServiceTermsModalCoordinatorBridgePresenterDelegate, PushNotificationServiceDelegate, SetPinCoordinatorBridgePresenterDelegate, CallPresenterDelegate>
|
||||
{
|
||||
/**
|
||||
Reachability observer
|
||||
@@ -230,6 +227,8 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
|
||||
@property (nonatomic, strong) SpaceFeatureUnavailablePresenter *spaceFeatureUnavailablePresenter;
|
||||
|
||||
@property (nonatomic, strong) AppInfo *appInfo;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LegacyAppDelegate
|
||||
@@ -304,38 +303,12 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
|
||||
- (NSString*)appVersion
|
||||
{
|
||||
if (!_appVersion)
|
||||
{
|
||||
_appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
return _appVersion;
|
||||
return self.appInfo.appVersion.bundleShortVersion;
|
||||
}
|
||||
|
||||
- (NSString*)build
|
||||
{
|
||||
if (!_build)
|
||||
{
|
||||
NSString *buildBranch = nil;
|
||||
NSString *buildNumber = nil;
|
||||
// Check whether GIT_BRANCH and BUILD_NUMBER were provided during compilation in command line argument.
|
||||
#ifdef GIT_BRANCH
|
||||
buildBranch = MAKE_NS_STRING(GIT_BRANCH);
|
||||
#endif
|
||||
#ifdef BUILD_NUMBER
|
||||
buildNumber = [NSString stringWithFormat:@"#%@", @(BUILD_NUMBER)];
|
||||
#endif
|
||||
if (buildBranch && buildNumber)
|
||||
{
|
||||
_build = [NSString stringWithFormat:@"%@ %@", buildBranch, buildNumber];
|
||||
} else if (buildNumber){
|
||||
_build = buildNumber;
|
||||
} else
|
||||
{
|
||||
_build = buildBranch ? buildBranch : NSLocalizedStringFromTable(@"settings_config_no_build_info", @"Vector", nil);
|
||||
}
|
||||
}
|
||||
return _build;
|
||||
return self.appInfo.buildInfo.readableBuildVersion;
|
||||
}
|
||||
|
||||
- (void)setIsOffline:(BOOL)isOffline
|
||||
@@ -396,18 +369,14 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
|
||||
MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: isProtectedDataAvailable: %@", @([application isProtectedDataAvailable]));
|
||||
|
||||
if (![application isProtectedDataAvailable])
|
||||
{
|
||||
MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: Terminating the app because protected data not available");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
_configuration = [AppConfiguration new];
|
||||
|
||||
self.appInfo = AppInfo.current;
|
||||
|
||||
// Log app information
|
||||
NSString *appDisplayName = [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"];
|
||||
NSString* appVersion = [AppDelegate theDelegate].appVersion;
|
||||
NSString* build = [AppDelegate theDelegate].build;
|
||||
NSString *appDisplayName = self.appInfo.displayName;
|
||||
NSString* appVersion = self.appVersion;
|
||||
NSString* build = self.build;
|
||||
|
||||
MXLogDebug(@"------------------------------");
|
||||
MXLogDebug(@"Application info:");
|
||||
@@ -2878,7 +2847,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
void (^onFailure)(NSError *) = ^(NSError *error){
|
||||
MXLogDebug(@"[AppDelegate] Create direct chat failed");
|
||||
//Alert user
|
||||
[self showErrorAsAlert:error];
|
||||
[self showAlertWithTitle:nil message:NSLocalizedStringFromTable(@"room_creation_dm_error", @"Vector", nil)];
|
||||
|
||||
if (completion)
|
||||
{
|
||||
@@ -3189,117 +3158,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
completion:nil];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Call status handling
|
||||
|
||||
/// Returns a suitable height for call status bar. Considers safe area insets if available and notch status.
|
||||
- (CGFloat)calculateCallStatusBarHeight
|
||||
{
|
||||
CGFloat result = CALL_STATUS_BAR_HEIGHT;
|
||||
if (@available(iOS 11.0, *))
|
||||
{
|
||||
if (UIDevice.currentDevice.hasNotch)
|
||||
{
|
||||
// this device has a notch (iPhone X +)
|
||||
result += UIApplication.sharedApplication.keyWindow.safeAreaInsets.top;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)displayCallStatusBarWithTitle:(NSString*)title
|
||||
{
|
||||
// Add a call status bar
|
||||
CGSize topBarSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width, [self calculateCallStatusBarHeight]);
|
||||
|
||||
_callStatusBarWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, topBarSize.width, topBarSize.height)];
|
||||
_callStatusBarWindow.windowLevel = UIWindowLevelStatusBar;
|
||||
|
||||
// Create statusBarButton
|
||||
_callBar = [CallBar instantiate];
|
||||
_callBar.frame = _callStatusBarWindow.bounds;
|
||||
_callBar.title = title;
|
||||
_callBar.backgroundColor = ThemeService.shared.theme.tintColor;
|
||||
_callBar.delegate = self;
|
||||
_callBar.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
|
||||
// Set call bar view as the view of the root view controller
|
||||
UIViewController *viewController = [[UIViewController alloc] init];
|
||||
viewController.view = _callBar;
|
||||
_callStatusBarWindow.rootViewController = viewController;
|
||||
|
||||
_callStatusBarWindow.hidden = NO;
|
||||
[self deviceOrientationDidChange];
|
||||
|
||||
// We need to listen to the device orientation change events to refresh the root controller frame.
|
||||
// Else the navigation bar position will be wrong.
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(deviceOrientationDidChange)
|
||||
name:UIDeviceOrientationDidChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)updateCallStatusBarWithTitle:(NSString*)title
|
||||
{
|
||||
_callBar.title = title;
|
||||
}
|
||||
|
||||
- (void)removeCallStatusBar
|
||||
{
|
||||
if (_callStatusBarWindow)
|
||||
{
|
||||
// No more need to listen to device orientation changes
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
|
||||
// Hide & destroy it
|
||||
_callStatusBarWindow.hidden = YES;
|
||||
[_callBar removeFromSuperview];
|
||||
_callBar = nil;
|
||||
_callStatusBarWindow = nil;
|
||||
|
||||
[self deviceOrientationDidChange];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)deviceOrientationDidChange
|
||||
{
|
||||
UIApplication *app = [UIApplication sharedApplication];
|
||||
UIViewController *rootController = app.keyWindow.rootViewController;
|
||||
|
||||
// Refresh the root view controller frame
|
||||
CGRect rootControllerFrame = [[UIScreen mainScreen] bounds];
|
||||
|
||||
if (_callStatusBarWindow)
|
||||
{
|
||||
CGFloat callStatusBarHeight = [self calculateCallStatusBarHeight];
|
||||
|
||||
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
|
||||
CGFloat width;
|
||||
|
||||
if (UIDeviceOrientationIsPortrait(deviceOrientation))
|
||||
{
|
||||
width = MIN(rootControllerFrame.size.width, rootControllerFrame.size.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = MAX(rootControllerFrame.size.width, rootControllerFrame.size.height);
|
||||
}
|
||||
|
||||
_callStatusBarWindow.frame = CGRectMake(0, 0, width, callStatusBarHeight);
|
||||
|
||||
// Apply the vertical offset due to call status bar
|
||||
rootControllerFrame.origin.y = callStatusBarHeight;
|
||||
rootControllerFrame.size.height -= callStatusBarHeight;
|
||||
}
|
||||
|
||||
rootController.view.frame = rootControllerFrame;
|
||||
if (rootController.presentedViewController)
|
||||
{
|
||||
rootController.presentedViewController.view.frame = rootControllerFrame;
|
||||
}
|
||||
[rootController.view setNeedsLayout];
|
||||
}
|
||||
|
||||
#pragma mark - Status Bar Tap handling
|
||||
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
@@ -4490,97 +4348,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
}
|
||||
}
|
||||
|
||||
- (void)callPresenter:(CallPresenter *)presenter presentCallBarFor:(UIViewController *)activeCallViewController numberOfPausedCalls:(NSUInteger)numberOfPausedCalls completion:(void (^)(void))completion
|
||||
{
|
||||
[self displayCallStatusBarWithTitle:nil];
|
||||
[self callPresenter:presenter updateCallBarFor:activeCallViewController numberOfPausedCalls:numberOfPausedCalls];
|
||||
|
||||
if (completion)
|
||||
{
|
||||
completion();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)callPresenter:(CallPresenter *)presenter updateCallBarFor:(UIViewController *)activeCallViewController numberOfPausedCalls:(NSUInteger)numberOfPausedCalls
|
||||
{
|
||||
NSString *btnTitle;
|
||||
|
||||
if (activeCallViewController)
|
||||
{
|
||||
NSString *callStatus = @"";
|
||||
BOOL isGroupCall = NO;
|
||||
if ([activeCallViewController isKindOfClass:[CallViewController class]])
|
||||
{
|
||||
CallViewController *activeCallVC = (CallViewController *)activeCallViewController;
|
||||
callStatus = activeCallVC.callStatusLabel.text;
|
||||
}
|
||||
else if ([activeCallViewController isKindOfClass:[JitsiViewController class]])
|
||||
{
|
||||
JitsiViewController *jitsiVC = (JitsiViewController *)activeCallViewController;
|
||||
NSUInteger duration = jitsiVC.callDuration / 1000;
|
||||
NSUInteger secs = duration % 60;
|
||||
NSUInteger mins = (duration / 60) % 60;
|
||||
NSUInteger hours = duration / 3600;
|
||||
if (hours > 0)
|
||||
{
|
||||
callStatus = [NSString stringWithFormat:@"%02tu:%02tu:%02tu", hours, mins, secs];
|
||||
}
|
||||
else
|
||||
{
|
||||
callStatus = [NSString stringWithFormat:@"%02tu:%02tu", mins, secs];
|
||||
}
|
||||
isGroupCall = YES;
|
||||
}
|
||||
|
||||
if (numberOfPausedCalls == 0)
|
||||
{
|
||||
// only one active
|
||||
if (isGroupCall)
|
||||
{
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_only_single_active_group", @"Vector", nil), callStatus];
|
||||
}
|
||||
else
|
||||
{
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_only_single_active", @"Vector", nil), callStatus];
|
||||
}
|
||||
}
|
||||
else if (numberOfPausedCalls == 1)
|
||||
{
|
||||
// one active and one paused
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_active_and_single_paused", @"Vector", nil), callStatus];
|
||||
}
|
||||
else
|
||||
{
|
||||
// one active and multiple paused
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_active_and_multiple_paused", @"Vector", nil), callStatus, @(numberOfPausedCalls)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no active calls
|
||||
if (numberOfPausedCalls == 1)
|
||||
{
|
||||
btnTitle = NSLocalizedStringFromTable(@"callbar_only_single_paused", @"Vector", nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"callbar_only_multiple_paused", @"Vector", nil), @(numberOfPausedCalls)];
|
||||
}
|
||||
}
|
||||
|
||||
[self updateCallStatusBarWithTitle:btnTitle];
|
||||
}
|
||||
|
||||
- (void)callPresenter:(CallPresenter *)presenter dismissCallBar:(void (^)(void))completion
|
||||
{
|
||||
[self removeCallStatusBar];
|
||||
|
||||
if (completion)
|
||||
{
|
||||
completion();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)callPresenter:(CallPresenter *)presenter enterPipForCallViewController:(UIViewController *)viewController completion:(void (^)(void))completion
|
||||
{
|
||||
// Check whether the call view controller is actually presented
|
||||
@@ -4607,13 +4374,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||
[self presentViewController:viewController animated:YES completion:completion];
|
||||
}
|
||||
|
||||
#pragma mark - CallBarDelegate
|
||||
|
||||
- (void)callBarDidTap:(CallBar *)callBar
|
||||
{
|
||||
[_callPresenter callStatusBarTapped];
|
||||
}
|
||||
|
||||
#pragma mark - Authentication
|
||||
|
||||
- (BOOL)continueSSOLoginWithToken:(NSString*)loginToken txnId:(NSString*)txnId
|
||||
|
||||
@@ -37,8 +37,11 @@
|
||||
BOOL promptForStunServerFallback;
|
||||
}
|
||||
|
||||
@property (nonatomic, weak) IBOutlet UIView *pipViewContainer;
|
||||
|
||||
@property (nonatomic, strong) id<Theme> overriddenTheme;
|
||||
@property (nonatomic, assign) BOOL inPiP;
|
||||
@property (nonatomic, strong) CallPiPView *pipView;
|
||||
|
||||
@property (nonatomic, strong) CustomSizedPresentationController *customSizedPresentationController;
|
||||
|
||||
@@ -224,6 +227,8 @@
|
||||
- (void)call:(MXCall *)call stateDidChange:(MXCallState)state reason:(MXEvent *)event
|
||||
{
|
||||
[super call:call stateDidChange:state reason:event];
|
||||
|
||||
[self configurePiPView];
|
||||
|
||||
[self checkStunServerFallbackWithCallState:state];
|
||||
}
|
||||
@@ -379,6 +384,23 @@
|
||||
return _overriddenTheme;
|
||||
}
|
||||
|
||||
- (CallPiPView *)pipView
|
||||
{
|
||||
if (_pipView == nil)
|
||||
{
|
||||
_pipView = [CallPiPView instantiateWithSession:self.mainSession];
|
||||
[_pipView updateWithTheme:self.overriddenTheme];
|
||||
}
|
||||
return _pipView;
|
||||
}
|
||||
|
||||
- (void)setMxCallOnHold:(MXCall *)mxCallOnHold
|
||||
{
|
||||
[super setMxCallOnHold:mxCallOnHold];
|
||||
|
||||
[self configurePiPView];
|
||||
}
|
||||
|
||||
- (UIImage*)picturePlaceholder
|
||||
{
|
||||
CGFloat fontSize = floor(self.callerImageViewWidthConstraint.constant * 0.7);
|
||||
@@ -502,11 +524,19 @@
|
||||
self.callStatusLabel.hidden = YES;
|
||||
self.localPreviewContainerView.hidden = YES;
|
||||
self.localPreviewActivityView.hidden = YES;
|
||||
|
||||
if (self.pipViewContainer.subviews.count == 0)
|
||||
{
|
||||
[self.pipViewContainer vc_addSubViewMatchingParent:self.pipView];
|
||||
}
|
||||
[self configurePiPView];
|
||||
self.pipViewContainer.hidden = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.localPreviewContainerView.hidden = NO;
|
||||
self.callerImageView.hidden = NO;
|
||||
self.pipViewContainer.hidden = YES;
|
||||
self.localPreviewContainerView.hidden = !self.mxCall.isVideoCall;
|
||||
self.callerImageView.hidden = self.mxCall.isVideoCall && self.mxCall.state == MXCallStateConnected;
|
||||
self.callerNameLabel.hidden = NO;
|
||||
self.callStatusLabel.hidden = NO;
|
||||
|
||||
@@ -644,14 +674,32 @@
|
||||
[viewController dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - PiP
|
||||
|
||||
- (void)configurePiPView
|
||||
{
|
||||
if (self.inPiP)
|
||||
{
|
||||
[self.pipView configureWithCall:self.mxCall
|
||||
peer:self.peer
|
||||
onHoldCall:self.mxCallOnHold
|
||||
onHoldPeer:self.peerOnHold];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - PictureInPicturable
|
||||
|
||||
- (void)enterPiP
|
||||
- (void)didEnterPiP
|
||||
{
|
||||
self.inPiP = YES;
|
||||
}
|
||||
|
||||
- (void)exitPiP
|
||||
- (void)willExitPiP
|
||||
{
|
||||
self.pipViewContainer.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)didExitPiP
|
||||
{
|
||||
self.inPiP = NO;
|
||||
}
|
||||
|
||||
@@ -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_5" 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="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@@ -35,6 +35,7 @@
|
||||
<outlet property="onHoldCallerImageView" destination="uFS-C2-TxV" id="SfP-iP-jgd"/>
|
||||
<outlet property="overlayContainerView" destination="JAR-tn-sGN" id="09u-3G-1UA"/>
|
||||
<outlet property="pausedIcon" destination="rjn-DE-i10" id="CHR-mM-Dae"/>
|
||||
<outlet property="pipViewContainer" destination="sJX-l2-pMa" id="mwA-1T-GHk"/>
|
||||
<outlet property="rejectCallButton" destination="H4g-11-Y8d" id="8aM-2q-Lv7"/>
|
||||
<outlet property="remotePreviewContainerView" destination="Tjb-57-yB1" id="MaR-IC-ZKw"/>
|
||||
<outlet property="resumeButton" destination="OaQ-Ki-dbe" id="23i-sp-y3f"/>
|
||||
@@ -294,7 +295,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="Zc0-eq-2kY">
|
||||
<rect key="frame" x="167" y="311.66666666666669" width="80" height="117"/>
|
||||
<rect key="frame" x="167" y="293" width="80" height="154"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FNb-tG-f7m">
|
||||
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
|
||||
@@ -339,7 +340,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wqv-Uf-iNe" userLabel="Transfer">
|
||||
<rect key="frame" x="11.5" y="176" width="57" height="29"/>
|
||||
<rect key="frame" x="11.666666666666657" y="125" width="57" height="29"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
|
||||
<color key="tintColor" systemColor="systemGreenColor"/>
|
||||
<state key="normal" title="Transfer"/>
|
||||
@@ -447,20 +448,27 @@
|
||||
<constraint firstAttribute="width" constant="144" id="wft-dC-ob6"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sJX-l2-pMa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="r1a-fi-tZ0"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="CallVCView"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="VWv-s0-46r" secondAttribute="bottom" id="25w-l9-NMg"/>
|
||||
<constraint firstItem="sJX-l2-pMa" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="4WB-kY-gwr"/>
|
||||
<constraint firstItem="6gQ-zo-2Zw" firstAttribute="top" secondItem="r1a-fi-tZ0" secondAttribute="top" priority="750" constant="420" id="6gi-ec-ZnO"/>
|
||||
<constraint firstItem="r1a-fi-tZ0" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="6gQ-zo-2Zw" secondAttribute="trailing" constant="20" id="9Om-6f-K9u"/>
|
||||
<constraint firstItem="r1a-fi-tZ0" firstAttribute="trailing" secondItem="VWv-s0-46r" secondAttribute="trailing" id="GX9-dL-Ejl"/>
|
||||
<constraint firstAttribute="trailing" secondItem="sJX-l2-pMa" secondAttribute="trailing" id="H3S-H9-PQq"/>
|
||||
<constraint firstItem="r1a-fi-tZ0" firstAttribute="trailing" secondItem="4TX-46-pAi" secondAttribute="trailing" constant="20" id="PWX-RT-P9p"/>
|
||||
<constraint firstItem="JAR-tn-sGN" firstAttribute="leading" secondItem="r1a-fi-tZ0" secondAttribute="leading" id="QLG-jw-Xph"/>
|
||||
<constraint firstItem="6gQ-zo-2Zw" firstAttribute="leading" secondItem="r1a-fi-tZ0" secondAttribute="leading" priority="750" constant="20" id="Qvg-FG-sBr"/>
|
||||
<constraint firstItem="VWv-s0-46r" firstAttribute="leading" secondItem="r1a-fi-tZ0" secondAttribute="leading" id="SNc-WF-jXg"/>
|
||||
<constraint firstItem="4TX-46-pAi" firstAttribute="top" secondItem="r1a-fi-tZ0" secondAttribute="top" constant="56" id="TQG-q5-eS7"/>
|
||||
<constraint firstAttribute="bottom" secondItem="sJX-l2-pMa" secondAttribute="bottom" id="Vlf-ys-lS2"/>
|
||||
<constraint firstItem="r1a-fi-tZ0" firstAttribute="bottom" secondItem="nk9-Un-LVP" secondAttribute="bottom" constant="20" id="VpW-QU-xiw"/>
|
||||
<constraint firstItem="r1a-fi-tZ0" firstAttribute="trailing" secondItem="JAR-tn-sGN" secondAttribute="trailing" id="Xcc-jT-zbd"/>
|
||||
<constraint firstItem="UGa-hI-iqx" firstAttribute="top" secondItem="r1a-fi-tZ0" secondAttribute="top" constant="120" id="YlJ-XZ-rCM"/>
|
||||
@@ -475,6 +483,7 @@
|
||||
<constraint firstAttribute="trailing" secondItem="Tjb-57-yB1" secondAttribute="trailing" id="rXn-dm-69F"/>
|
||||
<constraint firstItem="6gQ-zo-2Zw" firstAttribute="top" relation="greaterThanOrEqual" secondItem="r1a-fi-tZ0" secondAttribute="top" constant="80" id="tLa-Lx-XbY"/>
|
||||
<constraint firstAttribute="bottom" secondItem="JAR-tn-sGN" secondAttribute="bottom" id="vNS-wR-TjW"/>
|
||||
<constraint firstItem="sJX-l2-pMa" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="yjM-5y-vvH"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="139.13043478260872" y="152.67857142857142"/>
|
||||
</view>
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Reusable
|
||||
|
||||
@objcMembers
|
||||
class CallPiPView: UIView {
|
||||
|
||||
private enum Constants {
|
||||
static let viewWidth: CGFloat = 90
|
||||
static let smallDotWidth: CGFloat = 8
|
||||
static let bigDotWidth: CGFloat = 10
|
||||
static let spaceBetweenDots: CGFloat = 4
|
||||
static let placeholderFontScale: CGFloat = 0.7
|
||||
}
|
||||
|
||||
@IBOutlet private weak var bgView: UIView!
|
||||
@IBOutlet private weak var bgImageView: MXKImageView!
|
||||
|
||||
@IBOutlet private weak var stackView: UIStackView!
|
||||
|
||||
@IBOutlet private weak var mainCallAvatarImageView: MXKImageView! {
|
||||
didSet {
|
||||
mainCallAvatarImageView.clipsToBounds = true
|
||||
mainCallAvatarImageView.layer.cornerRadius = mainCallAvatarImageView.bounds.width/2
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var mainCallPauseIcon: UIImageView!
|
||||
|
||||
@IBOutlet private weak var onHoldCallView: UIView!
|
||||
@IBOutlet private weak var onHoldCallAvatarImageView: MXKImageView! {
|
||||
didSet {
|
||||
onHoldCallAvatarImageView.clipsToBounds = true
|
||||
onHoldCallAvatarImageView.layer.cornerRadius = onHoldCallAvatarImageView.bounds.width/2
|
||||
}
|
||||
}
|
||||
@IBOutlet private weak var onHoldCallEffectView: UIVisualEffectView! {
|
||||
didSet {
|
||||
onHoldCallEffectView.clipsToBounds = true
|
||||
onHoldCallEffectView.layer.cornerRadius = onHoldCallEffectView.bounds.width/2
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet private weak var connectingView: DotsView! {
|
||||
didSet {
|
||||
connectingView.dotMinWidth = self.bounds.width * Constants.smallDotWidth/Constants.viewWidth
|
||||
connectingView.dotMaxWidth = self.bounds.width * Constants.bigDotWidth/Constants.viewWidth
|
||||
connectingView.interSpaceMargin = self.bounds.width * Constants.spaceBetweenDots/Constants.viewWidth
|
||||
}
|
||||
}
|
||||
|
||||
private var theme: Theme = ThemeService.shared().theme
|
||||
private var session: MXSession!
|
||||
|
||||
static func instantiate(withSession session: MXSession) -> CallPiPView {
|
||||
let view = self.loadFromNib()
|
||||
view.session = session
|
||||
return view
|
||||
}
|
||||
|
||||
func configure(withCall mainCall: MXCall,
|
||||
peer: MXUser?,
|
||||
onHoldCall: MXCall?,
|
||||
onHoldPeer: MXUser?) {
|
||||
switch mainCall.state {
|
||||
case .fledgling, .waitLocalMedia, .createOffer, .inviteSent, .ringing, .createAnswer, .connecting:
|
||||
stackView.isHidden = true
|
||||
connectingView.isHidden = false
|
||||
mainCallPauseIcon.isHidden = true
|
||||
default:
|
||||
connectingView.isHidden = true
|
||||
if mainCall.isVideoCall {
|
||||
bgView.isHidden = true
|
||||
stackView.isHidden = true
|
||||
} else {
|
||||
bgView.isHidden = false
|
||||
stackView.isHidden = false
|
||||
}
|
||||
mainCallPauseIcon.isHidden = !mainCall.isOnHold
|
||||
onHoldCallView.isHidden = onHoldCall == nil
|
||||
}
|
||||
|
||||
let bgPlaceholder = placeholderImage(forPeer: peer,
|
||||
call: mainCall,
|
||||
imageView: bgImageView)
|
||||
let mainCallPlaceholder = placeholderImage(forPeer: peer,
|
||||
call: mainCall,
|
||||
imageView: mainCallAvatarImageView)
|
||||
|
||||
bgImageView.contentMode = .scaleAspectFill
|
||||
mainCallAvatarImageView.contentMode = .scaleAspectFill
|
||||
onHoldCallAvatarImageView.contentMode = .scaleAspectFill
|
||||
|
||||
if let avatarUrl = peer?.avatarUrl {
|
||||
bgImageView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder
|
||||
bgImageView.enableInMemoryCache = true
|
||||
|
||||
bgImageView.setImageURI(avatarUrl,
|
||||
withType: nil,
|
||||
andImageOrientation: .up,
|
||||
previewImage: bgPlaceholder,
|
||||
mediaManager: session.mediaManager)
|
||||
|
||||
mainCallAvatarImageView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder
|
||||
mainCallAvatarImageView.enableInMemoryCache = true
|
||||
|
||||
mainCallAvatarImageView.setImageURI(avatarUrl,
|
||||
withType: nil,
|
||||
andImageOrientation: .up,
|
||||
previewImage: mainCallPlaceholder,
|
||||
mediaManager: session.mediaManager)
|
||||
} else {
|
||||
bgImageView.image = bgPlaceholder
|
||||
mainCallAvatarImageView.image = mainCallPlaceholder
|
||||
}
|
||||
|
||||
let onHoldCallPlaceholder = placeholderImage(forPeer: onHoldPeer,
|
||||
call: onHoldCall,
|
||||
imageView: onHoldCallAvatarImageView)
|
||||
|
||||
if let avatarUrl = onHoldPeer?.avatarUrl {
|
||||
onHoldCallAvatarImageView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder
|
||||
onHoldCallAvatarImageView.enableInMemoryCache = true
|
||||
|
||||
onHoldCallAvatarImageView.setImageURI(avatarUrl,
|
||||
withType: nil,
|
||||
andImageOrientation: .up,
|
||||
previewImage: onHoldCallPlaceholder,
|
||||
mediaManager: session.mediaManager)
|
||||
} else {
|
||||
onHoldCallAvatarImageView.image = onHoldCallPlaceholder
|
||||
}
|
||||
}
|
||||
|
||||
private func placeholderImage(forPeer peer: MXUser?,
|
||||
call: MXCall?,
|
||||
imageView: MXKImageView) -> UIImage? {
|
||||
let fontSize = imageView.bounds.width * Constants.placeholderFontScale
|
||||
|
||||
if let peer = peer {
|
||||
return AvatarGenerator.generateAvatar(forMatrixItem: peer.userId,
|
||||
withDisplayName: peer.displayname,
|
||||
size: imageView.bounds.width,
|
||||
andFontSize: fontSize)
|
||||
} else if let room = call?.room {
|
||||
return AvatarGenerator.generateAvatar(forMatrixItem: room.roomId,
|
||||
withDisplayName: room.summary.displayname,
|
||||
size: imageView.bounds.width,
|
||||
andFontSize: fontSize)
|
||||
}
|
||||
|
||||
return MXKTools.paint(Asset.Images.placeholder.image,
|
||||
with: theme.tintColor)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CallPiPView: NibReusable {}
|
||||
|
||||
extension CallPiPView: Themable {
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="18093"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="Nhq-yj-aas" customClass="CallPiPView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="g3V-CO-w55">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleAspectFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2OA-qI-QAp" customClass="MXKImageView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ATO-Ff-TJp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="Vdx-ow-dSJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
<blurEffect style="dark"/>
|
||||
</visualEffectView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="ATO-Ff-TJp" secondAttribute="bottom" id="Oth-Rg-HRL"/>
|
||||
<constraint firstItem="ATO-Ff-TJp" firstAttribute="top" secondItem="g3V-CO-w55" secondAttribute="top" id="Uqs-y5-grh"/>
|
||||
<constraint firstItem="ATO-Ff-TJp" firstAttribute="leading" secondItem="g3V-CO-w55" secondAttribute="leading" id="fXT-eJ-M5E"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ATO-Ff-TJp" secondAttribute="trailing" id="gT9-MU-5YL"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="50" translatesAutoresizingMaskIntoConstraints="NO" id="dw1-5t-Fa9">
|
||||
<rect key="frame" x="97.5" y="241" width="219" height="414"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="m7y-28-xpb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="219" height="219.5"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="XQ2-lw-1Fx" customClass="MXKImageView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="219" height="219.5"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="call_paused_white_icon" translatesAutoresizingMaskIntoConstraints="NO" id="Cvf-KQ-Q52">
|
||||
<rect key="frame" x="64.5" y="64.5" width="90" height="90"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="Cvf-KQ-Q52" secondAttribute="height" multiplier="1:1" id="6zz-6v-j98"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Cvf-KQ-Q52" firstAttribute="centerX" secondItem="m7y-28-xpb" secondAttribute="centerX" id="CDS-n4-L7k"/>
|
||||
<constraint firstAttribute="trailing" secondItem="XQ2-lw-1Fx" secondAttribute="trailing" id="FH7-u6-K33"/>
|
||||
<constraint firstItem="XQ2-lw-1Fx" firstAttribute="leading" secondItem="m7y-28-xpb" secondAttribute="leading" id="TrB-0Y-Pkv"/>
|
||||
<constraint firstItem="Cvf-KQ-Q52" firstAttribute="centerY" secondItem="m7y-28-xpb" secondAttribute="centerY" id="aB5-wL-fma"/>
|
||||
<constraint firstAttribute="bottom" secondItem="XQ2-lw-1Fx" secondAttribute="bottom" id="e4U-gy-OJN"/>
|
||||
<constraint firstAttribute="width" secondItem="m7y-28-xpb" secondAttribute="height" multiplier="1:1" id="eey-Uj-ltE"/>
|
||||
<constraint firstItem="XQ2-lw-1Fx" firstAttribute="top" secondItem="m7y-28-xpb" secondAttribute="top" id="jqZ-qm-wjK"/>
|
||||
<constraint firstItem="Cvf-KQ-Q52" firstAttribute="width" secondItem="m7y-28-xpb" secondAttribute="width" multiplier="0.41" id="zTa-hN-3f6"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cWE-0k-gxK">
|
||||
<rect key="frame" x="37" y="269.5" width="145" height="144.5"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleAspectFill" translatesAutoresizingMaskIntoConstraints="NO" id="MRZ-Tj-GFD" customClass="MXKImageView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="145" height="144.5"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<visualEffectView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8dC-eG-cT1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="145" height="144.5"/>
|
||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="eQ1-SA-eiJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="145" height="144.5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
<blurEffect style="dark"/>
|
||||
</visualEffectView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="call_paused_white_icon" translatesAutoresizingMaskIntoConstraints="NO" id="Os7-T2-TwH">
|
||||
<rect key="frame" x="36.5" y="36" width="72" height="72.5"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="Os7-T2-TwH" secondAttribute="height" multiplier="1:1" id="i0Q-og-tZc"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="MRZ-Tj-GFD" secondAttribute="bottom" id="4vQ-F2-vLn"/>
|
||||
<constraint firstItem="8dC-eG-cT1" firstAttribute="leading" secondItem="cWE-0k-gxK" secondAttribute="leading" id="7LE-Gi-2py"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8dC-eG-cT1" secondAttribute="bottom" id="HsB-l2-kXL"/>
|
||||
<constraint firstItem="MRZ-Tj-GFD" firstAttribute="leading" secondItem="cWE-0k-gxK" secondAttribute="leading" id="V88-1z-YCU"/>
|
||||
<constraint firstItem="MRZ-Tj-GFD" firstAttribute="top" secondItem="cWE-0k-gxK" secondAttribute="top" id="VQ6-0i-ZJl"/>
|
||||
<constraint firstAttribute="trailing" secondItem="MRZ-Tj-GFD" secondAttribute="trailing" id="b0v-Xr-dN7"/>
|
||||
<constraint firstAttribute="width" secondItem="cWE-0k-gxK" secondAttribute="height" multiplier="1:1" id="cpz-Ea-1UY"/>
|
||||
<constraint firstItem="Os7-T2-TwH" firstAttribute="width" secondItem="MRZ-Tj-GFD" secondAttribute="width" multiplier="0.5" id="d1q-Qo-Rb7"/>
|
||||
<constraint firstAttribute="trailing" secondItem="8dC-eG-cT1" secondAttribute="trailing" id="fze-v5-rYt"/>
|
||||
<constraint firstItem="8dC-eG-cT1" firstAttribute="top" secondItem="cWE-0k-gxK" secondAttribute="top" id="mNe-Pb-bek"/>
|
||||
<constraint firstItem="Os7-T2-TwH" firstAttribute="centerX" secondItem="cWE-0k-gxK" secondAttribute="centerX" id="s5I-eW-1kK"/>
|
||||
<constraint firstItem="Os7-T2-TwH" firstAttribute="centerY" secondItem="cWE-0k-gxK" secondAttribute="centerY" id="y5S-wu-Y8S"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</stackView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yTy-AV-IZA" customClass="DotsView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="130.5" y="423" width="153" height="50"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" priority="250" constant="153" id="RfG-gl-t0t"/>
|
||||
<constraint firstAttribute="height" priority="250" constant="50" id="jTM-vB-gPv"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vJ3-gw-o2d"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="g3V-CO-w55" firstAttribute="leading" secondItem="Nhq-yj-aas" secondAttribute="leading" id="40l-3o-ZIS"/>
|
||||
<constraint firstItem="cWE-0k-gxK" firstAttribute="width" secondItem="Nhq-yj-aas" secondAttribute="width" multiplier="0.35" id="79g-Bn-C0o"/>
|
||||
<constraint firstItem="g3V-CO-w55" firstAttribute="top" secondItem="Nhq-yj-aas" secondAttribute="top" id="BeP-Rr-3DW"/>
|
||||
<constraint firstAttribute="trailing" secondItem="g3V-CO-w55" secondAttribute="trailing" id="LmD-2f-B6f"/>
|
||||
<constraint firstItem="dw1-5t-Fa9" firstAttribute="centerY" secondItem="Nhq-yj-aas" secondAttribute="centerY" id="PQx-td-mDC"/>
|
||||
<constraint firstItem="dw1-5t-Fa9" firstAttribute="centerX" secondItem="Nhq-yj-aas" secondAttribute="centerX" id="VQk-dH-mGH"/>
|
||||
<constraint firstItem="yTy-AV-IZA" firstAttribute="centerY" secondItem="Nhq-yj-aas" secondAttribute="centerY" id="f16-3g-VPE"/>
|
||||
<constraint firstItem="m7y-28-xpb" firstAttribute="width" secondItem="Nhq-yj-aas" secondAttribute="width" multiplier="0.53" id="k6u-G0-gmj"/>
|
||||
<constraint firstItem="yTy-AV-IZA" firstAttribute="centerX" secondItem="Nhq-yj-aas" secondAttribute="centerX" id="t3N-FC-MWo"/>
|
||||
<constraint firstAttribute="bottom" secondItem="g3V-CO-w55" secondAttribute="bottom" id="xVn-dm-NkG"/>
|
||||
</constraints>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="bgImageView" destination="2OA-qI-QAp" id="Wqx-I4-HHw"/>
|
||||
<outlet property="bgView" destination="g3V-CO-w55" id="rXb-BJ-cTO"/>
|
||||
<outlet property="connectingView" destination="yTy-AV-IZA" id="PNX-7s-QzT"/>
|
||||
<outlet property="mainCallAvatarImageView" destination="XQ2-lw-1Fx" id="SaP-3f-6j6"/>
|
||||
<outlet property="mainCallPauseIcon" destination="Cvf-KQ-Q52" id="5ZP-01-BDp"/>
|
||||
<outlet property="onHoldCallAvatarImageView" destination="MRZ-Tj-GFD" id="ytr-Jt-c0o"/>
|
||||
<outlet property="onHoldCallEffectView" destination="8dC-eG-cT1" id="iLS-Fd-mPD"/>
|
||||
<outlet property="onHoldCallView" destination="cWE-0k-gxK" id="jrg-bg-dpM"/>
|
||||
<outlet property="stackView" destination="dw1-5t-Fa9" id="70n-QK-kCx"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-536" y="726"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="call_paused_white_icon" width="20" height="20"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// Copyright 2020 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Reusable
|
||||
|
||||
@objc protocol CallBarDelegate: class {
|
||||
func callBarDidTap(_ callBar: CallBar)
|
||||
}
|
||||
|
||||
@objcMembers
|
||||
class CallBar: UIView, NibLoadable {
|
||||
|
||||
@IBOutlet private weak var titleLabel: UILabel!
|
||||
|
||||
weak var delegate: CallBarDelegate?
|
||||
|
||||
static func instantiate() -> CallBar {
|
||||
return CallBar.loadFromNib()
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGestureRecognized(_:)))
|
||||
addGestureRecognizer(tapRecognizer)
|
||||
}
|
||||
|
||||
var title: String? {
|
||||
get {
|
||||
return titleLabel.text
|
||||
} set {
|
||||
titleLabel.text = newValue
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private func tapGestureRecognized(_ sender: UITapGestureRecognizer) {
|
||||
delegate?.callBarDidTap(self)
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?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">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="CallBar" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eee-sW-qFO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="249" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4TV-K4-7lO">
|
||||
<rect key="frame" x="16" y="4" width="382" height="36"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="4TV-K4-7lO" secondAttribute="trailing" constant="16" id="0K7-QJ-OZO"/>
|
||||
<constraint firstAttribute="bottom" secondItem="4TV-K4-7lO" secondAttribute="bottom" constant="4" id="cij-lT-Nw6"/>
|
||||
<constraint firstAttribute="height" constant="44" id="g8Q-T8-geN"/>
|
||||
<constraint firstItem="4TV-K4-7lO" firstAttribute="leading" secondItem="eee-sW-qFO" secondAttribute="leading" constant="16" id="ilZ-Fq-aZJ"/>
|
||||
<constraint firstItem="4TV-K4-7lO" firstAttribute="top" secondItem="eee-sW-qFO" secondAttribute="top" constant="4" id="lfW-G9-DaP"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
|
||||
<color key="backgroundColor" red="0.011764705882352941" green="0.70196078431372544" blue="0.50588235294117645" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="eee-sW-qFO" secondAttribute="trailing" id="8uk-4g-uhK"/>
|
||||
<constraint firstAttribute="bottom" secondItem="eee-sW-qFO" secondAttribute="bottom" id="dPh-ko-WYf"/>
|
||||
<constraint firstItem="eee-sW-qFO" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="tfp-6O-DDi"/>
|
||||
</constraints>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="titleLabel" destination="4TV-K4-7lO" id="ZkY-wt-1OH"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="137.68115942028987" y="-187.5"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// AlertPresentable absracts an alert presenter
|
||||
protocol AlertPresentable {
|
||||
|
||||
func showError(_ error: Error, animated: Bool, completion: (() -> Void)?)
|
||||
func show(title: String?, message: String?, animated: Bool, completion: (() -> Void)?)
|
||||
}
|
||||
|
||||
// MARK: Default implementation
|
||||
extension AlertPresentable {
|
||||
|
||||
func showError(_ error: Error) {
|
||||
self.showError(error, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func show(title: String?, message: String?) {
|
||||
self.show(title: title, message: message, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// Base class to support an avatar view
|
||||
/// Note: This class is made to be sublcassed
|
||||
class AvatarView: UIView, Themable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet weak var avatarImageView: MXKImageView! {
|
||||
didSet {
|
||||
self.setupAvatarImageView()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var theme: Theme?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
override var isUserInteractionEnabled: Bool {
|
||||
get {
|
||||
return super.isUserInteractionEnabled
|
||||
}
|
||||
set {
|
||||
super.isUserInteractionEnabled = newValue
|
||||
self.updateAccessibilityTraits()
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicate highlighted state
|
||||
var isHighlighted: Bool = false {
|
||||
didSet {
|
||||
self.updateView()
|
||||
}
|
||||
}
|
||||
|
||||
var action: (() -> Void)?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
private func commonInit() {
|
||||
self.setupGestureRecognizer()
|
||||
self.updateAccessibilityTraits()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
self.commonInit()
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.commonInit()
|
||||
}
|
||||
|
||||
// MARK: - Lifecycle
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
self.avatarImageView.layer.cornerRadius = self.avatarImageView.bounds.height/2
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func fill(with viewData: AvatarViewDataProtocol) {
|
||||
self.updateAvatarImageView(with: viewData)
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
}
|
||||
|
||||
func updateAccessibilityTraits() {
|
||||
// Override in subclass
|
||||
}
|
||||
|
||||
func setupAvatarImageView() {
|
||||
self.avatarImageView.defaultBackgroundColor = UIColor.clear
|
||||
self.avatarImageView.enableInMemoryCache = true
|
||||
self.avatarImageView.layer.masksToBounds = true
|
||||
}
|
||||
|
||||
func updateAvatarImageView(with viewData: AvatarViewDataProtocol) {
|
||||
guard let avatarImageView = self.avatarImageView else {
|
||||
return
|
||||
}
|
||||
|
||||
let defaultavatarImage = AvatarGenerator.generateAvatar(forMatrixItem: viewData.matrixItemId, withDisplayName: viewData.displayName)
|
||||
|
||||
if let avatarUrl = viewData.avatarUrl {
|
||||
avatarImageView.setImageURI(avatarUrl,
|
||||
withType: nil,
|
||||
andImageOrientation: .up,
|
||||
toFitViewSize: avatarImageView.frame.size,
|
||||
with: MXThumbnailingMethodScale,
|
||||
previewImage: defaultavatarImage,
|
||||
mediaManager: viewData.mediaManager)
|
||||
} else {
|
||||
avatarImageView.image = defaultavatarImage
|
||||
}
|
||||
|
||||
avatarImageView.contentMode = .scaleAspectFill
|
||||
}
|
||||
|
||||
func updateView() {
|
||||
// Override in subclass if needed
|
||||
// TODO: Handle highlighted state
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupGestureRecognizer() {
|
||||
let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(buttonAction(_:)))
|
||||
gestureRecognizer.minimumPressDuration = 0
|
||||
self.addGestureRecognizer(gestureRecognizer)
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc private func buttonAction(_ sender: UILongPressGestureRecognizer) {
|
||||
|
||||
let isBackgroundViewTouched = sender.vc_isTouchingInside()
|
||||
|
||||
switch sender.state {
|
||||
case .began, .changed:
|
||||
self.isHighlighted = isBackgroundViewTouched
|
||||
case .ended:
|
||||
self.isHighlighted = false
|
||||
|
||||
if isBackgroundViewTouched {
|
||||
self.action?()
|
||||
}
|
||||
case .cancelled:
|
||||
self.isHighlighted = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// AvatarViewDataProtocol describe a view data that should be given to an AvatarView sublcass
|
||||
protocol AvatarViewDataProtocol {
|
||||
/// Matrix item identifier (user id or room id)
|
||||
var matrixItemId: String { get }
|
||||
|
||||
/// Matrix item display name (user or room display name)
|
||||
var displayName: String? { get }
|
||||
|
||||
/// Matrix item avatar URL (user or room avatar url)
|
||||
var avatarUrl: String? { get }
|
||||
|
||||
/// Matrix media handler
|
||||
var mediaManager: MXMediaManager { get }
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// The state for a room list screens.
|
||||
@objcMembers
|
||||
class RecentsDataSourceState: NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Cells
|
||||
let invitesCellDataArray: [MXKRecentCellDataStoring]
|
||||
let favoriteCellDataArray: [MXKRecentCellDataStoring]
|
||||
let peopleCellDataArray: [MXKRecentCellDataStoring]
|
||||
let conversationCellDataArray: [MXKRecentCellDataStoring]
|
||||
let lowPriorityCellDataArray: [MXKRecentCellDataStoring]
|
||||
let serverNoticeCellDataArray: [MXKRecentCellDataStoring]
|
||||
|
||||
// MARK: Notifications counts
|
||||
let favouriteMissedDiscussionsCount: MissedDiscussionsCount
|
||||
let directMissedDiscussionsCount: MissedDiscussionsCount
|
||||
let groupMissedDiscussionsCount: MissedDiscussionsCount
|
||||
|
||||
// MARK: Unsent counts
|
||||
let unsentMessagesDirectDiscussionsCount: UInt
|
||||
let unsentMessagesGroupDiscussionsCount: UInt
|
||||
|
||||
|
||||
// MARK: - Setup
|
||||
init(invitesCellDataArray: [MXKRecentCellDataStoring],
|
||||
favoriteCellDataArray: [MXKRecentCellDataStoring],
|
||||
peopleCellDataArray: [MXKRecentCellDataStoring],
|
||||
conversationCellDataArray: [MXKRecentCellDataStoring],
|
||||
lowPriorityCellDataArray: [MXKRecentCellDataStoring],
|
||||
serverNoticeCellDataArray: [MXKRecentCellDataStoring],
|
||||
favouriteMissedDiscussionsCount: MissedDiscussionsCount,
|
||||
directMissedDiscussionsCount: MissedDiscussionsCount,
|
||||
groupMissedDiscussionsCount: MissedDiscussionsCount,
|
||||
unsentMessagesDirectDiscussionsCount: UInt,
|
||||
unsentMessagesGroupDiscussionsCount: UInt) {
|
||||
self.invitesCellDataArray = invitesCellDataArray
|
||||
self.favoriteCellDataArray = favoriteCellDataArray
|
||||
self.peopleCellDataArray = peopleCellDataArray
|
||||
self.conversationCellDataArray = conversationCellDataArray
|
||||
self.lowPriorityCellDataArray = lowPriorityCellDataArray
|
||||
self.serverNoticeCellDataArray = serverNoticeCellDataArray
|
||||
self.favouriteMissedDiscussionsCount = favouriteMissedDiscussionsCount
|
||||
self.directMissedDiscussionsCount = directMissedDiscussionsCount
|
||||
self.groupMissedDiscussionsCount = groupMissedDiscussionsCount
|
||||
self.unsentMessagesDirectDiscussionsCount = unsentMessagesDirectDiscussionsCount
|
||||
self.unsentMessagesGroupDiscussionsCount = unsentMessagesGroupDiscussionsCount
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Noticiations counts per section
|
||||
@objcMembers
|
||||
class MissedDiscussionsCount: NSObject {
|
||||
/// Regular notifications
|
||||
var count: UInt = 0
|
||||
|
||||
/// Mentions like notications
|
||||
var highlightCount: UInt = 0
|
||||
}
|
||||
@@ -72,6 +72,8 @@
|
||||
|
||||
@property (nonatomic, strong) SpaceFeatureUnavailablePresenter *spaceFeatureUnavailablePresenter;
|
||||
|
||||
@property (nonatomic, strong) CustomSizedPresentationController *customSizedPresentationController;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RecentsViewController
|
||||
@@ -1796,6 +1798,24 @@
|
||||
|
||||
}]];
|
||||
|
||||
if (self.mainSession.callManager.supportsPSTN)
|
||||
{
|
||||
[currentAlert addAction:[UIAlertAction
|
||||
actionWithTitle:NSLocalizedStringFromTable(@"room_open_dialpad", @"Vector", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->currentAlert = nil;
|
||||
|
||||
[self openDialpad];
|
||||
}
|
||||
|
||||
}]];
|
||||
}
|
||||
|
||||
[currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction * action) {
|
||||
@@ -1815,6 +1835,46 @@
|
||||
[self presentViewController:currentAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)openDialpad
|
||||
{
|
||||
DialpadViewController *controller = [DialpadViewController instantiateWithConfiguration:[DialpadConfiguration default]];
|
||||
controller.delegate = self;
|
||||
self.customSizedPresentationController = [[CustomSizedPresentationController alloc] initWithPresentedViewController:controller presentingViewController:self];
|
||||
self.customSizedPresentationController.dismissOnBackgroundTap = NO;
|
||||
self.customSizedPresentationController.cornerRadius = 16;
|
||||
|
||||
controller.transitioningDelegate = self.customSizedPresentationController;
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)dialpadViewControllerDidTapCall:(DialpadViewController *)viewController withPhoneNumber:(NSString *)phoneNumber
|
||||
{
|
||||
if (self.mainSession.callManager && phoneNumber.length > 0)
|
||||
{
|
||||
[self startActivityIndicator];
|
||||
|
||||
[viewController dismissViewControllerAnimated:YES completion:^{
|
||||
MXWeakify(self);
|
||||
[self.mainSession.callManager placeCallAgainst:phoneNumber withVideo:NO success:^(MXCall * _Nonnull call) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self stopActivityIndicator];
|
||||
self.customSizedPresentationController = nil;
|
||||
|
||||
// do nothing extra here. UI will be handled automatically by the CallService.
|
||||
} failure:^(NSError * _Nullable error) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[self stopActivityIndicator];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dialpadViewControllerDidTapClose:(DialpadViewController *)viewController
|
||||
{
|
||||
[viewController dismissViewControllerAnimated:YES completion:nil];
|
||||
self.customSizedPresentationController = nil;
|
||||
}
|
||||
|
||||
- (void)createNewRoom
|
||||
{
|
||||
// Sanity check
|
||||
@@ -2113,4 +2173,50 @@
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
- (void)roomsDirectoryCoordinatorBridgePresenterDelegate:(RoomsDirectoryCoordinatorBridgePresenter *)coordinatorBridgePresenter didSelectRoomWithIdOrAlias:(NSString * _Nonnull)roomIdOrAlias
|
||||
{
|
||||
MXRoom *room = [self.mainSession vc_roomWithIdOrAlias:roomIdOrAlias];
|
||||
|
||||
if (room)
|
||||
{
|
||||
// Room is known show it directly
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession restoreInitialDisplay:NO];
|
||||
}];
|
||||
coordinatorBridgePresenter = nil;
|
||||
}
|
||||
else if ([MXTools isMatrixRoomAlias:roomIdOrAlias])
|
||||
{
|
||||
// Room preview doesn't support room alias
|
||||
[[AppDelegate theDelegate] showAlertWithTitle:[NSBundle mxk_localizedStringForKey:@"error"] message:NSLocalizedStringFromTable(@"room_recents_unknown_room_error_message", @"Vector", nil)];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to preview the room from his id
|
||||
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithRoomId:roomIdOrAlias
|
||||
andSession:self.mainSession];
|
||||
|
||||
[self startActivityIndicator];
|
||||
|
||||
// Try to get more information about the room before opening its preview
|
||||
MXWeakify(self);
|
||||
|
||||
[roomPreviewData peekInRoom:^(BOOL succeeded) {
|
||||
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[self stopActivityIndicator];
|
||||
|
||||
if (succeeded) {
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[[AppDelegate theDelegate].masterTabBarController showRoomPreview:roomPreviewData];
|
||||
}];
|
||||
self.roomsDirectoryCoordinatorBridgePresenter = nil;
|
||||
} else {
|
||||
[[AppDelegate theDelegate] showAlertWithTitle:[NSBundle mxk_localizedStringForKey:@"error"] message:NSLocalizedStringFromTable(@"room_recents_unknown_room_error_message", @"Vector", nil)];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -688,12 +688,16 @@
|
||||
NSUInteger index = [filteredLocalContacts indexOfObject:contact];
|
||||
if (index != NSNotFound)
|
||||
{
|
||||
indexPath = [NSIndexPath indexPathForRow:index inSection:filteredLocalContactsSection];
|
||||
// if local section is collapsed there is no cell
|
||||
if (!(shrinkedSectionsBitMask & CONTACTSDATASOURCE_LOCALCONTACTS_BITWISE)) {
|
||||
indexPath = [NSIndexPath indexPathForRow:index inSection:filteredLocalContactsSection];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
index = [filteredMatrixContacts indexOfObject:contact];
|
||||
if (index != NSNotFound)
|
||||
// if matrix section is collapsed or we are not showing the matrix section(as with empty query) there is no cell
|
||||
if (index != NSNotFound && !(shrinkedSectionsBitMask & CONTACTSDATASOURCE_USERDIRECTORY_BITWISE) && filteredMatrixContactsSection != -1)
|
||||
{
|
||||
indexPath = [NSIndexPath indexPathForRow:index inSection:filteredMatrixContactsSection];
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
|
||||
- (void)presentSecureBackupSetup
|
||||
{
|
||||
SecureBackupSetupCoordinatorBridgePresenter *keyBackupSetupCoordinatorBridgePresenter = [[SecureBackupSetupCoordinatorBridgePresenter alloc] initWithSession:self.mainSession];
|
||||
SecureBackupSetupCoordinatorBridgePresenter *keyBackupSetupCoordinatorBridgePresenter = [[SecureBackupSetupCoordinatorBridgePresenter alloc] initWithSession:self.mainSession allowOverwrite:NO];
|
||||
keyBackupSetupCoordinatorBridgePresenter.delegate = self;
|
||||
|
||||
[keyBackupSetupCoordinatorBridgePresenter presentFrom:self animated:YES];
|
||||
|
||||
@@ -26,6 +26,10 @@ static const NSString *kJitsiDataErrorKey = @"error";
|
||||
Class name for RCTSafeAreaView. It's in the React Native SDK, so we cannot import its header.
|
||||
*/
|
||||
static NSString * _Nonnull kRCTSafeAreaViewClassName = @"RCTSafeAreaView";
|
||||
/**
|
||||
Class name for RCTTextView. It's in the React Native SDK, so we cannot import its header.
|
||||
*/
|
||||
static NSString * _Nonnull kRCTTextViewClassName = @"RCTTextView";
|
||||
|
||||
/*
|
||||
Some feature flags defined in https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.js
|
||||
@@ -281,12 +285,13 @@ static NSString * _Nonnull kJitsiFeatureFlagChatEnabled = @"chat.enabled";
|
||||
}
|
||||
|
||||
/**
|
||||
Finds all the views in self.jitsiMeetView recursively those kind of class with the name `kRCTSafeAreaViewClassName`.
|
||||
Finds all the views in self.jitsiMeetView recursively those kind of class with the name `kRCTSafeAreaViewClassName` or `kRCTTextViewClassName`.
|
||||
*/
|
||||
- (NSArray<UIView*>*)overlayViewsIn:(UIView *)view
|
||||
{
|
||||
Class class = NSClassFromString(kRCTSafeAreaViewClassName);
|
||||
if ([view isKindOfClass:class])
|
||||
Class class1 = NSClassFromString(kRCTSafeAreaViewClassName);
|
||||
Class class2 = NSClassFromString(kRCTTextViewClassName);
|
||||
if ([view isKindOfClass:class1] || [view isKindOfClass:class2])
|
||||
{
|
||||
return @[view];
|
||||
}
|
||||
@@ -346,7 +351,7 @@ static NSString * _Nonnull kJitsiFeatureFlagChatEnabled = @"chat.enabled";
|
||||
|
||||
#pragma mark - PictureInPicturable
|
||||
|
||||
- (void)enterPiP
|
||||
- (void)didEnterPiP
|
||||
{
|
||||
self.overlayViews = [self overlayViewsIn:self.view];
|
||||
for (UIView *view in self.overlayViews)
|
||||
@@ -355,7 +360,7 @@ static NSString * _Nonnull kJitsiFeatureFlagChatEnabled = @"chat.enabled";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)exitPiP
|
||||
- (void)didExitPiP
|
||||
{
|
||||
for (UIView *view in self.overlayViews)
|
||||
{
|
||||
|
||||
@@ -44,11 +44,11 @@ final class KeyBackupSetupCoordinator: KeyBackupSetupCoordinatorType {
|
||||
// MARK: - Public methods
|
||||
|
||||
func start() {
|
||||
|
||||
// Set key backup setup intro as root controller
|
||||
let keyBackupSetupIntroViewController = self.createSetupIntroViewController()
|
||||
keyBackupSetupIntroViewController.delegate = self
|
||||
self.navigationRouter.setRootModule(keyBackupSetupIntroViewController)
|
||||
if self.session.crypto.recoveryService.hasRecovery() {
|
||||
showUnlockSecureBackup()
|
||||
} else {
|
||||
showSetupIntro()
|
||||
}
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
@@ -57,6 +57,13 @@ final class KeyBackupSetupCoordinator: KeyBackupSetupCoordinatorType {
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func showSetupIntro() {
|
||||
// Set key backup setup intro as root controller
|
||||
let keyBackupSetupIntroViewController = self.createSetupIntroViewController()
|
||||
keyBackupSetupIntroViewController.delegate = self
|
||||
self.navigationRouter.setRootModule(keyBackupSetupIntroViewController)
|
||||
}
|
||||
|
||||
private func createSetupIntroViewController() -> KeyBackupSetupIntroViewController {
|
||||
|
||||
let backupState = self.session.crypto.backup?.state ?? MXKeyBackupStateUnknown
|
||||
@@ -80,6 +87,17 @@ final class KeyBackupSetupCoordinator: KeyBackupSetupCoordinatorType {
|
||||
return KeyBackupSetupIntroViewController.instantiate(isABackupAlreadyExists: isABackupAlreadyExists, encryptionKeysExportPresenter: encryptionKeysExportPresenter)
|
||||
}
|
||||
|
||||
private func showUnlockSecureBackup() {
|
||||
let recoveryGoal: SecretsRecoveryGoal = .unlockSecureBackup { (privateKey, completion) in
|
||||
self.createKeyBackupUsingSecureBackup(privateKey: privateKey, completion: completion)
|
||||
}
|
||||
|
||||
let coordinator = SecretsRecoveryCoordinator(session: self.session, recoveryMode: .passphraseOrKey, recoveryGoal: recoveryGoal, navigationRouter: self.navigationRouter)
|
||||
coordinator.delegate = self
|
||||
coordinator.start()
|
||||
self.add(childCoordinator: coordinator)
|
||||
}
|
||||
|
||||
private func showSetupPassphrase(animated: Bool) {
|
||||
let keyBackupSetupPassphraseCoordinator = KeyBackupSetupPassphraseCoordinator(session: self.session)
|
||||
keyBackupSetupPassphraseCoordinator.delegate = self
|
||||
@@ -104,6 +122,33 @@ final class KeyBackupSetupCoordinator: KeyBackupSetupCoordinatorType {
|
||||
viewController.delegate = self
|
||||
self.navigationRouter.push(viewController, animated: animated, popCompletion: nil)
|
||||
}
|
||||
|
||||
private func showSetupWithSecureBackupSuccess(animated: Bool) {
|
||||
let viewController = KeyBackupSetupSuccessFromSecureBackupViewController.instantiate()
|
||||
viewController.delegate = self
|
||||
self.navigationRouter.push(viewController, animated: animated, popCompletion: nil)
|
||||
}
|
||||
|
||||
private func createKeyBackupUsingSecureBackup(privateKey: Data, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
guard let keyBackup = session.crypto.backup, let recoveryService = session.crypto.recoveryService else {
|
||||
return
|
||||
}
|
||||
|
||||
keyBackup.prepareKeyBackupVersion(withPassword: nil, success: { megolmBackupCreationInfo in
|
||||
keyBackup.createKeyBackupVersion(megolmBackupCreationInfo, success: { _ in
|
||||
recoveryService.updateRecovery(forSecrets: [MXSecretId.keyBackup.takeUnretainedValue() as String], withPrivateKey: privateKey) {
|
||||
completion(.success(Void()))
|
||||
} failure: { error in
|
||||
completion(.failure(error))
|
||||
}
|
||||
|
||||
}, failure: { error in
|
||||
completion(.failure(error))
|
||||
})
|
||||
}, failure: { error in
|
||||
completion(.failure(error))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - KeyBackupSetupIntroViewControllerDelegate
|
||||
@@ -133,6 +178,17 @@ extension KeyBackupSetupCoordinator: KeyBackupSetupPassphraseCoordinatorDelegate
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SecretsRecoveryCoordinatorDelegate
|
||||
extension KeyBackupSetupCoordinator: SecretsRecoveryCoordinatorDelegate {
|
||||
func secretsRecoveryCoordinatorDidRecover(_ coordinator: SecretsRecoveryCoordinatorType) {
|
||||
self.showSetupWithSecureBackupSuccess(animated: true)
|
||||
}
|
||||
|
||||
func secretsRecoveryCoordinatorDidCancel(_ coordinator: SecretsRecoveryCoordinatorType) {
|
||||
self.delegate?.keyBackupSetupCoordinatorDidCancel(self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - KeyBackupSetupSuccessFromPassphraseViewControllerDelegate
|
||||
extension KeyBackupSetupCoordinator: KeyBackupSetupSuccessFromPassphraseViewControllerDelegate {
|
||||
func keyBackupSetupSuccessFromPassphraseViewControllerDidTapDoneAction(_ viewController: KeyBackupSetupSuccessFromPassphraseViewController) {
|
||||
@@ -146,3 +202,10 @@ extension KeyBackupSetupCoordinator: KeyBackupSetupSuccessFromRecoveryKeyViewCon
|
||||
self.delegate?.keyBackupSetupCoordinatorDidSetupRecoveryKey(self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - KeyBackupSetupSuccessFromSecureBackupViewControllerDelegate
|
||||
extension KeyBackupSetupCoordinator: KeyBackupSetupSuccessFromSecureBackupViewControllerDelegate {
|
||||
func keyBackupSetupSuccessFromSecureBackupViewControllerDidTapDoneAction(_ viewController: KeyBackupSetupSuccessFromSecureBackupViewController) {
|
||||
self.delegate?.keyBackupSetupCoordinatorDidSetupRecoveryKey(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="b2C-jK-KPV">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Key Backup Setup Success From Secure Backup View Controller-->
|
||||
<scene sceneID="A4c-pi-pNE">
|
||||
<objects>
|
||||
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="b2C-jK-KPV" customClass="KeyBackupSetupSuccessFromSecureBackupViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="YAN-xg-EgW">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="S5g-F9-L3B">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a4X-9Q-mkr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="505"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="o2g-Ga-wwR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="505"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="key_backup_logo" translatesAutoresizingMaskIntoConstraints="NO" id="epg-Qy-eoD">
|
||||
<rect key="frame" x="163.5" y="40" width="48" height="46"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="48" id="V1N-K1-elw"/>
|
||||
<constraint firstAttribute="height" constant="46" id="Yzm-7B-uv2"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="xlp-uc-Mug">
|
||||
<rect key="frame" x="20" y="121" width="335" height="68.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Success!" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="X7g-Ha-15I">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Your keys are being backed up." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3eY-3I-XYH">
|
||||
<rect key="frame" x="0.0" y="50.5" width="335" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</stackView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7aK-CF-d5d">
|
||||
<rect key="frame" x="0.0" y="435" width="375" height="50"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QxC-gf-8VN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="qB9-Kq-7Jw"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
|
||||
<state key="normal" title="Done">
|
||||
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</state>
|
||||
<state key="disabled">
|
||||
<color key="titleColor" red="0.47843137250000001" green="0.78823529410000004" blue="0.63137254899999995" alpha="0.5" colorSpace="calibratedRGB"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="doneButtonAction:" destination="b2C-jK-KPV" eventType="touchUpInside" id="Vs7-qI-yBp"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="QxC-gf-8VN" secondAttribute="bottom" id="HQu-va-hRH"/>
|
||||
<constraint firstAttribute="trailing" secondItem="QxC-gf-8VN" secondAttribute="trailing" id="N4c-nq-GMC"/>
|
||||
<constraint firstItem="QxC-gf-8VN" firstAttribute="leading" secondItem="7aK-CF-d5d" secondAttribute="leading" id="Z8A-af-23Q"/>
|
||||
<constraint firstItem="QxC-gf-8VN" firstAttribute="top" secondItem="7aK-CF-d5d" secondAttribute="top" id="sed-9I-71h"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="7aK-CF-d5d" firstAttribute="leading" secondItem="o2g-Ga-wwR" secondAttribute="leading" id="1Hy-bc-46Y"/>
|
||||
<constraint firstAttribute="width" priority="750" constant="500" id="4a2-Az-ekr"/>
|
||||
<constraint firstItem="epg-Qy-eoD" firstAttribute="centerX" secondItem="o2g-Ga-wwR" secondAttribute="centerX" id="K4J-2Y-7bW"/>
|
||||
<constraint firstItem="xlp-uc-Mug" firstAttribute="leading" secondItem="o2g-Ga-wwR" secondAttribute="leading" constant="20" id="drb-kN-IRX"/>
|
||||
<constraint firstItem="xlp-uc-Mug" firstAttribute="top" secondItem="epg-Qy-eoD" secondAttribute="bottom" constant="35" id="hyp-kS-l81"/>
|
||||
<constraint firstAttribute="bottom" secondItem="7aK-CF-d5d" secondAttribute="bottom" constant="20" id="nPL-nn-PpM"/>
|
||||
<constraint firstItem="epg-Qy-eoD" firstAttribute="top" secondItem="o2g-Ga-wwR" secondAttribute="top" constant="40" id="p1e-CF-Kln"/>
|
||||
<constraint firstAttribute="trailing" secondItem="7aK-CF-d5d" secondAttribute="trailing" id="wl8-ha-UIh"/>
|
||||
<constraint firstAttribute="trailing" secondItem="xlp-uc-Mug" secondAttribute="trailing" constant="20" id="xIU-IL-ycK"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="o2g-Ga-wwR" firstAttribute="centerX" secondItem="a4X-9Q-mkr" secondAttribute="centerX" id="8Ps-hI-nHv"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="o2g-Ga-wwR" secondAttribute="trailing" id="GBk-AU-PAx"/>
|
||||
<constraint firstItem="o2g-Ga-wwR" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="a4X-9Q-mkr" secondAttribute="leading" id="Z9f-1y-sJV"/>
|
||||
<constraint firstAttribute="height" constant="505" id="dth-O0-khE"/>
|
||||
<constraint firstAttribute="bottom" secondItem="o2g-Ga-wwR" secondAttribute="bottom" id="kJP-Gd-vDF"/>
|
||||
<constraint firstItem="o2g-Ga-wwR" firstAttribute="top" secondItem="a4X-9Q-mkr" secondAttribute="top" id="zZX-fo-MMO"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="a4X-9Q-mkr" firstAttribute="top" secondItem="S5g-F9-L3B" secondAttribute="top" id="47v-Wy-vaA"/>
|
||||
<constraint firstItem="a4X-9Q-mkr" firstAttribute="width" secondItem="S5g-F9-L3B" secondAttribute="width" id="REA-MB-gew"/>
|
||||
<constraint firstAttribute="bottom" secondItem="a4X-9Q-mkr" secondAttribute="bottom" id="Sqk-TW-ccx"/>
|
||||
<constraint firstAttribute="trailing" secondItem="a4X-9Q-mkr" secondAttribute="trailing" id="keL-QJ-bja"/>
|
||||
<constraint firstItem="a4X-9Q-mkr" firstAttribute="leading" secondItem="S5g-F9-L3B" secondAttribute="leading" id="maD-UF-Wim"/>
|
||||
</constraints>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="hUM-zt-PJj"/>
|
||||
<color key="backgroundColor" red="0.94509803920000002" green="0.96078431369999995" blue="0.97254901959999995" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="hUM-zt-PJj" firstAttribute="trailing" secondItem="S5g-F9-L3B" secondAttribute="trailing" id="EAb-7P-Zsd"/>
|
||||
<constraint firstAttribute="bottom" secondItem="S5g-F9-L3B" secondAttribute="bottom" id="Ham-fU-JWM"/>
|
||||
<constraint firstItem="hUM-zt-PJj" firstAttribute="top" secondItem="S5g-F9-L3B" secondAttribute="top" id="Zkl-TJ-HEv"/>
|
||||
<constraint firstItem="S5g-F9-L3B" firstAttribute="leading" secondItem="hUM-zt-PJj" secondAttribute="leading" id="sme-S5-pY5"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="doneButton" destination="QxC-gf-8VN" id="eOc-Ec-FgG"/>
|
||||
<outlet property="doneButtonBackgroundView" destination="7aK-CF-d5d" id="y7U-Ol-8Nk"/>
|
||||
<outlet property="informationLabel" destination="3eY-3I-XYH" id="ZT2-Lo-JlX"/>
|
||||
<outlet property="keyBackupLogoImageView" destination="epg-Qy-eoD" id="YOa-Pv-XrT"/>
|
||||
<outlet property="titleLabel" destination="X7g-Ha-15I" id="yMg-6G-6lF"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Yhm-Kv-QZF" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-3178" y="-675"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="key_backup_logo" width="48" height="46"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2021 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol KeyBackupSetupSuccessFromSecureBackupViewControllerDelegate: class {
|
||||
func keyBackupSetupSuccessFromSecureBackupViewControllerDidTapDoneAction(_ viewController: KeyBackupSetupSuccessFromSecureBackupViewController)
|
||||
}
|
||||
|
||||
final class KeyBackupSetupSuccessFromSecureBackupViewController: UIViewController {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var keyBackupLogoImageView: UIImageView!
|
||||
@IBOutlet private weak var titleLabel: UILabel!
|
||||
@IBOutlet private weak var informationLabel: UILabel!
|
||||
|
||||
@IBOutlet private weak var doneButtonBackgroundView: UIView!
|
||||
@IBOutlet private weak var doneButton: UIButton!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var theme: Theme!
|
||||
|
||||
// MARK: Public
|
||||
|
||||
weak var delegate: KeyBackupSetupSuccessFromSecureBackupViewControllerDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
class func instantiate() -> KeyBackupSetupSuccessFromSecureBackupViewController {
|
||||
let viewController = StoryboardScene.KeyBackupSetupSuccessFromSecureBackupViewController.initialScene.instantiate()
|
||||
viewController.theme = ThemeService.shared().theme
|
||||
return viewController
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
|
||||
self.title = VectorL10n.keyBackupSetupTitle
|
||||
|
||||
self.setupViews()
|
||||
self.registerThemeServiceDidChangeThemeNotification()
|
||||
self.update(theme: self.theme)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
// Hide back button
|
||||
self.navigationItem.setHidesBackButton(true, animated: animated)
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return self.theme.statusBarStyle
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupViews() {
|
||||
|
||||
let keybackupLogoImage = Asset.Images.keyBackupLogo.image.withRenderingMode(.alwaysTemplate)
|
||||
self.keyBackupLogoImageView.image = keybackupLogoImage
|
||||
|
||||
self.titleLabel.text = VectorL10n.keyBackupSetupSuccessTitle
|
||||
self.informationLabel.text = VectorL10n.keyBackupSetupSuccessFromSecureBackupInfo
|
||||
|
||||
self.doneButton.setTitle(VectorL10n.keyBackupSetupSuccessFromPassphraseDoneAction, for: .normal)
|
||||
}
|
||||
|
||||
private func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
self.view.backgroundColor = theme.headerBackgroundColor
|
||||
|
||||
if let navigationBar = self.navigationController?.navigationBar {
|
||||
theme.applyStyle(onNavigationBar: navigationBar)
|
||||
}
|
||||
|
||||
self.keyBackupLogoImageView.tintColor = theme.textPrimaryColor
|
||||
self.titleLabel.textColor = theme.textPrimaryColor
|
||||
self.informationLabel.textColor = theme.textPrimaryColor
|
||||
|
||||
self.doneButtonBackgroundView.backgroundColor = theme.backgroundColor
|
||||
theme.applyStyle(onButton: self.doneButton)
|
||||
}
|
||||
|
||||
private func registerThemeServiceDidChangeThemeNotification() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
|
||||
}
|
||||
|
||||
@objc private func themeDidChange() {
|
||||
self.update(theme: ThemeService.shared().theme)
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction private func doneButtonAction(_ sender: Any) {
|
||||
self.delegate?.keyBackupSetupSuccessFromSecureBackupViewControllerDidTapDoneAction(self)
|
||||
}
|
||||
}
|
||||
@@ -132,9 +132,11 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai
|
||||
self.registerKeyVerificationManagerNewRequestNotification(for: self.verificationManager)
|
||||
self.update(viewState: .loaded(viewData))
|
||||
self.registerTransactionDidStateChangeNotification()
|
||||
self.registerKeyVerificationRequestChangeNotification()
|
||||
}
|
||||
|
||||
private func cancel() {
|
||||
self.unregisterKeyVerificationRequestChangeNotification()
|
||||
self.unregisterKeyVerificationManagerNewRequestNotification()
|
||||
self.cancelKeyVerificationRequest()
|
||||
self.coordinatorDelegate?.keyVerificationSelfVerifyWaitViewModelDidCancel(self)
|
||||
@@ -193,6 +195,42 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai
|
||||
self.acceptKeyVerificationRequest(keyVerificationRequest)
|
||||
}
|
||||
|
||||
// MARK: MXKeyVerificationRequestDidChangeNotification
|
||||
|
||||
private func registerKeyVerificationRequestChangeNotification() {
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(keyVerificationRequestChangeNotification(notification:)),
|
||||
name: .MXKeyVerificationRequestDidChange,
|
||||
object: nil)
|
||||
}
|
||||
|
||||
private func unregisterKeyVerificationRequestChangeNotification() {
|
||||
NotificationCenter.default.removeObserver(self,
|
||||
name: .MXKeyVerificationRequestDidChange,
|
||||
object: nil)
|
||||
}
|
||||
|
||||
@objc private func keyVerificationRequestChangeNotification(notification: Notification) {
|
||||
guard let request = notification.object as? MXKeyVerificationRequest else {
|
||||
return
|
||||
}
|
||||
guard let keyVerificationRequest = keyVerificationRequest,
|
||||
keyVerificationRequest.requestId == request.requestId else {
|
||||
return
|
||||
}
|
||||
|
||||
guard keyVerificationRequest.isFromMyUser,
|
||||
keyVerificationRequest.isFromMyDevice else {
|
||||
return
|
||||
}
|
||||
|
||||
if keyVerificationRequest.state == MXKeyVerificationRequestStateReady {
|
||||
self.unregisterKeyVerificationRequestChangeNotification()
|
||||
self.coordinatorDelegate?.keyVerificationSelfVerifyWaitViewModel(self,
|
||||
didAcceptKeyVerificationRequest: keyVerificationRequest)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: MXKeyVerificationTransactionDidChange
|
||||
|
||||
private func registerTransactionDidStateChangeNotification() {
|
||||
|
||||
@@ -17,35 +17,17 @@
|
||||
import UIKit
|
||||
import Reusable
|
||||
|
||||
final class RoomAvatarView: UIView, NibOwnerLoadable, Themable {
|
||||
final class RoomAvatarView: AvatarView, NibOwnerLoadable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var avatarImageView: MXKImageView!
|
||||
@IBOutlet private weak var cameraBadgeContainerView: UIView!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var theme: Theme?
|
||||
|
||||
private var isHighlighted: Bool = false {
|
||||
didSet {
|
||||
self.updateView()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
|
||||
var action: (() -> Void)?
|
||||
|
||||
// MARK: Setup
|
||||
|
||||
private func commonInit() {
|
||||
self.setupAvatarImageView()
|
||||
self.setupGestureRecognizer()
|
||||
self.vc_setupAccessibilityTraitsButton(withTitle: VectorL10n.roomAvatarViewAccessibilityLabel, hint: VectorL10n.roomAvatarViewAccessibilityHint, isEnabled: true)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
@@ -70,7 +52,7 @@ final class RoomAvatarView: UIView, NibOwnerLoadable, Themable {
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func fill(with viewData: RoomAvatarViewData) {
|
||||
override func fill(with viewData: AvatarViewDataProtocol) {
|
||||
self.updateAvatarImageView(with: viewData)
|
||||
|
||||
// Fix layoutSubviews not triggered issue
|
||||
@@ -78,72 +60,20 @@ final class RoomAvatarView: UIView, NibOwnerLoadable, Themable {
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
// MARK: - Overrides
|
||||
|
||||
private func setupGestureRecognizer() {
|
||||
let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(buttonAction(_:)))
|
||||
gestureRecognizer.minimumPressDuration = 0
|
||||
self.addGestureRecognizer(gestureRecognizer)
|
||||
}
|
||||
|
||||
private func setupAvatarImageView() {
|
||||
self.avatarImageView.defaultBackgroundColor = UIColor.clear
|
||||
self.avatarImageView.enableInMemoryCache = true
|
||||
self.avatarImageView.layer.masksToBounds = true
|
||||
}
|
||||
|
||||
private func updateAvatarImageView(with viewData: RoomAvatarViewData) {
|
||||
guard let avatarImageView = self.avatarImageView else {
|
||||
return
|
||||
}
|
||||
|
||||
let defaultavatarImage = AvatarGenerator.generateAvatar(forMatrixItem: viewData.roomId, withDisplayName: viewData.roomDisplayName)
|
||||
|
||||
if let avatarUrl = viewData.avatarUrl {
|
||||
avatarImageView.setImageURI(avatarUrl,
|
||||
withType: nil,
|
||||
andImageOrientation: .up,
|
||||
toFitViewSize: avatarImageView.frame.size,
|
||||
with: MXThumbnailingMethodScale,
|
||||
previewImage: defaultavatarImage,
|
||||
mediaManager: viewData.mediaManager)
|
||||
override func updateAccessibilityTraits() {
|
||||
if self.isUserInteractionEnabled {
|
||||
self.vc_setupAccessibilityTraitsButton(withTitle: VectorL10n.roomAvatarViewAccessibilityLabel, hint: VectorL10n.roomAvatarViewAccessibilityHint, isEnabled: true)
|
||||
} else {
|
||||
avatarImageView.image = defaultavatarImage
|
||||
self.vc_setupAccessibilityTraitsImage(withTitle: VectorL10n.roomAvatarViewAccessibilityLabel)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateAvatarImageView(with viewData: AvatarViewDataProtocol) {
|
||||
super.updateAvatarImageView(with: viewData)
|
||||
|
||||
avatarImageView.contentMode = .scaleAspectFill
|
||||
|
||||
self.cameraBadgeContainerView.isHidden = viewData.avatarUrl != nil
|
||||
}
|
||||
|
||||
private func updateView() {
|
||||
// TODO: Handle highlighted state
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc private func buttonAction(_ sender: UILongPressGestureRecognizer) {
|
||||
|
||||
let isBackgroundViewTouched = sender.vc_isTouchingInside()
|
||||
|
||||
switch sender.state {
|
||||
case .began, .changed:
|
||||
self.isHighlighted = isBackgroundViewTouched
|
||||
case .ended:
|
||||
self.isHighlighted = false
|
||||
|
||||
if isBackgroundViewTouched {
|
||||
self.action?()
|
||||
}
|
||||
case .cancelled:
|
||||
self.isHighlighted = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,13 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct RoomAvatarViewData {
|
||||
struct RoomAvatarViewData: AvatarViewDataProtocol {
|
||||
let roomId: String
|
||||
let roomDisplayName: String?
|
||||
let displayName: String?
|
||||
let avatarUrl: String?
|
||||
let mediaManager: MXMediaManager
|
||||
|
||||
var matrixItemId: String {
|
||||
return roomId
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,6 +412,11 @@ class RoomDirectCallStatusBubbleCell: RoomBaseCallBubbleCell {
|
||||
return (NSTimeIntervalSince1970 - TimeInterval(startDate))/MSEC_PER_SEC
|
||||
}
|
||||
|
||||
guard startDate < endDate else {
|
||||
// started but hung up/rejected on other end around the same time
|
||||
return 0
|
||||
}
|
||||
|
||||
// ended, compute the diff between two dates
|
||||
return TimeInterval(endDate - startDate)/MSEC_PER_SEC
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ class RoomCreationIntroCell: MXKRoomBubbleTableViewCell {
|
||||
let displayName = roomSummary.displayname ?? ""
|
||||
|
||||
let roomAvatarViewData = RoomAvatarViewData(roomId: roomId,
|
||||
roomDisplayName: displayName,
|
||||
displayName: displayName,
|
||||
avatarUrl: room.summary.avatar, mediaManager: session.mediaManager)
|
||||
|
||||
return RoomCreationIntroViewData(dicussionType: discussionType, roomDisplayName: displayName, avatarViewData: roomAvatarViewData)
|
||||
|
||||
@@ -72,6 +72,7 @@ final class RoomsDirectoryCoordinator: RoomsDirectoryCoordinatorType {
|
||||
|
||||
// MARK: - ShowDirectoryCoordinatorDelegate
|
||||
extension RoomsDirectoryCoordinator: ShowDirectoryCoordinatorDelegate {
|
||||
|
||||
func showDirectoryCoordinator(_ coordinator: ShowDirectoryCoordinatorType, didSelectRoom room: MXPublicRoom) {
|
||||
self.delegate?.roomsDirectoryCoordinator(self, didSelectRoom: room)
|
||||
}
|
||||
@@ -87,4 +88,8 @@ extension RoomsDirectoryCoordinator: ShowDirectoryCoordinatorDelegate {
|
||||
func showDirectoryCoordinatorWantsToShow(_ coordinator: ShowDirectoryCoordinatorType, viewController: UIViewController) {
|
||||
toPresentable().present(RiotNavigationController(rootViewController: viewController), animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func showDirectoryCoordinator(_ coordinator: ShowDirectoryCoordinatorType, didSelectRoomWithIdOrAlias roomIdOrAlias: String) {
|
||||
self.delegate?.roomsDirectoryCoordinator(self, didSelectRoomWithIdOrAlias: roomIdOrAlias)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import Foundation
|
||||
func roomsDirectoryCoordinatorBridgePresenterDelegateDidComplete(_ coordinatorBridgePresenter: RoomsDirectoryCoordinatorBridgePresenter)
|
||||
func roomsDirectoryCoordinatorBridgePresenterDelegate(_ coordinatorBridgePresenter: RoomsDirectoryCoordinatorBridgePresenter, didSelectRoom room: MXPublicRoom)
|
||||
func roomsDirectoryCoordinatorBridgePresenterDelegateDidTapCreateNewRoom(_ coordinatorBridgePresenter: RoomsDirectoryCoordinatorBridgePresenter)
|
||||
func roomsDirectoryCoordinatorBridgePresenterDelegate(_ coordinatorBridgePresenter: RoomsDirectoryCoordinatorBridgePresenter, didSelectRoomWithIdOrAlias roomIdOrAlias: String)
|
||||
}
|
||||
|
||||
/// RoomsDirectoryCoordinatorBridgePresenter enables to start RoomsDirectoryCoordinator from a view controller.
|
||||
@@ -96,6 +97,9 @@ extension RoomsDirectoryCoordinatorBridgePresenter: RoomsDirectoryCoordinatorDel
|
||||
self.delegate?.roomsDirectoryCoordinatorBridgePresenterDelegateDidComplete(self)
|
||||
}
|
||||
|
||||
func roomsDirectoryCoordinator(_ coordinator: RoomsDirectoryCoordinatorType, didSelectRoomWithIdOrAlias roomIdOrAlias: String) {
|
||||
self.delegate?.roomsDirectoryCoordinatorBridgePresenterDelegate(self, didSelectRoomWithIdOrAlias: roomIdOrAlias)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIAdaptivePresentationControllerDelegate
|
||||
|
||||
@@ -22,6 +22,7 @@ protocol RoomsDirectoryCoordinatorDelegate: class {
|
||||
func roomsDirectoryCoordinator(_ coordinator: RoomsDirectoryCoordinatorType, didSelectRoom room: MXPublicRoom)
|
||||
func roomsDirectoryCoordinatorDidTapCreateNewRoom(_ coordinator: RoomsDirectoryCoordinatorType)
|
||||
func roomsDirectoryCoordinatorDidComplete(_ coordinator: RoomsDirectoryCoordinatorType)
|
||||
func roomsDirectoryCoordinator(_ coordinator: RoomsDirectoryCoordinatorType, didSelectRoomWithIdOrAlias roomIdOrAlias: String)
|
||||
}
|
||||
|
||||
/// `RoomsDirectoryCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow.
|
||||
|
||||