diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c2277f70..3e9e33f5c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/.gitignore b/.gitignore index 20db4d165..05465bd32 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ DerivedData *.xcuserstate out/ .vscode/ +vendor/ # CocoaPods # diff --git a/CHANGES.rst b/CHANGES.rst index dc0a734c5..72f23a86d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -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) ================================================= diff --git a/Config/AppIdentifiers.xcconfig b/Config/AppIdentifiers.xcconfig index d1aba3d1c..cd0fd28f8 100644 --- a/Config/AppIdentifiers.xcconfig +++ b/Config/AppIdentifiers.xcconfig @@ -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 diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index e7d771d1f..3cfcf65dc 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -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. diff --git a/INSTALL.md b/INSTALL.md index 5800848d0..ca983508a 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -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). diff --git a/Podfile b/Podfile index 6b7502835..6746493b4 100644 --- a/Podfile +++ b/Podfile @@ -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 diff --git a/Riot/Assets/Base.lproj/Main.storyboard b/Riot/Assets/Base.lproj/Main.storyboard index fde16d1ad..aec7a4605 100644 --- a/Riot/Assets/Base.lproj/Main.storyboard +++ b/Riot/Assets/Base.lproj/Main.storyboard @@ -221,7 +221,7 @@ - + @@ -581,7 +581,7 @@ - + diff --git a/Riot/Assets/Images.xcassets/SideMenu/Contents.json b/Riot/Assets/Images.xcassets/SideMenu/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Riot/Assets/Images.xcassets/SideMenu/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/Contents.json b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/Contents.json new file mode 100644 index 000000000..17b471849 --- /dev/null +++ b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/Contents.json @@ -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" + } +} diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback.png new file mode 100644 index 000000000..4ff91ac99 Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback@2x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback@2x.png new file mode 100644 index 000000000..19622d587 Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback@2x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback@3x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback@3x.png new file mode 100644 index 000000000..c6db9f426 Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_feedback.imageset/side_menu_action_icon_feedback@3x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/Contents.json b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/Contents.json new file mode 100644 index 000000000..429cca21d --- /dev/null +++ b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/Contents.json @@ -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" + } +} diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help.png new file mode 100644 index 000000000..002952075 Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help@2x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help@2x.png new file mode 100644 index 000000000..8ae150437 Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help@2x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help@3x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help@3x.png new file mode 100644 index 000000000..34e86003a Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_help.imageset/side_menu_action_icon_help@3x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/Contents.json b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/Contents.json new file mode 100644 index 000000000..6959991ce --- /dev/null +++ b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/Contents.json @@ -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" + } +} diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings.png new file mode 100644 index 000000000..45fab88ce Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings@2x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings@2x.png new file mode 100644 index 000000000..49f384e3b Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings@2x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings@3x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings@3x.png new file mode 100644 index 000000000..8c8ba6a5f Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_settings.imageset/side_menu_action_icon_settings@3x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/Contents.json b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/Contents.json new file mode 100644 index 000000000..1cdd44ef6 --- /dev/null +++ b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/Contents.json @@ -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" + } +} diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share.png new file mode 100644 index 000000000..30ede3f1b Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share@2x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share@2x.png new file mode 100644 index 000000000..baf0ca170 Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share@2x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share@3x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share@3x.png new file mode 100644 index 000000000..7f5803071 Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_action_icon_share.imageset/side_menu_action_icon_share@3x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/Contents.json new file mode 100644 index 000000000..b4ad14b40 --- /dev/null +++ b/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/Contents.json @@ -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" + } +} diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon.png new file mode 100644 index 000000000..5c8d43350 Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon@2x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon@2x.png new file mode 100644 index 000000000..26726446b Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon@2x.png differ diff --git a/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon@3x.png b/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon@3x.png new file mode 100644 index 000000000..eac1d252d Binary files /dev/null and b/Riot/Assets/Images.xcassets/SideMenu/side_menu_icon.imageset/side_menu_icon@3x.png differ diff --git a/Riot/Assets/ar.lproj/Vector.strings b/Riot/Assets/ar.lproj/Vector.strings index 96290d0cb..8687e7f26 100644 --- a/Riot/Assets/ar.lproj/Vector.strings +++ b/Riot/Assets/ar.lproj/Vector.strings @@ -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" = "هَل أنتَ مُتَأكِّدٌ أنَّكَ تٌريدُ دَعوةَ %@ إلَى هَذِهِ المُحادَثَة؟"; diff --git a/Riot/Assets/bg.lproj/Localizable.strings b/Riot/Assets/bg.lproj/Localizable.strings index ec79b41a4..0b966c728 100644 --- a/Riot/Assets/bg.lproj/Localizable.strings +++ b/Riot/Assets/bg.lproj/Localizable.strings @@ -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" = "Беше стартиран групов разговор"; diff --git a/Riot/Assets/bg.lproj/Vector.strings b/Riot/Assets/bg.lproj/Vector.strings index 186c3ef67..d9fa91f5a 100644 --- a/Riot/Assets/bg.lproj/Vector.strings +++ b/Riot/Assets/bg.lproj/Vector.strings @@ -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" = "Докоснете за връщане в разговора (%@)"; diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index 0f2f241ca..0b5359262 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -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."; diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index dc0cbc884..234022cf2 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -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 %@"; diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index 3d884c119..32ede1f7f 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -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."; diff --git a/Riot/Assets/fa.lproj/Vector.strings b/Riot/Assets/fa.lproj/Vector.strings index e0420eb2b..142818c4c 100644 --- a/Riot/Assets/fa.lproj/Vector.strings +++ b/Riot/Assets/fa.lproj/Vector.strings @@ -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" = "ارتباط امن غیرمتمرکز"; diff --git a/Riot/Assets/fr.lproj/Vector.strings b/Riot/Assets/fr.lproj/Vector.strings index fcc72186c..f78010dfe 100644 --- a/Riot/Assets/fr.lproj/Vector.strings +++ b/Riot/Assets/fr.lproj/Vector.strings @@ -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."; diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index efd08c573..718f7de9b 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -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."; diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings new file mode 100644 index 000000000..fe5f556f7 --- /dev/null +++ b/Riot/Assets/id.lproj/Vector.strings @@ -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"; diff --git a/Riot/Assets/nl.lproj/Vector.strings b/Riot/Assets/nl.lproj/Vector.strings index 9efb88de9..bfa85bc1b 100644 --- a/Riot/Assets/nl.lproj/Vector.strings +++ b/Riot/Assets/nl.lproj/Vector.strings @@ -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."; diff --git a/Riot/Assets/pt_BR.lproj/InfoPlist.strings b/Riot/Assets/pt_BR.lproj/InfoPlist.strings index be958c502..035cfaba2 100644 --- a/Riot/Assets/pt_BR.lproj/InfoPlist.strings +++ b/Riot/Assets/pt_BR.lproj/InfoPlist.strings @@ -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."; diff --git a/Riot/Assets/pt_BR.lproj/Localizable.strings b/Riot/Assets/pt_BR.lproj/Localizable.strings index 6b95f38ba..7109ba71e 100644 --- a/Riot/Assets/pt_BR.lproj/Localizable.strings +++ b/Riot/Assets/pt_BR.lproj/Localizable.strings @@ -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"; diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings index b94a62387..2749e389a 100644 --- a/Riot/Assets/pt_BR.lproj/Vector.strings +++ b/Riot/Assets/pt_BR.lproj/Vector.strings @@ -1,106 +1,106 @@ // Titles -"title_home" = "Início"; +"title_home" = "Home"; "title_favourites" = "Favoritos"; "title_people" = "Pessoas"; "title_rooms" = "Salas"; "title_groups" = "Comunidades"; -"warning" = "Atenção"; +"warning" = "Aviso"; // Actions -"view" = "Ver"; +"view" = "Visualizar"; "next" = "Próximo"; "back" = "Voltar"; "continue" = "Continuar"; "create" = "Criar"; -"start" = "Iniciar"; +"start" = "Começar"; "leave" = "Sair"; "remove" = "Remover"; "invite" = "Convidar"; -"retry" = "Tentar novamente"; +"retry" = "Retentar"; "on" = "Ativado"; "off" = "Desativado"; "cancel" = "Cancelar"; "save" = "Salvar"; -"join" = "Entrar"; -"decline" = "Recusar"; +"join" = "Juntar-Se"; +"decline" = "Declinar"; "accept" = "Aceitar"; -"preview" = "Pré-visualização"; +"preview" = "Previsualizar"; "camera" = "Câmera"; "voice" = "Voz"; "video" = "Vídeo"; -"active_call" = "Chamada em andamento"; -"active_call_details" = "Chamada em andamento (%@)"; -"later" = "Mais tarde"; +"active_call" = "Chamada Ativa"; +"active_call_details" = "Chamada Ativa (%@)"; +"later" = "Mais Tarde"; "rename" = "Renomear"; -"collapse" = "reduzir"; +"collapse" = "colapsar"; "send_to" = "Enviar para %@"; "sending" = "Enviando"; // Authentication "auth_login" = "Fazer login"; -"auth_register" = "Criar nova conta"; -"auth_submit" = "Enviar"; -"auth_skip" = "Ignorar"; -"auth_send_reset_email" = "Enviar e-mail de redefinição de senha"; -"auth_return_to_login" = "Voltar à tela de login"; -"auth_user_id_placeholder" = "E-mail ou nome de usuário"; +"auth_register" = "Registrar-se"; +"auth_submit" = "Submeter"; +"auth_skip" = "Pular"; +"auth_send_reset_email" = "Enviar Email de Reset"; +"auth_return_to_login" = "Retornar a tela de login"; +"auth_user_id_placeholder" = "Email ou nome de usuária(o)"; "auth_password_placeholder" = "Senha"; "auth_new_password_placeholder" = "Nova senha"; -"auth_user_name_placeholder" = "Nome de usuário"; -"auth_optional_email_placeholder" = "Endereço de e-mail (opcional)"; -"auth_email_placeholder" = "Endereço de e-mail"; +"auth_user_name_placeholder" = "Nome de usuária(o)"; +"auth_optional_email_placeholder" = "Endereço de email (opcional)"; +"auth_email_placeholder" = "Endereço de email"; "auth_optional_phone_placeholder" = "Número de telefone (opcional)"; "auth_phone_placeholder" = "Número de telefone"; -"auth_repeat_password_placeholder" = "Repita a senha"; -"auth_repeat_new_password_placeholder" = "Confirme sua nova senha"; -"auth_home_server_placeholder" = "Endereço (por exemplo: https://matrix.org)"; -"auth_identity_server_placeholder" = "Endereço (por exemplo: https://vector.im)"; -"auth_invalid_login_param" = "Nome de usuário e/ou senha incorretos"; -"auth_invalid_user_name" = "Nomes de usuários podem conter apenas letras, números, pontos, hifens e sublinhados"; -"auth_invalid_password" = "Senha muito curta (mín. 6 letras)"; -"auth_invalid_email" = "Este não parece ser um endereço de e-mail válido"; -"auth_invalid_phone" = "Este não parece ser um número de telefone válido"; -"auth_missing_password" = "Falta a senha"; +"auth_repeat_password_placeholder" = "Repetir senha"; +"auth_repeat_new_password_placeholder" = "Confirmar sua nova senha"; +"auth_home_server_placeholder" = "URL (e.g. https://matrix.org)"; +"auth_identity_server_placeholder" = "URL (e.g. https://vector.im)"; +"auth_invalid_login_param" = "Nome de usuária(o) e/ou senha incorretos"; +"auth_invalid_user_name" = "Nomes de usuária(o) podem somente conter letras, números, pontos, hifens e underscores"; +"auth_invalid_password" = "Senha curta demais (mín 6)"; +"auth_invalid_email" = "Isto não parece com um endereço de email válido"; +"auth_invalid_phone" = "Isto não parece com um número de telefone válido"; +"auth_missing_password" = "Senha faltando"; "auth_add_email_message" = "Adicione um endereço de e-mail para a sua conta para permitir que outras pessoas possam te achar, e também para que você possa redefinir sua senha."; "auth_add_phone_message" = "Adicione um número de telefone à sua conta para permitir que outras pessoas te encontrem."; "auth_add_email_phone_message" = "Adicione um endereço de e-mail e/ou um telefone à sua conta para permitir que outras pessoas encontrem você. O endereço de e-mail também permite que você redefina a sua senha."; "auth_add_email_and_phone_message" = "Adicione um endereço de e-mail e um telefone à sua conta para permitir que outras pessoas encontrem você. O endereço de e-mail também permite que você redefina a sua senha."; -"auth_missing_email" = "Falta o endereço de e-mail"; -"auth_missing_phone" = "Falta o número de telefone"; -"auth_missing_email_or_phone" = "Falta o endereço de e-mail ou o número de telefone"; -"auth_email_in_use" = "Este endereço de e-mail já está sendo usado por outra pessoa"; +"auth_missing_email" = "Endereço de email faltando"; +"auth_missing_phone" = "Número de telefone faltando"; +"auth_missing_email_or_phone" = "Endereço de email ou número de telefone faltando"; +"auth_email_in_use" = "Este endereço de email já está em uso"; "auth_phone_in_use" = "Este número de telefone já está em uso"; -"auth_untrusted_id_server" = "Este servidor de identidades não é confiável"; -"auth_password_dont_match" = "As senhas não correspondem"; -"auth_username_in_use" = "Nome de usuário indisponível"; -"auth_forgot_password" = "Esqueceu sua senha?"; -"auth_email_not_found" = "Não foi possível enviar um e-mail: este endereço de e-mail não foi encontrado"; -"auth_use_server_options" = "Use opções para servidor personalizado (avançado)"; -"auth_email_validation_message" = "Por favor, verifique o seu e-mail para continuar a inscrição"; -"auth_msisdn_validation_title" = "Faltando confirmação"; -"auth_msisdn_validation_message" = "Nós enviamos um SMS com um código de ativação. Por favor, coloque abaixo este código."; -"auth_msisdn_validation_error" = "Não foi possível confirmar o número de telefone."; -"auth_recaptcha_message" = "Este servidor local quer se certificar de que você não é um robô"; -"auth_reset_password_message" = "Para redefinir sua senha, digite o endereço de e-mail vinculado à sua conta:"; -"auth_reset_password_missing_email" = "O e-mail vinculado à sua conta precisa ser informado."; -"auth_reset_password_missing_password" = "Uma nova senha precisa ser inserida."; -"auth_reset_password_email_validation_message" = "Um e-mail foi enviado para %@. Após clicar no link contido no e-mail, clique abaixo."; -"auth_reset_password_next_step_button" = "Eu confirmei o meu endereço de e-mail"; -"auth_reset_password_error_unauthorized" = "Falha ao confirmar o endereço de e-mail: certifique-se de clicar no link do e-mail"; -"auth_reset_password_error_not_found" = "O seu endereço de e-mail não parece estar associado a um ID Matrix neste servidor local."; -"auth_reset_password_success_message" = "Sua senha foi alterada.↵\n↵\nVocê foi desconectado de todas as sessões e não receberá mais notificações. Para reativar as notificações, faça login novamente em cada aparelho."; -"auth_add_email_and_phone_warning" = "Atualmente, registrar-se com e-mail e número de telefone ao mesmo tempo não é possível. Apenas o número de telefone será levado em consideração. No entanto, você pode adicionar o endereço de e-mail ao seu perfil nas configurações."; +"auth_untrusted_id_server" = "O servidor de identidade não é confiado"; +"auth_password_dont_match" = "Senhas não correspondem"; +"auth_username_in_use" = "Nome de usuária(o) em uso"; +"auth_forgot_password" = "Esqueceu senha?"; +"auth_email_not_found" = "Falha para enviar email: Este endereço de email não foi encontrado"; +"auth_use_server_options" = "Usar opções de servidor personalizadas (avançado)"; +"auth_email_validation_message" = "Por favor cheque seu email para continuar registro"; +"auth_msisdn_validation_title" = "Verificação Pendendo"; +"auth_msisdn_validation_message" = "Nós temos enviado um SMS com um código de ativação. Por favor entre este código abaixo."; +"auth_msisdn_validation_error" = "Incapaz de verificar número de telefone."; +"auth_recaptcha_message" = "Este servidorcasa gostaria de assegurar que você não é um robô"; +"auth_reset_password_message" = "Para resettar sua senha, entre o endereço de email linkado a sua conta:"; +"auth_reset_password_missing_email" = "O email linkado à sua conta deve ser entrado."; +"auth_reset_password_missing_password" = "Uma nova senha deve ser entrada."; +"auth_reset_password_email_validation_message" = "Um email tem sido enviado para %@. Uma vez que você tenha seguido o link que ele contém, clique abaixo."; +"auth_reset_password_next_step_button" = "Eu tenho verificado meu endereço de email"; +"auth_reset_password_error_unauthorized" = "Falha para verificar endereço de email: assegure que você clicou no link no email"; +"auth_reset_password_error_not_found" = "Seu endereço de email não parece estar associado a uma ID Matrix neste servidorcasa."; +"auth_reset_password_success_message" = "Sua senha tem sido resettada.\n\nVocê tem sido feito logout de todas as sessões e não vai mais receber notificações push. Para re-ativar as notificações, refaça login em cada dispositivo."; +"auth_add_email_and_phone_warning" = "Registro com email e número de telefone ao mesmo tempo não é suportado ainda até que a api exista. Somente o número de telefone vai ser levado em conta. Você pode adicionar seu email a seu perfil em configurações."; "room_creation_appearance" = "Aparência"; "room_creation_appearance_name" = "Nome"; -"room_creation_appearance_picture" = "Imagem da Sala (opcional)"; +"room_creation_appearance_picture" = "Imagem de Chat (opcional)"; "room_creation_privacy" = "Privacidade"; -"room_creation_private_room" = "Esta conversa é privada"; -"room_creation_public_room" = "Esta conversa é pública"; -"room_creation_make_public" = "Tornar público"; -"room_creation_make_public_prompt_title" = "Tornar esta conversa pública?"; -"room_creation_make_public_prompt_msg" = "Você tem certeza que deseja tornar esta conversa pública? Qualquer um poderá ler suas mensagens e entrar na conversa."; -"room_creation_keep_private" = "Manter privada"; -"room_creation_make_private" = "Manter privada"; -"room_creation_wait_for_creation" = "A sala já está sendo criada. Por favor, aguarde."; -"room_creation_invite_another_user" = "Buscar / convidar por ID de usuário, nome e sobrenome ou e-mail"; +"room_creation_private_room" = "Este chat é privado"; +"room_creation_public_room" = "Este chat é público"; +"room_creation_make_public" = "Fazer público"; +"room_creation_make_public_prompt_title" = "Fazer este chat público?"; +"room_creation_make_public_prompt_msg" = "Tem certeza que você quer fazer este chat público? Qualquer pessoa pode ler suas mensagens e juntar-se ao chat."; +"room_creation_keep_private" = "Manter privado"; +"room_creation_make_private" = "Fazer privado"; +"room_creation_wait_for_creation" = "Uma sala já está sendo criada. Por favor espere."; +"room_creation_invite_another_user" = "Buscar / convidar por ID de usuária(o), Nome ou email"; "room_recents_directory_section_network" = "Rede"; "room_recents_favourites_section" = "FAVORITOS"; "room_recents_people_section" = "PESSOAS"; @@ -108,11 +108,11 @@ "room_recents_no_conversation" = "Nenhuma sala"; "room_recents_low_priority_section" = "BAIXA PRIORIDADE"; "room_recents_invites_section" = "CONVITES"; -"room_recents_start_chat_with" = "Iniciar conversa"; +"room_recents_start_chat_with" = "Começar chat"; "room_recents_create_empty_room" = "Criar sala"; -"room_recents_join_room" = "Entrar na sala"; -"room_recents_join_room_title" = "Entrar na sala"; -"room_recents_join_room_prompt" = "Digite o ID da sala ou o nome da sala"; +"room_recents_join_room" = "Juntar-se a sala"; +"room_recents_join_room_title" = "Juntar-se a uma sala"; +"room_recents_join_room_prompt" = "Digite um ID de sala ou um alias de sala"; // People tab "people_invites_section" = "CONVITES"; "people_conversation_section" = "CONVERSAS"; @@ -121,878 +121,878 @@ "room_directory_no_public_room" = "Nenhuma sala pública disponível"; // Groups tab "group_invite_section" = "CONVITES"; -"group_section" = "Comunidades"; +"group_section" = "COMUNIDADES"; // Search "search_rooms" = "Salas"; "search_messages" = "Mensagens"; "search_people" = "Pessoas"; "search_files" = "Arquivos"; -"search_default_placeholder" = "Procurar"; -"search_people_placeholder" = "Procurar por ID de usuário, nome e sobrenome ou e-mail"; +"search_default_placeholder" = "Pesquisar"; +"search_people_placeholder" = "Pesquisar por ID de usuária(o), Nome ou email"; "search_no_result" = "Nenhum resultado"; -"search_in_progress" = "Procurando…"; +"search_in_progress" = "Pesquisando…"; // Directory -"directory_cell_title" = "Procurar na lista"; +"directory_cell_title" = "Navegar diretório"; "directory_cell_description" = "%tu salas"; "directory_search_results" = "%tu resultados encontrados para %@"; "directory_search_results_more_than" = ">%tu resultados encontrados para %@"; -"directory_searching_title" = "Procurando na lista…"; +"directory_searching_title" = "Pesquisando diretório…"; // Contacts "contacts_address_book_section" = "CONTATOS LOCAIS"; -"contacts_address_book_matrix_users_toggle" = "Apenas usuários na Matrix"; +"contacts_address_book_matrix_users_toggle" = "Usuários Matrix somente"; "contacts_address_book_no_contact" = "Nenhum contato local"; -"contacts_address_book_permission_required" = "Permissão necessária para acessar contatos locais"; -"contacts_address_book_permission_denied" = "Você não permitiu que o Element acesse seus contatos locais"; -"contacts_user_directory_section" = "LISTA DE CONTATOS"; -"contacts_user_directory_offline_section" = "LISTA DE CONTATOS (offline)"; +"contacts_address_book_permission_required" = "Permissão requerida para acessar contatos locais"; +"contacts_address_book_permission_denied" = "Você não permitiu Element acessar seus contatos locais"; +"contacts_user_directory_section" = "DIRETÓRIO DE USUÁRIAS(OS)"; +"contacts_user_directory_offline_section" = "DIRETÓRIO DE USUÁRIAS(OS) (offline)"; // Chat participants "room_participants_title" = "Participantes"; -"room_participants_add_participant" = "Adicionar participantes"; +"room_participants_add_participant" = "Adicionar participante"; "room_participants_one_participant" = "1 participante"; "room_participants_multi_participants" = "%d participantes"; -"room_participants_leave_prompt_title" = "Sair da sala"; -"room_participants_leave_prompt_msg" = "Tem certeza de que deseja sair da sala?"; +"room_participants_leave_prompt_title" = "Sair de sala"; +"room_participants_leave_prompt_msg" = "Tem certeza que você quer sair da sala?"; "room_participants_remove_prompt_title" = "Confirmação"; -"room_participants_remove_prompt_msg" = "Você tem certeza que deseja remover %@ desta conversa?"; +"room_participants_remove_prompt_msg" = "Tem certeza que você quer remover %@ deste chat?"; // Chat creation -"room_creation_title" = "Nova Sala"; +"room_creation_title" = "Novo Chat"; "room_creation_account" = "Conta"; // Room recents -"room_recents_directory_section" = "LISTA DE SALAS"; -"directory_search_results_title" = "Procurar nos resultados da lista"; -"directory_search_fail" = "Falha ao buscar dados"; -"auth_accept_policies" = "Por favor, revise e aceite as políticas deste servidor local:"; +"room_recents_directory_section" = "DIRETÓRIO DE SALAS"; +"directory_search_results_title" = "Navegar resultados de diretório"; +"directory_search_fail" = "Falha para buscar dados"; +"auth_accept_policies" = "Por favor revise e aceite as políticas deste servidorcasa:"; "room_recents_server_notice_section" = "ALERTAS DO SISTEMA"; "room_participants_remove_third_party_invite_msg" = "Remover convite de terceiros ainda não é suportado até que a API exista"; "room_participants_invite_prompt_title" = "Confirmação"; -"room_participants_invite_prompt_msg" = "Tem certeza de que deseja convidar %@ para este chat?"; -"room_participants_filter_room_members" = "Pesquisar participantes da sala"; -"room_participants_invite_another_user" = "Pesquisar / convidar por ID de usuário, nome e sobrenome ou e-mail"; -"room_participants_invite_malformed_id_title" = "Erro no Convite"; -"room_participants_invited_section" = "CONVIDADO"; +"room_participants_invite_prompt_msg" = "Tem certeza que você quer convidar %@ para este chat?"; +"room_participants_filter_room_members" = "Filtrar membros de sala"; +"room_participants_invite_another_user" = "Pesquisar / convidar por ID de Usuária(o), Nome ou email"; +"room_participants_invite_malformed_id_title" = "Erro de Convidar"; +"room_participants_invited_section" = "CONVIDADAS(OS)"; "room_participants_online" = "Online"; "room_participants_offline" = "Offline"; "room_participants_unknown" = "Desconhecido"; -"room_participants_idle" = "Ocioso"; +"room_participants_idle" = "Ociosa(o)"; "room_participants_now" = "agora"; "room_participants_ago" = "atrás"; -"room_participants_action_section_admin_tools" = "Ferramentas Administrativas"; -"room_participants_action_section_direct_chats" = "bate-papos diretos"; +"room_participants_action_section_admin_tools" = "Ferramentas de admin"; +"room_participants_action_section_direct_chats" = "Chats diretos"; "room_participants_action_section_devices" = "Sessões"; "room_participants_action_section_other" = "Opções"; "room_participants_action_invite" = "Convidar"; "room_participants_action_leave" = "Sair desta sala"; "room_participants_action_remove" = "Remover desta sala"; -"room_participants_action_ban" = "Banir da sala"; -"room_participants_action_unban" = "Remover banimento"; -"room_participants_action_ignore" = "Esconder todas as mensagens deste usuário"; -"room_participants_action_unignore" = "Mostrar todas as mensagens deste usuário"; -"room_participants_invite_malformed_id" = "ID mal formatado. Precisa ser um endereço de e-mail ou um ID Matrix, como '@participantelocal:dominio'"; -"room_participants_action_set_default_power_level" = "Redefinir para usuário normal"; -"room_participants_action_set_moderator" = "Faça moderador"; -"room_participants_action_set_admin" = "Faça administrador"; -"room_participants_action_start_new_chat" = "Iniciar nova conversa"; -"room_participants_action_start_voice_call" = "Iniciar chamada de voz"; -"room_participants_action_start_video_call" = "Iniciar chamada de vídeo"; +"room_participants_action_ban" = "Banir desta sala"; +"room_participants_action_unban" = "Desbanir"; +"room_participants_action_ignore" = "Esconder todas as mensagens desta(e) usuária(o)"; +"room_participants_action_unignore" = "Mostrar todas as mensagens desta(e) usuária(o)"; +"room_participants_invite_malformed_id" = "ID malformado. Deveria ser um endereço de email ou uma ID Matrix como '@partlocal:dominio'"; +"room_participants_action_set_default_power_level" = "Resettar para usuária(o) normal"; +"room_participants_action_set_moderator" = "Fazer moderador(a)"; +"room_participants_action_set_admin" = "Fazer admin"; +"room_participants_action_start_new_chat" = "Começar novo chat"; +"room_participants_action_start_voice_call" = "Começar chamada de voz"; +"room_participants_action_start_video_call" = "Começar chamada de vídeo"; "room_participants_action_mention" = "Mencionar"; // Chat -"room_jump_to_first_unread" = "Ir para a primeira mensagem não lida"; +"room_jump_to_first_unread" = "Pular para não-lida"; "room_new_message_notification" = "%d nova mensagem"; "room_new_messages_notification" = "%d novas mensagens"; "room_one_user_is_typing" = "%@ está digitando…"; "room_two_users_are_typing" = "%@ & %@ estão digitando…"; -"room_many_users_are_typing" = "%@, %@ e outros estão digitando…"; -"room_message_placeholder" = "Digite uma mensagem (não criptografada)…"; -"room_message_reply_to_placeholder" = "Digite sua resposta (não criptografada)…"; -"room_do_not_have_permission_to_post" = "Você não tem permissão para digitar nesta sala"; -"encrypted_room_message_placeholder" = "Digite uma mensagem criptografada…"; -"encrypted_room_message_reply_to_placeholder" = "Digite sua resposta criptografada…"; -"room_message_short_placeholder" = "Digite uma mensagem…"; -"room_message_reply_to_short_placeholder" = "Digite sua resposta…"; -"room_offline_notification" = "A conectividade com o servidor foi perdida."; -"room_unsent_messages_notification" = "Falha ao enviar mensagens."; -"room_unsent_messages_unknown_devices_notification" = "Mensagem não enviada devido à presença de sessões desconhecidas."; -"room_ongoing_conference_call" = "Chamada em grupo em andamento. Junte-se como %@ ou %@."; -"room_ongoing_conference_call_with_close" = "Chamada em grupo em andamento. Junte-se como %@ ou %@. %@ isto."; +"room_many_users_are_typing" = "%@, %@ & outras(os) estão digitando…"; +"room_message_placeholder" = "Enviar uma mensagem (não-encriptada)…"; +"room_message_reply_to_placeholder" = "Enviar uma resposta (não-encriptada)…"; +"room_do_not_have_permission_to_post" = "Você não tem permissão para postar a esta sala"; +"encrypted_room_message_placeholder" = "Enviar uma mensagem encriptada…"; +"encrypted_room_message_reply_to_placeholder" = "Enviar uma resposta encriptada…"; +"room_message_short_placeholder" = "Enviar uma mensagem…"; +"room_message_reply_to_short_placeholder" = "Enviar uma resposta…"; +"room_offline_notification" = "Conectividade ao servidor tem sido perdida."; +"room_unsent_messages_notification" = "Mensagens falharam para enviar."; +"room_unsent_messages_unknown_devices_notification" = "Mensagem falhou para enviar devido a sessões desconhecidas estando presentes."; +"room_ongoing_conference_call" = "Chamada de conferência acontecendo. Juntar-se como %@ ou %@."; +"room_ongoing_conference_call_with_close" = "Chamada de conferência acontecendo. Juntar-se como %@ ou %@. %@ isto."; "room_ongoing_conference_call_close" = "Fechar"; -"room_conference_call_no_power" = "Você precisa de permissão para gerenciar a chamada em grupo nesta sala"; -"room_prompt_resend" = "Reenviar tudo"; -"room_prompt_cancel" = "Cancelar todas"; -"room_resend_unsent_messages" = "Reenviar mensagens não enviadas"; -"room_delete_unsent_messages" = "Excluir mensagens não enviadas"; +"room_conference_call_no_power" = "Você precisa de permissão para gerenciar a chamada de conferência nesta sala"; +"room_prompt_resend" = "Reenviar todas"; +"room_prompt_cancel" = "cancelar todas"; +"room_resend_unsent_messages" = "Reenviar mensagens não-enviadas"; +"room_delete_unsent_messages" = "Deletar mensagens não-enviadas"; "room_event_action_copy" = "Copiar"; "room_event_action_quote" = "Citar"; -"room_event_action_redact" = "Redigir"; +"room_event_action_redact" = "Remover"; "room_event_action_more" = "Mais"; "room_event_action_share" = "Compartilhar"; -"room_event_action_permalink" = "Link"; -"room_event_action_view_source" = "Ver código-fonte"; -"room_event_action_view_decrypted_source" = "Ver código-fonte descriptografado"; -"room_event_action_report" = "Denunciar conteúdo"; -"room_event_action_report_prompt_reason" = "Razão para denunciar este conteúdo"; -"room_event_action_kick_prompt_reason" = "Motivo para remover este usuário"; -"room_event_action_ban_prompt_reason" = "Motivo para banir este usuário"; -"room_event_action_report_prompt_ignore_user" = "Você quer esconder todas as mensagens deste usuário?"; +"room_event_action_permalink" = "Permalink"; +"room_event_action_view_source" = "Visualizar Fonte"; +"room_event_action_view_decrypted_source" = "Visualizar Fonte Decriptada"; +"room_event_action_report" = "Reportar conteúdo"; +"room_event_action_report_prompt_reason" = "Razão para reportar este conteúdo"; +"room_event_action_kick_prompt_reason" = "Razão para expulsar esta(e) usuária(o)"; +"room_event_action_ban_prompt_reason" = "Razão para banir esta(e) usuária(o)"; +"room_event_action_report_prompt_ignore_user" = "Você quer esconder todas as mensagens desta(e) usuária(o)?"; "room_event_action_save" = "Salvar"; "room_event_action_resend" = "Reenviar"; -"room_event_action_delete" = "Excluir"; -"room_event_action_cancel_send" = "Cancelar envio"; -"room_event_action_cancel_download" = "Cancelar download"; -"room_event_action_view_encryption" = "Informação criptografada"; -"room_warning_about_encryption" = "A criptografia de ponta a ponta está na versão beta e pode não ser confiável.↵\n↵\nVocê ainda não deve confiar nela para proteger os dados.↵\n↵\nOs aparelhos ainda não poderão descriptografar o histórico antes de entrarem na sala.↵\n↵\nAs mensagens criptografadas não estarão visíveis em clientes que ainda não implementaram a criptografia."; -"room_event_failed_to_send" = "Falha ao enviar"; +"room_event_action_delete" = "Deletar"; +"room_event_action_cancel_send" = "Cancelar Enviar"; +"room_event_action_cancel_download" = "Cancelar Download"; +"room_event_action_view_encryption" = "Informação de Encriptação"; +"room_warning_about_encryption" = "Encriptação ponta-a-ponta está em beta e pode não ser confiável.\n\nVocê ainda não devia confiar nela para assegurar dados.\n\nDispositivos ainda não vão ser capazes de decriptar histórico de antes que eles se juntaram à sala.\n\nMensagens encriptadas não vão estar visíveis em clientes que ainda não implementam encriptação."; +"room_event_failed_to_send" = "Falha para enviar"; "room_action_send_photo_or_video" = "Enviar foto ou vídeo"; -"room_action_send_sticker" = "Enviar figurinha"; -"room_replacement_information" = "Esta sala foi substituída e não está mais ativa."; +"room_action_send_sticker" = "Enviar sticker"; +"room_replacement_information" = "Esta sala tem sido substituída e não está mais ativa."; "room_replacement_link" = "A conversa continua aqui."; -"room_predecessor_information" = "Esta sala é uma continuação de outra conversa."; -"room_predecessor_link" = "Clique aqui para ver as mensagens mais antigas."; +"room_predecessor_information" = "Esta sala é uma continuação de uma outra conversa."; +"room_predecessor_link" = "Toque aqui para ver mensagens mais antigas."; "room_resource_limit_exceeded_message_contact_1" = " Por favor "; -"room_resource_limit_exceeded_message_contact_2_link" = "entre em contato com o administrador do serviço"; +"room_resource_limit_exceeded_message_contact_2_link" = "contacte o/a administrador(a) de seu serviço"; "room_resource_limit_exceeded_message_contact_3" = " para continuar usando este serviço."; -"room_resource_usage_limit_reached_message_1_default" = "Este servidor local excedeu um dos limites de seus recursos, portanto· "; -"room_resource_usage_limit_reached_message_1_monthly_active_user" = "Esse servidor local atingiu seu limite mensal de usuários ativos, portanto· "; -"room_resource_usage_limit_reached_message_2" = "alguns usuários não poderão efetuar login."; +"room_resource_usage_limit_reached_message_1_default" = "Este servidorcasa tem excedido um dos limites de recursos então "; +"room_resource_usage_limit_reached_message_1_monthly_active_user" = "Este servidorcasa tem atingido seu limite de Usuárias(os) Mensalmente Ativas(os) então "; +"room_resource_usage_limit_reached_message_2" = "algumas(ns) usuárias(os) não vão ser capazes de fazer login."; "room_resource_usage_limit_reached_message_contact_3" = " para ter este limite aumentado."; // Unknown devices -"unknown_devices_alert_title" = "A sala contém sessões desconhecidas"; -"unknown_devices_send_anyway" = "Enviar mesmo assim"; -"unknown_devices_call_anyway" = "Ligar mesmo assim"; -"unknown_devices_answer_anyway" = "Responder mesmo assim"; -"unknown_devices_verify" = "Confirmar…"; +"unknown_devices_alert_title" = "Sala contém sessões desconhecidas"; +"unknown_devices_send_anyway" = "Enviar Mesmo Assim"; +"unknown_devices_call_anyway" = "Chamar Mesmo Assim"; +"unknown_devices_answer_anyway" = "Atender Mesmo Assim"; +"unknown_devices_verify" = "Verificar…"; "unknown_devices_title" = "Sessões desconhecidas"; // Room Title "room_title_new_room" = "Nova sala"; -"room_title_multiple_active_members" = "%@/%@ participantes ativos"; -"room_title_one_active_member" = "%@/%@ participante ativo"; -"room_title_invite_members" = "Convidar participantes"; -"room_title_members" = "%@ participantes"; -"room_title_one_member" = "1 participante"; +"room_title_multiple_active_members" = "%@/%@ membros ativos"; +"room_title_one_active_member" = "%@/%@ membro ativo"; +"room_title_invite_members" = "Convidar membros"; +"room_title_members" = "%@ membros"; +"room_title_one_member" = "1 membro"; // Room Preview -"room_preview_invitation_format" = "Você foi convidado a participar desta sala por %@"; -"unknown_devices_alert" = "Esta sala contém sessões desconhecidas que não foram confirmadas.↵\nIsso significa que não há garantia de que as sessões pertençam aos usuários em questão.↵\nRecomendamos que você passe pelo processo de confirmação de cada sessão antes de continuar, mas você pode reenviar a mensagem sem confirmar, se preferir."; -"room_preview_subtitle" = "Esta é uma prévia desta sala. Interações de sala foram desativadas."; -"room_preview_unlinked_email_warning" = "Este convite foi enviado para %@, que não está associado a esta conta. Você pode querer fazer login com uma conta diferente ou adicionar este e-mail a essa conta."; -"room_preview_try_join_an_unknown_room" = "Você está tentando acessar %@. Você gostaria de entrar para participar da discussão?"; +"room_preview_invitation_format" = "Você tem sido convidada(o) a juntar-se a esta sala por %@"; +"unknown_devices_alert" = "Esta sala contém sessões desconhecidas que não têm sido verificadas.\nIsto significa que não há nenhuma garantia que as sessões pertencem às/aos usuárias(os) às/aos quais elas clamam pertencer.\nNós recomendamos que você passe pelo processo de verificação para cada sessão antes de continuar, mas você pode reenviar a mensagem sem verificar se você preferir."; +"room_preview_subtitle" = "Esta é uma previsualização desta sala. Interações de sala têm sido desativadas."; +"room_preview_unlinked_email_warning" = "Este convite foi enviado para %@, que não está associada(o) a esta conta. Você pode desejar fazer login com uma conta diferente, ou adicionar este email a sua conta."; +"room_preview_try_join_an_unknown_room" = "Você está tentando acessar %@. Você gostaria de se juntar para participar na discussão?"; "room_preview_try_join_an_unknown_room_default" = "uma sala"; // Settings "settings_title" = "Configurações"; -"account_logout_all" = "Sair de todas as contas"; -"settings_config_no_build_info" = "Nenhuma informação da build"; +"account_logout_all" = "Fazer logout de todas as contas"; +"settings_config_no_build_info" = "Nenhuma info de build"; "settings_mark_all_as_read" = "Marcar todas as mensagens como lidas"; -"settings_report_bug" = "Relatar erro"; -"settings_config_home_server" = "O servidor local é %@"; -"settings_config_identity_server" = "Servidor de Identidades é %@"; -"settings_config_user_id" = "Logado como %@"; -"settings_user_settings" = "CONFIGURAÇÕES DE USUÁRIO"; -"settings_notifications_settings" = "CONFIGURAÇÕES DE NOTIFICAÇÕES"; +"settings_report_bug" = "Reportar bug"; +"settings_config_home_server" = "Servidorcasa é %@"; +"settings_config_identity_server" = "Servidor de identidade é %@"; +"settings_config_user_id" = "Feito login como %@"; +"settings_user_settings" = "CONFIGURAÇÕES DE USUÁRIA(O)"; +"settings_notifications_settings" = "CONFIGURAÇÕES DE NOTIFICAÇÃO"; "settings_calls_settings" = "CHAMADAS"; -"settings_user_interface" = "INTERFACE DO USUÁRIO"; -"settings_ignored_users" = "USUÁRIOS BLOQUEADOS"; +"settings_user_interface" = "INTERFACE DE USUÁRIA(O)"; +"settings_ignored_users" = "USUÁRIAS(OS) IGNORADAS(OS)"; "settings_contacts" = "CONTATOS LOCAIS"; -"settings_advanced" = "AVANÇADO"; -"settings_other" = "OUTROS"; -"settings_labs" = "LABORATÓRIO"; -"settings_flair" = "Mostrar ícones onde permitido"; +"settings_advanced" = "AVANÇADAS"; +"settings_other" = "OUTRAS"; +"settings_labs" = "LABS"; +"settings_flair" = "Mostrar flair onde permitido"; "settings_devices" = "SESSÕES"; "settings_cryptography" = "CRIPTOGRAFIA"; -"settings_deactivate_account" = "DESATIVAR MINHA CONTA"; -"settings_sign_out" = "Sair"; +"settings_deactivate_account" = "DESATIVAR CONTA"; +"settings_sign_out" = "Fazer Signout"; "settings_sign_out_confirmation" = "Você tem certeza?"; -"settings_sign_out_e2e_warn" = "Você perderá suas chaves de criptografia de ponta a ponta. Isso significa que você não poderá mais ler mensagens antigas em salas criptografadas neste aparelho."; -"settings_profile_picture" = "Foto de perfil"; +"settings_sign_out_e2e_warn" = "Você vai perder suas chaves de encriptação ponta-a-ponta. Isso significa que você não vai mais ser capaz de ler mensagens antigas em salas encriptadas neste dispositivo."; +"settings_profile_picture" = "Imagem de Perfil"; // Room Details -"room_details_title" = "Detalhes da sala"; -"settings_first_name" = "Primeiro nome"; +"room_details_title" = "Detalhes de Sala"; +"settings_first_name" = "Primeiro Nome"; "settings_surname" = "Sobrenome"; "settings_remove_prompt_title" = "Confirmação"; -"settings_remove_email_prompt_msg" = "Tem certeza de que deseja remover o endereço de e-mail %@?"; -"settings_remove_phone_prompt_msg" = "Tem certeza de que deseja remover o número de telefone %@?"; -"settings_email_address" = "E-mail"; -"settings_email_address_placeholder" = "Insira o seu endereço de e-mail"; -"settings_add_email_address" = "Adicionar endereço de e-mail"; +"settings_remove_email_prompt_msg" = "Você tem certeza que você quer remover o endereço de email %@?"; +"settings_remove_phone_prompt_msg" = "Você tem certeza que você quer remover o número de telefone %@?"; +"settings_email_address" = "Email"; +"settings_email_address_placeholder" = "Entre seu endereço de email"; +"settings_add_email_address" = "Adicionar endereço de email"; "settings_phone_number" = "Telefone"; "settings_add_phone_number" = "Adicionar número de telefone"; -"settings_night_mode" = "Modo noturno"; -"settings_fail_to_update_profile" = "Falha ao atualizar perfil"; -"settings_enable_push_notif" = "Notificações neste aparelho"; -"settings_show_decrypted_content" = "Mostrar conteúdo descriptografado"; -"settings_global_settings_info" = "Configurações gerais de notificação estão disponíveis no %@ Web"; -"settings_on_denied_notification" = "As notificações são negadas para %@, permita-as nas configurações do seu aparelho"; -"settings_enable_callkit" = "Chamada integrada"; -"settings_callkit_info" = "Receba chamadas na sua tela de bloqueio. Veja suas chamadas do Element no histórico de chamadas do sistema. Se o iCloud estiver ativado, esse histórico de chamadas será compartilhado com a Apple."; -"settings_ui_language" = "Idioma"; +"settings_night_mode" = "Modo Noite"; +"settings_fail_to_update_profile" = "Falha para atualizar perfil"; +"settings_enable_push_notif" = "Notificações neste dispositivo"; +"settings_show_decrypted_content" = "Mostrar conteúdo decriptado"; +"settings_global_settings_info" = "Configurações de notificação globais estão disponíveis em seu cliente web %@"; +"settings_on_denied_notification" = "Notificações são negadas para %@, por favor permita-as nas configurações de seu dispositivo"; +"settings_enable_callkit" = "Chamamento integrado"; +"settings_callkit_info" = "Receba chamadas chegando em sua tela de bloqueio. Veja suas chamadas Element no histórico de chamadas do sistema. Se iCloud está ativado, este histórico de chamadas vai ser compartilhado com Apple."; +"settings_ui_language" = "Língua"; "settings_ui_theme" = "Tema"; -"settings_ui_theme_auto" = "Automático"; +"settings_ui_theme_auto" = "Auto"; "settings_ui_theme_light" = "Claro"; "settings_ui_theme_dark" = "Escuro"; "settings_ui_theme_black" = "Preto"; -"settings_ui_theme_picker_title" = "Selecione o tema"; -"settings_ui_theme_picker_message" = "\"Auto\" usa as configurações \"Inverter Cores\" do seu aparelho"; +"settings_ui_theme_picker_title" = "Selecione um tema"; +"settings_ui_theme_picker_message" = "\"Auto\" usa as configurações \"Inverter Cores\" de seu dispositivo"; "settings_unignore_user" = "Mostrar todas as mensagens de %@?"; -"settings_contacts_discover_matrix_users" = "Use e-mails e números de telefone para descobrir usuários"; -"settings_contacts_phonebook_country" = "País da lista telefônica"; -"settings_labs_e2e_encryption" = "Criptografia de ponta a ponta"; -"settings_labs_e2e_encryption_prompt_message" = "Para concluir a configuração da criptografia, você deve efetuar login novamente."; +"settings_contacts_discover_matrix_users" = "Usar emails e números de telefone para descobrir usuários"; +"settings_contacts_phonebook_country" = "País de livro de telefones"; +"settings_labs_e2e_encryption" = "Encriptação Ponta-a-Ponta"; +"settings_labs_e2e_encryption_prompt_message" = "Para terminar de configurar encriptação você deve fazer login de novo."; "settings_labs_room_members_lazy_loading" = "Usuários de carrregamento Lazy de salas"; "settings_labs_room_members_lazy_loading_error_message" = "Seu homeserver não suporta o carregamento Lazy de membros da sala ainda. Tente depois."; -"settings_labs_create_conference_with_jitsi" = "Crie chamadas em grupo com jitsi"; +"settings_labs_create_conference_with_jitsi" = "Criar chamadas de conferência com jitsi"; "settings_version" = "Versão %@"; -"settings_olm_version" = "Versão do Olm %@"; +"settings_olm_version" = "Versão de Olm %@"; "settings_copyright" = "Copyright"; "settings_copyright_url" = "https://riot.im/copyright"; -"settings_term_conditions" = "Termos e Condições"; +"settings_term_conditions" = "Termos & Condições"; "settings_term_conditions_url" = "https://riot.im/tac_apple"; "settings_privacy_policy" = "Política de Privacidade"; "settings_privacy_policy_url" = "https://riot.im/privacy"; -"settings_third_party_notices" = "Avisos de terceiros"; -"settings_send_crash_report" = "Enviar dados de falha e uso anônimos"; -"settings_enable_rageshake" = "Agite rapidamente para relatar um erro"; -"settings_clear_cache" = "Limpar cache e recarregar"; -"settings_change_password" = "Alterar senha"; +"settings_third_party_notices" = "Notas de Terceiros"; +"settings_send_crash_report" = "Enviar dados de cash & uso anon"; +"settings_enable_rageshake" = "Agite com raiva para reportar bug"; +"settings_clear_cache" = "Limpar cache"; +"settings_change_password" = "Mudar senha"; "settings_old_password" = "senha antiga"; "settings_new_password" = "senha nova"; -"settings_confirm_password" = "confirme a senha"; -"settings_fail_to_update_password" = "Falha ao atualizar senha"; -"settings_password_updated" = "Sua senha foi atualizada"; -"settings_crypto_device_name" = "Nome da sessão:· "; -"settings_crypto_device_id" = "\nID da sessão: "; -"settings_crypto_device_key" = "\nChave da sessão:\n"; +"settings_confirm_password" = "confirmar senha"; +"settings_fail_to_update_password" = "Falha para atualizar senha"; +"settings_password_updated" = "Sua senha tem sido atualizada"; +"settings_crypto_device_name" = "Nome de sessão: "; +"settings_crypto_device_id" = "\nID de sessão: "; +"settings_crypto_device_key" = "\nChave de sessão:\n"; "settings_crypto_export" = "Chaves de exportação"; -"settings_crypto_blacklist_unverified_devices" = "Criptografar apenas para sessões confirmadas"; +"settings_crypto_blacklist_unverified_devices" = "Encriptar para sessões verificadas somente"; "settings_deactivate_my_account" = "Desativar minha conta"; -"room_details_people" = "Participantes"; -"room_details_files" = "Arquivos"; +"room_details_people" = "Membros"; +"room_details_files" = "Uploads"; "room_details_settings" = "Configurações"; -"room_details_photo" = "Imagem da Sala"; -"room_details_room_name" = "Nome da sala"; -"room_details_topic" = "Descrição"; -"room_details_favourite_tag" = "Favorito"; +"room_details_photo" = "Foto de Sala"; +"room_details_room_name" = "Nome de Sala"; +"room_details_topic" = "Tópico"; +"room_details_favourite_tag" = "Favoritar"; "room_details_low_priority_tag" = "Baixa prioridade"; -"room_details_mute_notifs" = "Silenciar notificações"; -"room_details_direct_chat" = "Chat direto"; +"room_details_mute_notifs" = "Mutar notificações"; +"room_details_direct_chat" = "Chat Direto"; "room_details_access_section" = "Quem pode acessar esta sala?"; -"room_details_access_section_invited_only" = "Apenas pessoas que foram convidadas"; -"room_details_access_section_anyone_apart_from_guest" = "Quem conhece o link da sala, exceto convidados"; -"room_details_access_section_anyone" = "Qualquer pessoa que conheça o link da sala, incluindo convidados"; -"room_details_access_section_no_address_warning" = "Para ligar a uma sala, isto deve ter um endereço"; -"room_details_access_section_directory_toggle" = "Listar esta sala na lista de salas"; +"room_details_access_section_invited_only" = "Somente pessoas que têm sido convidadas"; +"room_details_access_section_anyone_apart_from_guest" = "Qualquer pessoa que sabe o link da sala, a parte de visitantes"; +"room_details_access_section_anyone" = "Qualquer pessoa que sabe o link da sala, incluindo visitantes"; +"room_details_access_section_no_address_warning" = "Para linkar a uma sala ela deve ter um endereço"; +"room_details_access_section_directory_toggle" = "Listar esta sala em diretório de salas"; "room_details_history_section" = "Quem pode ler o histórico?"; -"room_details_history_section_anyone" = "Qualquer um"; -"room_details_history_section_members_only" = "Apenas participantes (desde o momento em que selecionamos esta opção)"; -"room_details_history_section_members_only_since_invited" = "Apenas participantes (desde que foram convidados)"; -"room_details_history_section_members_only_since_joined" = "Apenas participantes (desde que aderiram)"; -"room_details_history_section_prompt_title" = "Alerta de privacidade"; -"room_details_history_section_prompt_msg" = "Alterações em quem pode ler o histórico de conversas aplica-se apenas para mensagens futuras nesta sala. A visibilidade do histórico existente não será alterada."; +"room_details_history_section_anyone" = "Qualquer pessoa"; +"room_details_history_section_members_only" = "Membros somente (desde o ponto no tempo de seleção desta opção)"; +"room_details_history_section_members_only_since_invited" = "Membros somente (desde que eles foram convidados)"; +"room_details_history_section_members_only_since_joined" = "Membros somente (desde que eles se juntaram)"; +"room_details_history_section_prompt_title" = "Aviso de privacidade"; +"room_details_history_section_prompt_msg" = "Mundaças de quem pode ler o histórico só se vão aplicar a mensagens futuras nesta sala. A visibilidade de histórico existente vai ser inalterada."; "room_details_addresses_section" = "Endereços"; -"room_details_no_local_addresses" = "Este quarto não tem endereços locais"; -"room_details_new_address" = "adicionar novo endereço"; -"room_details_new_address_placeholder" = "Adicionar novo endereço (por exemplo, #foo%@)"; +"room_details_no_local_addresses" = "Esta sala não tem nenhum endereço local"; +"room_details_new_address" = "Adicionar novo endereço"; +"room_details_new_address_placeholder" = "Adicionar novo endereço (e.g. #foo%@)"; "room_details_addresses_invalid_address_prompt_title" = "Formato de alias inválido"; "room_details_addresses_invalid_address_prompt_msg" = "%@ não é um formato válido para um alias"; -"room_details_addresses_disable_main_address_prompt_title" = "Alerta de endereço principal"; -"room_details_addresses_disable_main_address_prompt_msg" = "Você terá nenhum endereço principal especificado. O endereço principal padrão desta sala será escolhido aleatoriamente"; -"room_details_flair_section" = "Mostrar ícones de comunidades"; -"room_details_new_flair_placeholder" = "Adicionar nova ID de comunidade (por exemplo, +foo%@)"; -"room_details_flair_invalid_id_prompt_title" = "Formato Inválido"; +"room_details_addresses_disable_main_address_prompt_title" = "Aviso de endereço principal"; +"room_details_addresses_disable_main_address_prompt_msg" = "Você não vai ter nenhum endereço principal especificado. O endereço principal default para esta sala vai ser pego aleatoriamente"; +"room_details_flair_section" = "Mostrar flair para comunidades"; +"room_details_new_flair_placeholder" = "Adicionar nova ID de comunidade (e.g. +foo%@)"; +"room_details_flair_invalid_id_prompt_title" = "Formato inválido"; "room_details_flair_invalid_id_prompt_msg" = "%@ não é um identificador válido para uma comunidade"; -"room_details_banned_users_section" = "Usuários banidos"; -"room_details_advanced_section" = "Avançado"; -"room_details_advanced_room_id" = "ID da sala:"; -"room_details_advanced_enable_e2e_encryption" = "Ativar criptografia (atenção: não pode ser desativado novamente!)"; -"room_details_advanced_e2e_encryption_enabled" = "A criptografia está ativada nesta sala"; -"room_details_advanced_e2e_encryption_disabled" = "A criptografia não está ativada nesta sala."; -"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "Criptografar apenas para sessões confirmadas"; -"room_details_fail_to_update_avatar" = "Falha ao atualizar a imagem da sala"; -"room_details_fail_to_update_room_name" = "Falha ao atualizar o nome da sala"; -"room_details_fail_to_update_topic" = "Falha ao atualizar a descrição"; -"room_details_fail_to_update_room_guest_access" = "Falha ao atualizar o acesso do convidado da sala"; -"room_details_fail_to_update_room_join_rule" = "Falha ao atualizar a regra de participação"; -"room_details_fail_to_update_room_directory_visibility" = "Falha ao atualizar a visibilidade da sala na lista"; -"room_details_fail_to_update_history_visibility" = "Falha ao atualizar a visibilidade do histórico"; +"room_details_banned_users_section" = "Usuárias(os) banidas(os)"; +"room_details_advanced_section" = "Avançadas"; +"room_details_advanced_room_id" = "ID de sala:"; +"room_details_advanced_enable_e2e_encryption" = "Ativar encriptação (aviso: não pode ser desativada de novo!)"; +"room_details_advanced_e2e_encryption_enabled" = "Encriptação está ativada nesta sala"; +"room_details_advanced_e2e_encryption_disabled" = "Encriptação não está ativada nesta sala."; +"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "Encriptar para sessões verificadas somente"; +"room_details_fail_to_update_avatar" = "Falha para atualizar a foto da sala"; +"room_details_fail_to_update_room_name" = "Falha para atualizar o nome da sala"; +"room_details_fail_to_update_topic" = "Falha para atualizar o tópico"; +"room_details_fail_to_update_room_guest_access" = "Falha para atualizar o acesso de visitante da sala"; +"room_details_fail_to_update_room_join_rule" = "Falha para atualizar a regra de se juntar"; +"room_details_fail_to_update_room_directory_visibility" = "Falha para atualizar a visibilidade do diretório de salas"; +"room_details_fail_to_update_history_visibility" = "Falha para atualizar a visibilidade do histórico"; "room_details_advanced_e2e_encryption_prompt_message" = "A criptografia de ponta a ponta é experimental e pode não ser confiável.\n\nVocê ainda não deve confiar nele para proteger os dados.\n\nOs dispositivos ainda não poderão descriptografar o histórico antes de ingressarem na sala.\n\nQuando a criptografia estiver ativada para uma sala, ela não poderá ser desativada novamente (por enquanto).\n\nAs mensagens criptografadas não estarão visíveis em clientes que ainda não implementam a criptografia."; -"room_details_fail_to_add_room_aliases" = "Falha ao adicionar os novos endereços da sala"; -"room_details_fail_to_remove_room_aliases" = "Falha ao remover os endereços da sala"; -"room_details_fail_to_update_room_canonical_alias" = "Falha ao atualizar o endereço principal"; -"room_details_fail_to_update_room_communities" = "Falha ao atualizar as comunidades relacionadas"; -"room_details_fail_to_update_room_direct" = "Falha ao atualizar o sinalizador direto desta sala"; -"room_details_fail_to_enable_encryption" = "Falha ao ativar a criptografia nesta sala"; -"room_details_save_changes_prompt" = "Deseja salvar as alterações?"; -"room_details_set_main_address" = "Definir como endereço principal"; -"room_details_unset_main_address" = "Desativar como endereço principal"; -"room_details_copy_room_id" = "Copiar o ID da sala"; -"room_details_copy_room_address" = "Copiar o endereço da sala"; -"room_details_copy_room_url" = "Copiar o link da sala"; +"room_details_fail_to_add_room_aliases" = "Falha para adicionar os novos endereços da sala"; +"room_details_fail_to_remove_room_aliases" = "Falha para remover os endereços da sala"; +"room_details_fail_to_update_room_canonical_alias" = "Falha para atualizar o endereço principal"; +"room_details_fail_to_update_room_communities" = "Falha para atualizar as comunidades relacionadas"; +"room_details_fail_to_update_room_direct" = "Falha para atualizar a bandeira direta desta sala"; +"room_details_fail_to_enable_encryption" = "Falha para ativar encriptação nesta sala"; +"room_details_save_changes_prompt" = "Você quer salvar mudanças?"; +"room_details_set_main_address" = "Definir como Endereço Principal"; +"room_details_unset_main_address" = "Desdefinir como Endereço Principal"; +"room_details_copy_room_id" = "Copiar ID de Sala"; +"room_details_copy_room_address" = "Copiar Endereço de Sala"; +"room_details_copy_room_url" = "Copiar URL de Sala"; // Group Details -"group_details_title" = "Detalhes da Comunidade"; -"group_details_home" = "Início"; +"group_details_title" = "Detalhes de Comunidade"; +"group_details_home" = "Home"; "group_details_people" = "Pessoas"; "group_details_rooms" = "Salas"; // Group Home -"group_home_one_member_format" = "1 participante"; -"group_home_multi_members_format" = "%tu participantes"; +"group_home_one_member_format" = "1 membro"; +"group_home_multi_members_format" = "%tu membros"; "group_home_one_room_format" = "1 sala"; "group_home_multi_rooms_format" = "%tu salas"; -"group_invitation_format" = "%@ convidou você para participar desta comunidade"; +"group_invitation_format" = "%@ tem convidado você para se juntar a esta comunidade"; // Group participants "group_participants_add_participant" = "Adicionar participante"; -"group_participants_leave_prompt_title" = "Sair da comunidade"; -"group_participants_leave_prompt_msg" = "Tem certeza de que deseja sair da comunidade?"; +"group_participants_leave_prompt_title" = "Sair de grupo"; +"group_participants_leave_prompt_msg" = "Você tem certeza que você quer sair do grupo?"; "group_participants_remove_prompt_title" = "Confirmação"; -"group_participants_remove_prompt_msg" = "Tem certeza de que deseja remover %@ desta comunidade?"; +"group_participants_remove_prompt_msg" = "Você tem certeza que você quer remover %@ deste grupo?"; "group_participants_invite_prompt_title" = "Confirmação"; -"group_participants_invite_prompt_msg" = "Tem certeza de que deseja convidar %@ para esta comunidade?"; -"group_participants_filter_members" = "Pesquisar participantes da comunidade"; -"group_participants_invite_another_user" = "Pesquisar / convidar por ID de usuário ou nome e sobrenome"; -"group_participants_invite_malformed_id_title" = "Erro ao convidar"; -"group_participants_invite_malformed_id" = "ID malformado. Deve ser um ID da Matrix como \"@localpart:domain\""; -"group_participants_invited_section" = "CONVIDADO"; +"group_participants_invite_prompt_msg" = "Você tem certeza que você quer convidar %@ para este grupo?"; +"group_participants_filter_members" = "Filtrar membros de comunidade"; +"group_participants_invite_another_user" = "Pesquisar / convidar por ID de Usuária(o) ou Nome"; +"group_participants_invite_malformed_id_title" = "Erro de Convidar"; +"group_participants_invite_malformed_id" = "ID malformada. Deveria ser uma ID Matrix como '@partlocal:dominio'"; +"group_participants_invited_section" = "CONVIDADAS(OS)"; // Group rooms -"group_rooms_filter_rooms" = "Filtrar salas da comunidade"; +"group_rooms_filter_rooms" = "Filtrar salas de comunidade"; // Read Receipts -"read_receipts_list" = "Lista de confirmações de leitura"; -"receipt_status_read" = "Leitura: "; +"read_receipts_list" = "Lista de Recibos de Leitura"; +"receipt_status_read" = "Lida: "; // Media picker -"media_picker_library" = "Galeria"; +"media_picker_library" = "Biblioteca"; "media_picker_select" = "Selecionar"; // Directory -"directory_title" = "Lista"; -"directory_server_picker_title" = "Selecionar uma lista"; -"settings_display_name" = "Nome e sobrenome"; -"settings_pin_rooms_with_missed_notif" = "Fixar sala com notificações perdidas"; -"settings_pin_rooms_with_unread" = "Fixar sala com mensagens não lidas"; -"directory_server_all_rooms" = "Todas as salas no servidor %@"; -"directory_server_all_native_rooms" = "Todas as salas nativas da Matrix"; -"directory_server_type_homeserver" = "Digite um servidor local para listar suas salas públicas"; +"directory_title" = "Diretório"; +"directory_server_picker_title" = "Selecionar um diretório"; +"settings_display_name" = "Nome de Exibição"; +"settings_pin_rooms_with_missed_notif" = "Fixar salas com notificações perdidas"; +"settings_pin_rooms_with_unread" = "Fixar salas com mensagens não-lidas"; +"directory_server_all_rooms" = "Todas as salas em servidor %@"; +"directory_server_all_native_rooms" = "Todas as salas Matrix nativas"; +"directory_server_type_homeserver" = "Digite um servidorcasa para de onde listar salas públicas"; "directory_server_placeholder" = "matrix.org"; // Events formatter -"event_formatter_member_updates" = "%tu alterações na filiação"; +"event_formatter_member_updates" = "%tu mudanças de filiação"; "event_formatter_widget_added" = "%@ widget adicionado por %@"; "event_formatter_widget_removed" = "%@ widget removido por %@"; -"event_formatter_jitsi_widget_added" = "Chamada em grupo adicionada por %@"; -"event_formatter_jitsi_widget_removed" = "Chamada em grupo removida por %@"; -"event_formatter_rerequest_keys_part1_link" = "Solicitar novamente chaves de criptografia"; -"event_formatter_rerequest_keys_part2" = " ·de suas outras sessões."; +"event_formatter_jitsi_widget_added" = "Conferência de VoIP adicionada por %@"; +"event_formatter_jitsi_widget_removed" = "Conferência de VoIP removida por %@"; +"event_formatter_rerequest_keys_part1_link" = "Re-requisitar chaves de encriptação"; +"event_formatter_rerequest_keys_part2" = " de suas outras sessões."; // Others "or" = "ou"; "you" = "Você"; "today" = "Hoje"; "yesterday" = "Ontem"; -"network_offline_prompt" = "A internet parece estar fora do ar."; -"homeserver_connection_lost" = "Não foi possível conectar-se ao servidor local."; +"network_offline_prompt" = "A conexão de Internet parece estar offline."; +"homeserver_connection_lost" = "Não foi possível conectar-se ao servidorcasa."; "public_room_section_title" = "Salas Públicas (em %@):"; -"bug_report_prompt" = "O aplicativo encerrou inesperadamente na última vez. Gostaria de enviar um relatório de erros?"; -"rage_shake_prompt" = "Você parece estar agitando o telefone em frustração. Gostaria de enviar um relatório de erro?"; -"do_not_ask_again" = "Não perguntar novamente"; -"camera_access_not_granted" = "%@ não tem permissão para usar a câmera, altere as configurações de privacidade"; +"bug_report_prompt" = "O aplicativo tem crashado da última vez. Você gostaria de submeter um reporte de crash?"; +"rage_shake_prompt" = "Você parece estar agitando o telefone em frustração. Você gostaria desubmeter um reporte de bug?"; +"do_not_ask_again" = "Não perguntar de novo"; +"camera_access_not_granted" = "%@ não tem permissão para usar Câmera, por favor mude configurações de privacidade"; "large_badge_value_k_format" = "%.1fK"; // Call -"call_incoming_voice_prompt" = "Recebendo chamada de voz de %@"; -"call_incoming_video_prompt" = "Recebendo chamada de vídeo de %@"; -"call_incoming_voice" = "Recebendo chamada de voz…"; -"call_incoming_video" = "Recebendo chamada de vídeo…"; -"call_already_displayed" = "Já existe uma chamada em andamento."; -"call_jitsi_error" = "Não foi possível participar da chamada em grupo."; +"call_incoming_voice_prompt" = "Chamada de voz recebendo de %@"; +"call_incoming_video_prompt" = "Chamada de vídeo recebendo de %@"; +"call_incoming_voice" = "Chamada recebendo…"; +"call_incoming_video" = "Chamada de vídeo recebendo…"; +"call_already_displayed" = "Já existe uma chamada em progresso."; +"call_jitsi_error" = "Falha para se juntar a chamada de conferência."; // No VoIP support -"no_voip_title" = "Recebendo chamada"; -"no_voip" = "%@ está ligando para você, mas %@ ainda não suporta chamadas.↵\nVocê pode ignorar essa notificação e aceitar a chamada em outro aparelho, ou recusá-la."; +"no_voip_title" = "Chamada recebendo"; +"no_voip" = "%@ está chamando você mas %@ não suporta chamadas ainda.\nVocê pode ignorar esta notificação e atender a chamada de um outro dispositivo ou você pode rejeitá-la."; // Crash report -"google_analytics_use_prompt" = "Você gostaria de ajudar a melhorar o %@ informando automaticamente relatórios de falhas e dados de uso anônimos?"; +"google_analytics_use_prompt" = "Você gostaria de ajudar a melhorar %@ ao reportar automaticamente reportes de crash e dados de uso anônimos?"; // Crypto -"e2e_enabling_on_app_update" = "O Element agora suporta criptografia de ponta a ponta, mas você precisa fazer login novamente para ativá-la.↵\n↵\nVocê pode fazer isso agora ou mais tarde nas configurações do aplicativo."; -"e2e_need_log_in_again" = "Você precisa fazer login novamente para gerar chaves de criptografia de ponta a ponta para esta sessão, e enviar a chave pública ao seu servidor local.↵\nIsso ocorre apenas dessa vez; desculpe pela inconveniência."; +"e2e_enabling_on_app_update" = "Element agora suporta encriptação ponta-a-ponta mas você precisa fazer login de novo para ativá-la.\n\nVocê pode fazê-lo agora ou mais tarde desde as configurações do aplicativo."; +"e2e_need_log_in_again" = "Você precisa fazer login de volta para gerar chaves de encriptação ponta-a-ponta para esta sessão e submeter a chave pública a seu servidorcasa.\nIsto é só desta vez; desculpe pela inconveniência."; // Bug report -"bug_report_title" = "Relatório de erro"; -"bug_report_description" = "Por favor, descreva o erro. O que você fez? O que você esperava que acontecesse? O que realmente aconteceu?"; -"bug_crash_report_title" = "Relatório de erros"; -"bug_crash_report_description" = "Por favor, descreva o que você fez antes do erro:"; -"bug_report_logs_description" = "Para diagnosticar problemas, os logs deste cliente serão enviados com este relatório de erro. Se preferir enviar apenas o texto acima, por favor desmarque:"; -"bug_report_send_logs" = "Enviar registros"; -"bug_report_send_screenshot" = "Enviar recorte de tela"; +"bug_report_title" = "Report de Bug"; +"bug_report_description" = "Por favor descreva o bug. O que você fez? O que você esperava que acontecesse? O que na verdade aconteceu?"; +"bug_crash_report_title" = "Reporte de Crash"; +"bug_crash_report_description" = "Por favor descreva o que você fez antes do crash:"; +"bug_report_logs_description" = "A fim de diagnosticar problemas, logs deste cliente vão ser enviados com este reporte de bug. Se você prefere somente enviar o texto acima, por favor desmarque:"; +"bug_report_send_logs" = "Enviar logs"; +"bug_report_send_screenshot" = "Enviar screenshot"; "bug_report_progress_zipping" = "Coletando logs"; -"bug_report_progress_uploading" = "Enviando relatório"; +"bug_report_progress_uploading" = "Fazendo upload de reporte"; "bug_report_send" = "Enviar"; // Widget "widget_no_power_to_manage" = "Você precisa de permissão para gerenciar widgets nesta sala"; -"widget_creation_failure" = "A criação do widget falhou"; -"widget_sticker_picker_no_stickerpacks_alert" = "No momento, você não possui pacotes de figurinhas ativados."; -"widget_sticker_picker_no_stickerpacks_alert_add_now" = "Adicione alguns agora?"; +"widget_creation_failure" = "Criação de widget tem falhado"; +"widget_sticker_picker_no_stickerpacks_alert" = "Você não tem atualmente nenhum pacote de stickers ativados."; +"widget_sticker_picker_no_stickerpacks_alert_add_now" = "Adicionar alguns agora?"; // Widget Integration Manager -"widget_integration_need_to_be_able_to_invite" = "Você precisa convidar os usuários para fazer isso."; -"widget_integration_unable_to_create" = "Não é possível criar widget."; -"widget_integration_failed_to_send_request" = "Falha ao enviar solicitação."; +"widget_integration_need_to_be_able_to_invite" = "Você precisa ser capaz de convidar usuárias(os) para fazer isso."; +"widget_integration_unable_to_create" = "Incapaz de criar widget."; +"widget_integration_failed_to_send_request" = "Falha para enviar requisição."; "widget_integration_room_not_recognised" = "Esta sala não é reconhecida."; -"widget_integration_positive_power_level" = "O nível de permissão deve ser inteiro positivo."; +"widget_integration_positive_power_level" = "Nível de poder deve ser inteiro positivo."; "widget_integration_must_be_in_room" = "Você não está nesta sala."; "widget_integration_no_permission_in_room" = "Você não tem permissão para fazer isso nesta sala."; -"widget_integration_missing_room_id" = "room_id ausente em pedido."; -"widget_integration_missing_user_id" = "user_id ausente em pedido."; -"widget_integration_room_not_visible" = "Sala %@ não é visível."; +"widget_integration_missing_room_id" = "room_id faltando em requisição."; +"widget_integration_missing_user_id" = "user_id faltando em requisição."; +"widget_integration_room_not_visible" = "Sala %@ não está visível."; // Share extension -"share_extension_auth_prompt" = "Entre no aplicativo principal para compartilhar conteúdo"; -"share_extension_failed_to_encrypt" = "Falha ao enviar. Verifique no aplicativo principal as configurações de criptografia desta sala"; +"share_extension_auth_prompt" = "Faça login no app principal para compartilhar conteúdo"; +"share_extension_failed_to_encrypt" = "Falha para enviar. Cheque no app principal as configurações de encriptação para esta sala"; // Room key request dialog -"e2e_room_key_request_title" = "Pedido de chave de encriptação"; -"e2e_room_key_request_message_new_device" = "Você adicionou uma nova sessão '%@', que está solicitando chaves de criptografia."; -"e2e_room_key_request_message" = "Sua sessão não confirmada '%@' está solicitando chaves de criptografia."; -"e2e_room_key_request_start_verification" = "Iniciar confirmação…"; -"e2e_room_key_request_share_without_verifying" = "Compartilhar sem confirmar"; -"e2e_room_key_request_ignore_request" = "Ignorar solicitação"; +"e2e_room_key_request_title" = "Requisição de chave de encriptação"; +"e2e_room_key_request_message_new_device" = "Você adicionou uma nova sessão '%@', que está requisitando chaves de encriptação."; +"e2e_room_key_request_message" = "Sua sessão não-verificada '%@' está requisitando chaves de encriptação."; +"e2e_room_key_request_start_verification" = "Começar verificação…"; +"e2e_room_key_request_share_without_verifying" = "Compartilhar sem verificar"; +"e2e_room_key_request_ignore_request" = "Ignorar requisição"; // GDPR -"gdpr_consent_not_given_alert_message" = "Para continuar usando o %@ servidor local, você deve revisar e concordar com os termos e condições."; +"gdpr_consent_not_given_alert_message" = "Para continuar usando o servidorcasa %@ você deve revisar e concordar com os termos e condições."; "gdpr_consent_not_given_alert_review_now_action" = "Revisar agora"; -"deactivate_account_title" = "Desativar minha conta"; -"deactivate_account_informations_part1" = "Isso tornará sua conta permanentemente inutilizável. Você não poderá efetuar login e ninguém poderá registrar novamente o mesmo ID de usuário. Isso fará com que sua conta deixe todas as salas nas quais está participando e removerá os detalhes da sua conta do seu servidor de identidade. "; -"deactivate_account_informations_part2_emphasize" = "Essa ação é irreversível."; -"deactivate_account_informations_part3" = "\n\nDesativando sua conta "; -"deactivate_account_informations_part4_emphasize" = "não nos faz esquecer, por padrão, as mensagens que você enviou. "; -"deactivate_account_informations_part5" = "Se você gostaria que nós esquecêssemos suas mensagens, por favor marque a caixa abaixo↵\n↵\nA visibilidade das mensagens no Matrix é semelhante ao e-mail. O fato de esquecermos suas mensagens significa que as mensagens que você enviou não serão compartilhadas com usuários novos ou não registrados, mas os usuários registrados que já têm acesso a essas mensagens ainda terão acesso à cópia delas."; -"deactivate_account_forget_messages_information_part1" = "Quando minha conta for desativada, exclua todas as mensagens que eu enviei ("; -"deactivate_account_forget_messages_information_part2_emphasize" = "Atenção"; -"deactivate_account_forget_messages_information_part3" = ": isso fará com que futuros usuários vejam uma visão incompleta das conversas)"; -"deactivate_account_validate_action" = "Desativar minha conta"; -"deactivate_account_password_alert_title" = "Desativar minha conta"; -"deactivate_account_password_alert_message" = "Para continuar, por favor, digite sua senha"; +"deactivate_account_title" = "Desativar Conta"; +"deactivate_account_informations_part1" = "Isto vai fazer sua conta permanentemente inusável. Você não vai ser capaz de fazer login, e ninguém vai ser capaz de re-registrar a mesma ID de usuária(o). Isto vai causar sua conta sair de todas as salas em que ela está participando, e vai remover detalhes de sua conta de seu servidor de identidade. "; +"deactivate_account_informations_part2_emphasize" = "Esta ação é irreversível."; +"deactivate_account_informations_part3" = "\n\nDesativar sua conta "; +"deactivate_account_informations_part4_emphasize" = "não nos causa por default esquecer mensagens que você tem enviado. "; +"deactivate_account_informations_part5" = "Se você gostaria que nós esqueçamos suas mensagens, por favor marque a caixa abaixo.\n\nVisibilidade de mensagem em Matrix é similar a email. Nós esquecermos suas mensagens significa que mensagens que você tem enviado não vão ser compartilhadas com nenhum usuária(o) nova(o) ou não-registrada(o), mas usuárias(os) registradas(os) que já têm acesso a estas mensagens vão ainda ter acesso à cópia delas(es)."; +"deactivate_account_forget_messages_information_part1" = "Por favor esqueça todas as mensagens que eu tenho enviado quando minha conta for desativada ("; +"deactivate_account_forget_messages_information_part2_emphasize" = "Aviso"; +"deactivate_account_forget_messages_information_part3" = ": isto vai causar usuárias/os futuras/os terem uma visualização incompleta de conversas)"; +"deactivate_account_validate_action" = "Desativar conta"; +"deactivate_account_password_alert_title" = "Desativar Conta"; +"deactivate_account_password_alert_message" = "Para continuar, por favor entre sua senha"; // Re-request confirmation dialog -"rerequest_keys_alert_title" = "Requisição enviada"; -"rerequest_keys_alert_message" = "Por favor, inicie o Element em outro aparelho que possa descriptografar a mensagem, de modo que ele possa enviar as chaves para esta sessão."; +"rerequest_keys_alert_title" = "Requisição Enviada"; +"rerequest_keys_alert_message" = "Por favor lance Element num outro dispositivo que possa decriptar a mensagem para que ele possa enviar as chaves para esta sessão."; // String for App Store -"store_short_description" = "Conversas e chamadas: seguras e descentralizadas"; -"store_full_description" = "O Element é um novo tipo de aplicativo de comunicação e colaboração que:↵\n↵\n1. Coloca você no controle de sua privacidade;↵\n2. Permite que você se comunique com qualquer pessoa na rede Matrix, e até mais além, integrando-se a aplicativos como o Slack;↵\n3. Protege você de publicidade, mineração de dados, backdoors e ecossistemas fechados;↵\n4. Protege você por meio da criptografia de ponta a ponta, com autoverificação para confirmar outras pessoas.↵\n↵\nO Element é completamente diferente de outros aplicativos de mensagens e colaboração porque é descentralizado e de código aberto.↵\n↵\nO Element permite que você use seu próprio servidor - ou escolha uma alternativa de armazenamento - para ter privacidade, propriedade e controle de seus dados e conversas. Dá acesso a uma rede aberta; para que você não fique falando apenas com outros usuários do Element. E é muito seguro.↵\n↵\nO Element é capaz de fazer tudo isso porque opera na rede Matrix - o padrão para comunicação aberta e descentralizada.↵\n↵\nO Element coloca você no controle, permitindo escolher quem armazena suas conversas. No aplicativo do Element, você pode optar por armazenar de diferentes maneiras:↵\n↵\n1. Obtenha uma conta gratuita no servidor público matrix.org↵\n2. Armazene sua conta automaticamente, executando um servidor em seu próprio hardware↵\n3. Inscreva-se em uma conta para um servidor personalizado, basta se inscrever na plataforma de armazenamento do Element Matrix Services↵\n↵\nPor que escolher o Element?↵\n↵\nPOSSUA SEUS DADOS: você decide onde guardar seus dados e mensagens. Você os possui e controla, e não alguma MEGA CORPORAÇÃO que vende seus dados ou dá acesso a terceiros.↵\n↵\nMENSAGEM ABERTA E COLABORAÇÃO: você pode conversar com qualquer outra pessoa na rede Matrix, esteja ela usando o Element ou outro aplicativo que se conecta na rede Matrix. E mesmo se estiverem usando um sistema de mensagens diferente, como Slack, IRC ou XMPP.↵\n↵\nSUPER SEGURO: criptografia real de ponta a ponta (somente aqueles na conversa podem descriptografar as mensagens) e autoverificação para confirmar os aparelhos dos participantes da conversa.↵\n↵\nCOMUNICAÇÃO COMPLETA: mensagens, chamadas de voz e de vídeo, compartilhamento de arquivos, compartilhamento de tela e um monte de integrações, bots e widgets. Crie salas, comunidades, mantenha contato e faça as coisas acontecerem.↵\n↵\nONDE QUER QUE VOCÊ ESTEJA: mantenha contato onde quer que você esteja, com o histórico de mensagens totalmente sincronizado em todos os seus aparelhos e no navegador de internet em https://element.io/app."; -"auth_login_single_sign_on" = "Entrar"; -"auth_autodiscover_invalid_response" = "Resposta de descoberta inválida no servidor local"; -"room_message_unable_open_link_error_message" = "Não foi possível abrir o link."; -"settings_key_backup" = "BACKUP DA CHAVE"; -"settings_key_backup_info" = "As mensagens criptografadas são protegidas com criptografia de ponta a ponta. Somente você e o(s) destinatário(s) têm as chaves para ler essas mensagens."; -"settings_key_backup_info_checking" = "Verificando…"; -"settings_key_backup_info_none" = "O backup de suas chaves não está sendo feito nesta sessão."; -"settings_key_backup_info_signout_warning" = "Faça backup das chaves desta sessão antes de sair, para evitar a perda de chaves que estejam apenas neste aparelho."; -"settings_key_backup_info_version" = "Versão do backup de chave: %@"; +"store_short_description" = "Chat/VoIP descentralizado e seguro"; +"store_full_description" = "Element is um novo tipo de mensageiro e app de colaboração que:\n\n1. Põe você em controle para preservar sua privacidade\n2. Permite você se comunicar com qualquer pessoa na rede Matrix, e até além ao integrar-se com apps como Slack\n3. Protege você de publicidade, datamining, backdoors e jardins murados\n4. Assegura você através de encriptação ponta-a-pontam com assinatura cruzada para verificar ouras(os)\n\nElement é completamente diferente de outros apps de mensageria e colaboração porque ele é descentralizado e open source.\n\nElement permite você auto-hospedar - ou escolher um host - para que você tenha privacidade, propriedade e controle de seus dados e conversas. Ele dá a você acesso a uma rede aberta; então você não está simplesmente preso falando com outras(os) usuárias(os) Element somente. E ele é muito seguro.\n\nElement é capaz de fazer tudo isso porque ele opera em Matrix - o padrão para comunicação aberta e descentralizada.\n\nElement põe você em controle ao permitir você escolher quem hospeda suas conversas. De seu app Element, você pode escolher hospedar de diferentes maneiras:\n\n1. Pegar uma conta grátis no servidor público matrix.org\n2. Auto-hospedar sua conta ao rodar um servidor em seu próprio hardware\n3. Registrar-se para uma conta num servidor personalizado ao simplesmente assinar a plataforma de hospedagem Element Matrix Services\n\nPorquê escolher Element?\n\nTENHA POSSE DE SEUS DADOS: Você decide onde manter seus dados e mensagens. Você os possui e controla, não alguma MEGACORP que mina seus dados ou dá acesso a terceiros.\n\nMENSAGERIA E COLABORAÇÃO ABERTOS: Você pode fazer chat com qualquer outra pessoa na rede Matrix, caso ela esteja usando Element ou um outro app Matrix, e mesmo se ela estiver usando um sistema de mensageria diferente, do tipo de Slack, IRC ou XMPP.\n\nSUPER-SEGURO: Encriptação ponta-a-ponta real (somente aquelas/es na conversa podem decriptar mensagens), e assinatura cruzada para verificar os dispositivos de participantes de conversa.\n\nCOMUNICAÇÃO COMPLETA: Mensageria, chamadas de voz e vídeo, compartilhamento de arquivo, compartilhamento de tela e um monte de integrações, bots e widgets. Construa salas, comunidades, fique em contato e tenha as coisas feitas.\n\nEM TODO LUGAR ONDE VOCÊ ESTEJA: Fique em contato onde quer que você esteja com histórico de mensagem sincronizado por todos os dispositivos e na web em https://element.io/app."; +"auth_login_single_sign_on" = "Fazer Sign In"; +"auth_autodiscover_invalid_response" = "Resposta de descoberta de servidorcasa inválida"; +"room_message_unable_open_link_error_message" = "Incapaz de abrir o link."; +"settings_key_backup" = "BACKUP DE CHAVE"; +"settings_key_backup_info" = "Mensagens encriptadas são asseguradas com encriptação ponta-a-ponta. Somente você e a(s)/o(s) recipiente(s) têm as chaves para ler estas mensagens."; +"settings_key_backup_info_checking" = "Checando…"; +"settings_key_backup_info_none" = "Backup de suas chaves não está sendo feito desta sessão."; +"settings_key_backup_info_signout_warning" = "Faça backup de suas chaves antes de fazer signout para evitar perdê-las."; +"settings_key_backup_info_version" = "Versão de Backup de Chave: %@"; "settings_key_backup_info_algorithm" = "Algoritmo: %@"; "settings_key_backup_info_valid" = "Esta sessão está fazendo backup de suas chaves."; -"settings_key_backup_info_not_valid" = "Esta sessão não está fazendo backup de suas chaves, mas você já possui um backup existente, o qual poderá restaurar e atualizar no futuro."; -"settings_key_backup_info_progress" = "Fazendo o backup das chaves %@…"; -"settings_key_backup_info_progress_done" = "O Backup de todas as chaves foi realizado"; -"settings_key_backup_info_trust_signature_unknown" = "O backup tem uma assinatura da sessão com o ID: %@"; -"settings_key_backup_info_trust_signature_valid" = "O backup tem uma assinatura válida desta sessão"; -"settings_key_backup_info_trust_signature_valid_device_verified" = "O backup tem uma assinatura válida de %@"; -"settings_key_backup_info_trust_signature_valid_device_unverified" = "O backup tem uma assinatura de %@"; -"settings_key_backup_info_trust_signature_invalid_device_verified" = "O backup tem uma assinatura inválida de %@"; -"settings_key_backup_info_trust_signature_invalid_device_unverified" = "O backup tem uma assinatura inválida de %@"; -"settings_key_backup_button_create" = "Comece a fazer o Backup de chave"; -"settings_key_backup_button_restore" = "Restaurar do backup"; -"settings_key_backup_button_delete" = "Remover backup"; +"settings_key_backup_info_not_valid" = "Esta sessão não está fazendo backup de suas chaves, mas você tem sim um backup existente de onde você pode restaurar e para onde você pode adicionar daqui em diante."; +"settings_key_backup_info_progress" = "Fazendo backup de %@ chaves…"; +"settings_key_backup_info_progress_done" = "Backup de todas as chaves foi feito"; +"settings_key_backup_info_trust_signature_unknown" = "Backup tem uma assinatura de sessão com ID: %@"; +"settings_key_backup_info_trust_signature_valid" = "Backup tem uma assinatura válida desta sessão"; +"settings_key_backup_info_trust_signature_valid_device_verified" = "Backup tem uma assinatura válida de %@"; +"settings_key_backup_info_trust_signature_valid_device_unverified" = "Backup tem uma assinatura de %@"; +"settings_key_backup_info_trust_signature_invalid_device_verified" = "Backup tem uma assinatura inválida de %@"; +"settings_key_backup_info_trust_signature_invalid_device_unverified" = "Backup tem uma assinatura inválida de %@"; +"settings_key_backup_button_create" = "Começar a usar Backup de Chave"; +"settings_key_backup_button_restore" = "Restaurar de Backup"; +"settings_key_backup_button_delete" = "Deletar Backup"; "settings_key_backup_button_use" = "Usar Backup da chave"; -"settings_key_backup_delete_confirmation_prompt_title" = "Remover backup"; -"settings_key_backup_delete_confirmation_prompt_msg" = "Tem certeza? Você perderá suas mensagens criptografadas se não tiver feito corretamente o backup de suas chaves."; +"settings_key_backup_delete_confirmation_prompt_title" = "Deletar Backup"; +"settings_key_backup_delete_confirmation_prompt_msg" = "Você tem certeza? Você vai perder suas mensagens encriptadas se o backup de suas chaves não tiver sido feito apropriadamente."; "room_does_not_exist" = "%@ não existe"; // Key backup wrong version -"e2e_key_backup_wrong_version_title" = "Novo backup de chave"; -"e2e_key_backup_wrong_version" = "Um novo backup de chave foi detectado.\n\nSe não foi você, defina uma nova frase secreta em Configurações."; +"e2e_key_backup_wrong_version_title" = "Novo Backup de Chave"; +"e2e_key_backup_wrong_version" = "Um novo backup de chave de mensagem segura tem sido detectado.\n\nSe isto não foi você, defina uma nova Frase de Segurança em Configurações."; "e2e_key_backup_wrong_version_button_settings" = "Configurações"; "e2e_key_backup_wrong_version_button_wasme" = "Foi eu"; -"key_backup_setup_title" = "Backup de chave"; +"key_backup_setup_title" = "Backup de Chave"; "key_backup_setup_skip_alert_title" = "Você tem certeza?"; -"key_backup_setup_skip_alert_message" = "Você pode perder mensagens seguras se sair dessa sessão ou perder o seu aparelho."; +"key_backup_setup_skip_alert_message" = "Você pode perder mensagens seguras se você fizer logout ou perder seu dispositivo."; "key_backup_setup_skip_alert_skip_action" = "Pular"; -"key_backup_setup_intro_title" = "Nunca perca mensagens criptografadas"; -"key_backup_setup_intro_info" = "As mensagens em salas criptografadas são protegidas com criptografia de ponta a ponta. Somente você e o(s) destinatário(s) têm as chaves para ler essas mensagens.\n\nFaça backup de suas chaves com segurança para evitar perdê-las."; -"key_backup_setup_intro_setup_action_without_existing_backup" = "Comece a usar o Backup de chave"; +"key_backup_setup_intro_title" = "Nunca perca mensagens encriptadas"; +"key_backup_setup_intro_info" = "Mensagens em salas encriptadas são asseguradas com encriptação ponta-a-ponta. Somente você e a(s)/o(s) recipiente(s) têm as chaves para ler estas mensagens.\n\nFaça seguramente backup de suas chaves para evitar perdê-las."; +"key_backup_setup_intro_setup_action_without_existing_backup" = "Começar a usar Backup de Chave"; "key_backup_setup_intro_setup_action_with_existing_backup" = "Usar Backup de Chave"; -"key_backup_setup_intro_manual_export_info" = "(Avançado)"; -"key_backup_setup_intro_manual_export_action" = "Exportar as chaves manualmente"; -"key_backup_setup_passphrase_title" = "Proteja seu backup com uma frase secreta"; -"key_backup_setup_passphrase_info" = "Nós vamos armazenar uma cópia criptografada de suas chaves em nosso servidor. Proteja seu backup com uma frase secreta para mantê-lo seguro.\n\nPara segurança máxima, a frase secreta deve ser diferente da senha da sua conta."; +"key_backup_setup_intro_manual_export_info" = "(Avançada)"; +"key_backup_setup_intro_manual_export_action" = "Exportar chaves manualmente"; +"key_backup_setup_passphrase_title" = "Assegure seu backup com uma Frase de Segurança"; +"key_backup_setup_passphrase_info" = "Nós vamos armazenar uma cópia encriptada de suas chaves em nosso servidor. Proteja seu backup com uma frase para mantê-lo seguro.\n\nPara segurança máxima, esta deveria ser diferente da senha de sua conta."; "key_backup_setup_passphrase_passphrase_title" = "Entrar"; -"key_backup_setup_passphrase_passphrase_placeholder" = "Digite a senha"; +"key_backup_setup_passphrase_passphrase_placeholder" = "Entrar frase"; "key_backup_setup_passphrase_passphrase_valid" = "Ótimo!"; "key_backup_setup_passphrase_passphrase_invalid" = "Tente adicionar uma palavra"; -"key_backup_setup_passphrase_confirm_passphrase_title" = "Confirme"; -"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "Confirme a senha"; +"key_backup_setup_passphrase_confirm_passphrase_title" = "Confirmar"; +"key_backup_setup_passphrase_confirm_passphrase_placeholder" = "Confirmar frase"; "key_backup_setup_passphrase_confirm_passphrase_valid" = "Ótimo!"; -"key_backup_setup_passphrase_confirm_passphrase_invalid" = "As senhas não conferem"; -"key_backup_setup_passphrase_set_passphrase_action" = "Definir a frase secreta"; -"key_backup_setup_passphrase_setup_recovery_key_info" = "Ou, proteja seu backup com uma chave de recuperação, salvando-a em algum lugar seguro."; -"key_backup_setup_passphrase_setup_recovery_key_action" = "(Avançado) Configurar com chave de recuperação"; -"key_backup_setup_success_title" = "Pronto!"; +"key_backup_setup_passphrase_confirm_passphrase_invalid" = "Frase não corresponde"; +"key_backup_setup_passphrase_set_passphrase_action" = "Definir Frase"; +"key_backup_setup_passphrase_setup_recovery_key_info" = "Ou, assegure seu backup com uma Chave de Segurança, salvando-a em algum lugar seguro."; +"key_backup_setup_passphrase_setup_recovery_key_action" = "(Avançada) Configurar com Chave de Segurança"; +"key_backup_setup_success_title" = "Sucesso!"; // Success from passphrase -"key_backup_setup_success_from_passphrase_info" = "Suas chaves estão sendo copiadas.\n\nSua chave de recuperação é uma rede de segurança - você pode usá-la para restaurar o acesso às suas mensagens criptografadas se esquecer sua frase secreta.\n\nMantenha sua chave de recuperação em algum lugar muito seguro, como um gerenciador de senhas (ou um cofre)."; -"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Salvar chave de recuperação"; -"key_backup_setup_success_from_passphrase_done_action" = "Fechar"; +"key_backup_setup_success_from_passphrase_info" = "Backup de suas chaves está sendo feito.\n\nSua Chave de Segurança é uma rede de segurança - você pode usá-la para restaurar acesso a suas mensagens encriptadas se você esquecer sua frasepasse.\n\nMantenha sua Chave de Segurança em algum lugar muito seguro, como um gerenciador de senhas (ou um cofre)."; +"key_backup_setup_success_from_passphrase_save_recovery_key_action" = "Salvar Chave de Segurança"; +"key_backup_setup_success_from_passphrase_done_action" = "Feito"; // Success from recovery key -"key_backup_setup_success_from_recovery_key_info" = "Suas chaves estão sendo copiadas.\n\nFaça uma cópia dessa chave de recuperação e mantenha-a segura."; -"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Chave de recuperação"; -"key_backup_setup_success_from_recovery_key_make_copy_action" = "Fazer uma cópia"; -"key_backup_setup_success_from_recovery_key_made_copy_action" = "Eu já fiz uma cópia"; -"key_backup_recover_title" = "Mensagens seguras"; -"key_backup_recover_invalid_passphrase_title" = "Senha de recuperação incorreta"; -"key_backup_recover_invalid_passphrase" = "O backup não pôde ser descriptografado com essa frase secreta: verifique se você digitou corretamente a frase secreta de recuperação."; -"key_backup_recover_invalid_recovery_key_title" = "Chave de recuperação incorreta"; -"key_backup_recover_invalid_recovery_key" = "O backup não pôde ser descriptografado com essa chave: verifique se você inseriu corretamente a chave de recuperação."; -"key_backup_recover_from_passphrase_info" = "Use sua frase secreta de recuperação para desbloquear seu histórico de mensagens seguras"; +"key_backup_setup_success_from_recovery_key_info" = "Backup de suas chaves está sendo feito.\n\nFaça uma cópia desta Chave de Segurança e mantenha-a segura."; +"key_backup_setup_success_from_recovery_key_recovery_key_title" = "Chave de Segurança"; +"key_backup_setup_success_from_recovery_key_make_copy_action" = "Fazer uma Cópia"; +"key_backup_setup_success_from_recovery_key_made_copy_action" = "Eu tenho feito uma cópia"; +"key_backup_recover_title" = "Mensagens Seguras"; +"key_backup_recover_invalid_passphrase_title" = "Frase de Segurança Incorreta"; +"key_backup_recover_invalid_passphrase" = "Backup não pôde ser decriptado com esta frase: por favor verifique que você entrou a Frase de Segurança correta."; +"key_backup_recover_invalid_recovery_key_title" = "Disparidade de Chave de Segurança"; +"key_backup_recover_invalid_recovery_key" = "Backup não pôde ser decriptografado com esta chave: por favor verifique que você entrou a Chave de Segurança correta."; +"key_backup_recover_from_passphrase_info" = "Use sua Frase de Segurança para destrancar seu histórico de mensagens seguras"; "key_backup_recover_from_passphrase_passphrase_title" = "Entrar"; -"key_backup_recover_from_passphrase_passphrase_placeholder" = "Digite a frase secreta"; -"key_backup_recover_from_passphrase_recover_action" = "Desbloquear Histórico"; -"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Não sabe sua senha de recuperação? Você pode "; -"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "use sua chave de recuperação"; +"key_backup_recover_from_passphrase_passphrase_placeholder" = "Entrar Frase"; +"key_backup_recover_from_passphrase_recover_action" = "Destrancar Histórico"; +"key_backup_recover_from_passphrase_lost_passphrase_action_part1" = "Não sabe sua Frase de Segurança? Você pode "; +"key_backup_recover_from_passphrase_lost_passphrase_action_part2" = "usar sua Chave de Segurança"; "key_backup_recover_from_passphrase_lost_passphrase_action_part3" = "."; -"key_backup_recover_from_recovery_key_info" = "Use sua chave de recuperação para desbloquear o seu histórico de mensagens seguras"; +"key_backup_recover_from_recovery_key_info" = "Use sua Chave de Segurança para destrancar seu histórico de mensagens seguras"; "key_backup_recover_from_recovery_key_recovery_key_title" = "Entrar"; -"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Digite a chave de recuperação"; -"key_backup_recover_from_recovery_key_recover_action" = "Desbloquear Histórico"; -"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Perdeu sua chave de recuperação? Você pode configurar uma nova nas configurações."; -"key_backup_recover_success_info" = "Backup restaurado!"; -"key_backup_recover_done_action" = "Fechar"; +"key_backup_recover_from_recovery_key_recovery_key_placeholder" = "Entrar Chave de Segurança"; +"key_backup_recover_from_recovery_key_recover_action" = "Destrancar Histórico"; +"key_backup_recover_from_recovery_key_lost_recovery_key_action" = "Perdeu sua Chave de Segurança? Você pode configurar uma nova em configurações."; +"key_backup_recover_success_info" = "Backup Restaurado!"; +"key_backup_recover_done_action" = "Feito"; "key_backup_setup_banner_title" = "Nunca perca mensagens criptografadas"; "key_backup_setup_banner_subtitle" = "Comece a usar o Backup de chave"; "key_backup_recover_banner_title" = "Nunca perca mensagens criptografadas"; "key_backup_recover_banner_subtitle" = "Use o backup de chave"; -"sign_out_existing_key_backup_alert_title" = "Deseja mesmo sair?"; -"sign_out_existing_key_backup_alert_sign_out_action" = "Sair"; -"sign_out_non_existing_key_backup_alert_title" = "Você perderá o acesso às suas mensagens criptografadas se sair agora"; +"sign_out_existing_key_backup_alert_title" = "Você tem certeza que você quer fazer signout?"; +"sign_out_existing_key_backup_alert_sign_out_action" = "Fazer signout"; +"sign_out_non_existing_key_backup_alert_title" = "Você vai perder acesso a suas mensagens encriptadas se fizer signout agora"; "sign_out_non_existing_key_backup_alert_setup_key_backup_action" = "Comece a usar o Backup de chave"; -"sign_out_non_existing_key_backup_alert_discard_key_backup_action" = "Eu não quero minhas mensagens criptografadas"; -"sign_out_non_existing_key_backup_sign_out_confirmation_alert_title" = "Você perderá suas mensagens criptografadas"; -"sign_out_non_existing_key_backup_sign_out_confirmation_alert_message" = "Você perderá o acesso às suas mensagens criptografadas, a menos que faça o backup das suas chaves antes de sair."; -"sign_out_non_existing_key_backup_sign_out_confirmation_alert_sign_out_action" = "Sair"; +"sign_out_non_existing_key_backup_alert_discard_key_backup_action" = "Eu não quero minhas mensagens encriptadas"; +"sign_out_non_existing_key_backup_sign_out_confirmation_alert_title" = "Você vai perder suas mensagens encriptadas"; +"sign_out_non_existing_key_backup_sign_out_confirmation_alert_message" = "Você vai perder acesso a suas mensagens encriptadas a menos que faça backup de suas chaves antes de fazer signout."; +"sign_out_non_existing_key_backup_sign_out_confirmation_alert_sign_out_action" = "Fazer signout"; "sign_out_non_existing_key_backup_sign_out_confirmation_alert_backup_action" = "Backup"; -"sign_out_key_backup_in_progress_alert_title" = "Backup de chave em andamento. Se você sair agora, perderá o acesso às suas mensagens criptografadas."; -"sign_out_key_backup_in_progress_alert_discard_key_backup_action" = "Eu não quero minhas mensagens criptografadas"; -"sign_out_key_backup_in_progress_alert_cancel_action" = "Eu esperarei"; -"store_promotional_text" = "Aplicativo de bate-papo e colaboração que preserva a privacidade, em uma rede aberta. Descentralizado para colocar você no controle. Sem datamining, sem backdoors e sem acesso de terceiros."; +"sign_out_key_backup_in_progress_alert_title" = "Backup de chave em progresso. Se você fizer signout agora você vai perder acesso a suas mensagens encriptadas."; +"sign_out_key_backup_in_progress_alert_discard_key_backup_action" = "Eu não quero minhas mensagens encriptadas"; +"sign_out_key_backup_in_progress_alert_cancel_action" = "Eu vou esperar"; +"store_promotional_text" = "App de chat e colaboração que preserva privacidade, em uma rede aberta. Descentralizado para pôr você em controle. Sem datamining, sem backdoors e sem acesso de terceiros."; "close" = "Fechar"; "skip" = "Pular"; -"auth_add_email_message_2" = "Defina um e-mail para servir para a recuperação da conta e, posteriormente, para ser opcionalmente detectável por pessoas que a/o conhecem."; -"auth_softlogout_reason" = "O administrador do seu servidor local (%1$@) desconectou você da sua conta %2$@ (%3$@)."; +"auth_add_email_message_2" = "Defina um email para recuperação de conta, e depois para ser opcionalmente descobertável por pessoas que conhecem você."; +"auth_softlogout_reason" = "A/o admin de seu servidorcasa (%1$@) tem feito seu signout de sua conta %2$@ (%3$@)."; // Errors -"error_user_already_logged_in" = "Parece que você está tentando se conectar a outro servidor local. Deseja sair?"; -"settings_calls_stun_server_fallback_description" = "Permitir a assistência do servidor de chamadas reserva %@ quando seu servidor não oferecer este serviço (seu endereço IP será transmitido quando você ligar)."; -"security_settings_blacklist_unverified_devices" = "Nunca envie mensagens para sessões não confiáveis"; -"security_settings_blacklist_unverified_devices_description" = "Verifique todas as sessões de um usuário para marcá-las como confirmadas e enviar mensagens para eles."; -"security_settings_user_password_description" = "Confirme sua identidade digitando a senha da sua conta"; +"error_user_already_logged_in" = "Parece que você está tentando se conectar a um outro servidorcasa. Você quer fazer signout?"; +"settings_calls_stun_server_fallback_description" = "Permitir servidor fallback de assistência de chamadas %@ quando seu servidorcasa não oferece um (seu endereço de IP seria compartilhado durante uma chamada)."; +"security_settings_blacklist_unverified_devices" = "Nunca enviar mensagens para sessões não-confiadas"; +"security_settings_blacklist_unverified_devices_description" = "Verificar todas as sessões de um/uma usuário(a) para marcá-las como confiadas e enviar mensagens para ele/ela."; +"security_settings_user_password_description" = "Confirme sua identidade ao entrar a senha de sua conta"; // Manage session "manage_session_title" = "Gerenciar sessão"; -"manage_session_name" = "Nome da sessão"; +"manage_session_name" = "Nome de sessão"; // AuthenticatedSessionViewControllerFactory -"authenticated_session_flow_not_supported" = "Este aplicativo não suporta o mecanismo de autenticação em seu servidor local."; -"call_no_stun_server_error_message_1" = "Peça ao administrador do seu servidor local %@ para configurar um servidor TURN, de modo que as chamadas funcionem de maneira confiável."; -"secure_key_backup_setup_existing_backup_error_unlock_it" = "Desbloqueá-lo"; -"secure_key_backup_setup_existing_backup_error_delete_it" = "Apagá-lo"; +"authenticated_session_flow_not_supported" = "Este app não suporta o mecanismo de autenticação em seu servidorcasa."; +"call_no_stun_server_error_message_1" = "Por favor peça ao/à administrador(a) de seu servidorcasa %@ para configurar um servidor TURN a fim que chamadas funcionem confiavelmente."; +"secure_key_backup_setup_existing_backup_error_unlock_it" = "Destrancá-lo"; +"secure_key_backup_setup_existing_backup_error_delete_it" = "Deletá-lo"; "secure_key_backup_setup_cancel_alert_title" = "Você tem certeza?"; -"secure_key_backup_setup_cancel_alert_message" = "Se você cancelar agora, poderá perder mensagens e dados criptografados, se perder o acesso aos seus logins.\n\nVocê também pode configurar o Backup online e configurar suas chaves em Configurações."; -"secure_backup_setup_banner_title" = "Backup online"; -"secure_backup_setup_banner_subtitle" = "Proteja-se contra a perda de acesso a mensagens e dados criptografados"; +"secure_key_backup_setup_cancel_alert_message" = "Se você cancelar agora, você pode perder mensagens & dados encriptados se você perder acesso a seus logins.\n\nVocê também pode configurar Backup Seguro & gerenciar suas chaves em Configurações."; +"secure_backup_setup_banner_title" = "Backup Seguro"; +"secure_backup_setup_banner_subtitle" = "Salvaguardar-se contra perda de acesso a mensagens & dados encriptados"; // Recover from private key -"key_backup_recover_from_private_key_info" = "Restaurando o backup…"; -"sign_out_non_existing_key_backup_alert_setup_secure_backup_action" = "Comece a usar o backup online"; +"key_backup_recover_from_private_key_info" = "Restaurando backup…"; +"sign_out_non_existing_key_backup_alert_setup_secure_backup_action" = "Começar a usar Backup Seguro"; // MARK: - Device Verification -"key_verification_other_session_title" = "Confirmar a sessão"; -"key_verification_new_session_title" = "Confirme sua nova sessão"; -"key_verification_this_session_title" = "Confirme esta sessão"; -"key_verification_user_title" = "Confirme-os"; -"device_verification_security_advice_number" = "Compare os números, garantindo que eles apareçam na mesma ordem."; -"device_verification_cancelled_by_me" = "A confirmação foi cancelada. Motivo: %@"; -"device_verification_error_cannot_load_device" = "Não foi possível carregar as informações da sessão."; -"major_update_information" = "Estamos felizes em anunciar que mudamos de nome! Seu aplicativo está atualizado e você está conectado à sua conta."; -"room_action_camera" = "Tirar uma foto ou gravar vídeo"; -"room_accessibility_call" = "Chamada de voz"; +"key_verification_other_session_title" = "Verificar sessão"; +"key_verification_new_session_title" = "Verificar sua nova sessão"; +"key_verification_this_session_title" = "Verificar esta sessão"; +"key_verification_user_title" = "Verificá-la(o)"; +"device_verification_security_advice_number" = "Compare os números, garantindo que eles aparecem na mesma ordem."; +"device_verification_cancelled_by_me" = "A verificação tem sido cancelada. Razão: %@"; +"device_verification_error_cannot_load_device" = "Não dá para carregar informação de sessão."; +"major_update_information" = "Nós estamos animados em anunciar que nós temos mudado de nome! Seu app está atualizado e você está com signin feito a sua conta."; +"room_action_camera" = "Tirar foto ou vídeo"; +"room_accessibility_call" = "Chamar"; "media_type_accessibility_video" = "Vídeo"; -"event_formatter_jitsi_widget_added_by_you" = "Você adicionou chamada em grupo"; -"event_formatter_jitsi_widget_removed_by_you" = "Você removeu chamada em grupo"; -"room_widget_permission_avatar_url_permission" = "Link da sua foto de perfil"; +"event_formatter_jitsi_widget_added_by_you" = "Você adicionou conferência de VoIP"; +"event_formatter_jitsi_widget_removed_by_you" = "Você removeu conferência de VoIP"; +"room_widget_permission_avatar_url_permission" = "URL de seu avatar"; "device_verification_emoji_banana" = "Banana"; "room_participants_action_security_status_loading" = "Carregando…"; "room_participants_security_loading" = "Carregando…"; -"room_participants_security_information_room_not_encrypted" = "As mensagens nesta sala não estão criptografadas de ponta a ponta."; -"room_member_power_level_admin_in" = "Administrador em %@"; -"room_member_power_level_moderator_in" = "Moderador em %@"; -"room_member_power_level_short_admin" = "Administrador"; -"room_member_power_level_short_moderator" = "Moderador"; +"room_participants_security_information_room_not_encrypted" = "Mensagens nesta sala não são encriptadas ponta-a-ponta."; +"room_member_power_level_admin_in" = "Admin em %@"; +"room_member_power_level_moderator_in" = "Moderador(a) em %@"; +"room_member_power_level_short_admin" = "Admin"; +"room_member_power_level_short_moderator" = "Mod"; "room_event_action_reply" = "Responder"; "room_event_action_edit" = "Editar"; -"room_event_action_reaction_show_all" = "Mostrar tudo"; +"room_event_action_reaction_show_all" = "Mostrar todas"; "room_action_send_file" = "Enviar arquivo"; "room_action_reply" = "Responder"; -"room_accessibility_search" = "Buscar"; +"room_accessibility_search" = "Pesquisar"; "room_accessibility_integrations" = "Integrações"; "media_type_accessibility_audio" = "Áudio"; "media_type_accessibility_file" = "Arquivo"; -"media_type_accessibility_sticker" = "Figurinha"; +"media_type_accessibility_sticker" = "Sticker"; "settings_integrations" = "INTEGRAÇÕES"; "settings_three_pids_management_information_part3" = "."; "settings_security" = "SEGURANÇA"; "settings_integrations_allow_button" = "Gerenciar integrações"; -"settings_integrations_allow_description" = "Use o Gerenciador de Integrações (%@) para gerenciar bots, integrações, widgets e pacotes de figurinhas.\n\nO Gerenciador de Integrações recebe dados de configuração e pode modificar widgets, enviar convites para salas e definir níveis de permissão em seu nome."; -"settings_add_3pid_password_title_email" = "Adicionar endereço de e-mail"; -"settings_discovery_three_pids_management_information_part2" = "Configurações do usuário"; +"settings_integrations_allow_description" = "Use um Gerenciador de Integração (%@) para gerenciar bots, bridges, widgets e pacotes de stickers.\n\nGerenciadores de Integração recebem dados de configuração, e podem modificar widgets, enviar convites de sala e definir níveis de poder em seu nome."; +"settings_add_3pid_password_title_email" = "Adicionar endereço de email"; +"settings_discovery_three_pids_management_information_part2" = "Configurações de Usuária(o)"; "settings_discovery_three_pids_management_information_part3" = "."; "settings_discovery_three_pid_details_share_action" = "Compartilhar"; "settings_discovery_three_pid_details_revoke_action" = "Revogar"; -"service_terms_modal_description_for_integration_manager" = "Use bots, integrações, widgets e pacotes de figurinhas"; -"device_verification_cancelled" = "Seu contato cancelou a confirmação."; +"service_terms_modal_description_for_integration_manager" = "Usar Bots, bridges, widgets e pacotes de stickers"; +"device_verification_cancelled" = "A outra parte cancelou a verificação."; // Mark: Incoming -"device_verification_incoming_title" = "Recebendo solicitação de confirmação"; -"device_verification_start_wait_partner" = "Aguardando seu contato aceitar…"; -"device_verification_self_verify_start_waiting" = "Aguardando…"; -"device_verification_verify_wait_partner" = "Aguardando seu contato confirmar…"; -"key_verification_tile_request_status_waiting" = "Aguardando…"; +"device_verification_incoming_title" = "Requisição de Verificação Recebendo"; +"device_verification_start_wait_partner" = "Esperando por parceira(o) aceitar…"; +"device_verification_self_verify_start_waiting" = "Esperando…"; +"device_verification_verify_wait_partner" = "Esperando por parceira(o) confirmar…"; +"key_verification_tile_request_status_waiting" = "Esperando…"; // Scanning -"key_verification_scan_confirmation_scanning_title" = "Quase lá! Aguardando a confirmação…"; -"key_verification_scan_confirmation_scanning_user_waiting_other" = "Aguardando %@…"; -"key_verification_scan_confirmation_scanning_device_waiting_other" = "Aguardando o outro aparelho…"; -"user_verification_start_waiting_partner" = "Aguardando %@…"; -"settings_devices_description" = "O nome público de uma sessão é visível para as pessoas com quem você se comunica"; -"security_settings_crypto_sessions_description_2" = "Se você não reconhecer um login, altere sua senha e refaça o backup online."; -"security_settings_export_keys_manually" = "Exportar as chaves manualmente"; -"identity_server_settings_change" = "Alterar"; -"identity_server_settings_alert_change_title" = "Alterar o servidor de identidade"; +"key_verification_scan_confirmation_scanning_title" = "Quase lá! Esperando por confirmação…"; +"key_verification_scan_confirmation_scanning_user_waiting_other" = "Esperando por %@…"; +"key_verification_scan_confirmation_scanning_device_waiting_other" = "Esperando por outro dispositivo…"; +"user_verification_start_waiting_partner" = "Esperando por %@…"; +"settings_devices_description" = "O nome público de uma sessão é visível para pessoas com quem você se comunica"; +"security_settings_crypto_sessions_description_2" = "Se você não reconhece um login, mude sua senha e resette Backup Seguro."; +"security_settings_export_keys_manually" = "Exportar chaves manualmente"; +"identity_server_settings_change" = "Mudar"; +"identity_server_settings_alert_change_title" = "Mudar servidor de identidade"; // Media picker -"media_picker_title" = "Galeria"; -"image_picker_action_library" = "Escolher da galeria"; -"photo_library_access_not_granted" = "%@ não tem permissão para acessar a galeria de fotos, altere as configurações de privacidade"; -"room_widget_permission_display_name_permission" = "Seu nome e sobrenome"; -"device_verification_security_advice_emoji" = "Compare os emojis únicos, garantindo que eles aparecem na mesma ordem."; -"device_verification_self_verify_alert_message" = "Verifique o novo login na sua conta: %@"; -"key_verification_verify_sas_title_emoji" = "Compare os emojis"; -"key_verification_manually_verify_device_title" = "Confirme manualmente por texto"; +"media_picker_title" = "Biblioteca de mídia"; +"image_picker_action_library" = "Escolher de biblioteca"; +"photo_library_access_not_granted" = "%@ não tem permissão para acessar biblioteca de fotos, por favor mude configurações de privacidade"; +"room_widget_permission_display_name_permission" = "Seu nome de exibição"; +"device_verification_security_advice_emoji" = "Compare os emoji únicos, garantindo que eles aparecem na mesma ordem."; +"device_verification_self_verify_alert_message" = "Verifique o novo login acessando sua conta: %@"; +"key_verification_verify_sas_title_emoji" = "Comparar emoji"; +"key_verification_manually_verify_device_title" = "Verificar Manualmente por Texto"; "device_verification_emoji_scissors" = "Tesoura"; "device_verification_emoji_guitar" = "Guitarra"; -"emoji_picker_people_category" = "Sorrisos e pessoas"; -"emoji_picker_nature_category" = "Animais e natureza"; -"emoji_picker_foods_category" = "Comidas e bebidas"; +"emoji_picker_people_category" = "Smileys & Pessoas"; +"emoji_picker_nature_category" = "Animais & Natureza"; +"emoji_picker_foods_category" = "Comida & Bebida"; "emoji_picker_activity_category" = "Atividades"; -"emoji_picker_places_category" = "Viagem e lugares"; +"emoji_picker_places_category" = "Viagem & Lugares"; "emoji_picker_objects_category" = "Objetos"; "emoji_picker_symbols_category" = "Símbolos"; "emoji_picker_flags_category" = "Bandeiras"; -"key_verification_verify_qr_code_scan_code_action" = "Escanear o código do seu contato"; +"key_verification_verify_qr_code_scan_code_action" = "Scannar código dela(e)"; // Scanned "key_verification_scan_confirmation_scanned_title" = "Quase lá!"; -"user_verification_session_details_additional_information_untrusted_other_user" = "Até que este usuário confirme esta sessão, as mensagens enviadas para e a partir dela são rotuladas com alertas. Como alternativa, você pode confirmá-la manualmente."; -"user_verification_session_details_verify_action_current_user" = "Confirmem interativamente"; -"user_verification_session_details_verify_action_current_user_manually" = "Confirme manualmente por texto"; -"user_verification_session_details_verify_action_other_user" = "Confirmar manualmente"; -"auth_add_email_phone_message_2" = "Defina um e-mail para recuperação da conta. Posteriormente, você pode permitir que as pessoas encontrem você através dele, ou através do número de telefone."; -"auth_email_is_required" = "Nenhum servidor de identidade está configurado, portanto você não pode adicionar um endereço de e-mail para redefinir sua senha no futuro."; -"auth_softlogout_clear_data_message_1" = "Atenção: seus dados pessoais (incluindo chaves de criptografia) ainda estão armazenados neste aparelho."; -"auth_softlogout_clear_data_sign_out" = "Sair"; -"room_creation_error_invite_user_by_email_without_identity_server" = "Nenhum servidor de identidade está configurado, portanto você não pode adicionar participantes com um e-mail."; -"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "Nenhum servidor de identidade está configurado, portanto você não pode iniciar uma conversa com um contato usando um e-mail."; -"room_participants_action_security_status_warning" = "Atenção"; -"settings_three_pids_management_information_part1" = "Gerencie quais endereços de e-mail ou números de telefone você pode usar para fazer login ou recuperar sua conta aqui. Controle quem pode encontrar você em· "; -"settings_calls_stun_server_fallback_button" = "Permitir a assistência do servidor de chamadas reserva"; -"settings_discovery_terms_not_signed" = "Concorde com os Termos de Serviço do servidor de identidade (%@), para que você possa ser descoberto por endereço de e-mail ou por número de telefone."; -"settings_discovery_three_pids_management_information_part1" = "Gerencie quais endereços de e-mail ou números de telefone outros usuários podem usar para descobrir sua conta e enviar um convite para salas. Adicione ou remova endereços de e-mail ou números de telefone desta lista em· "; -"settings_discovery_three_pid_details_title_email" = "Gerenciar e-mail"; -"settings_discovery_three_pid_details_information_email" = "Configure este endereço de e-mail, que outros usuários podem usar para descobrir sua conta e enviar um convite para salas. Adicione ou remova endereços de e-mail em Contas."; -"settings_discovery_three_pid_details_cancel_email_validation_action" = "Cancelar a validação de e-mail"; -"security_settings_crosssigning" = "AUTOVERIFICAÇÃO"; -"security_settings_crosssigning_info_not_bootstrapped" = "A autoverificação ainda não está ativada."; -"security_settings_crosssigning_info_exists" = "A sua conta tem uma identidade autoverificada em armazenamento secreto, mas ainda não é considerada confiável por esta sessão. Conclua as etapas de segurança desta sessão."; -"security_settings_crosssigning_info_trusted" = "A autoverificação está ativada. Você pode confiar em outros usuários e em suas outras sessões com base na autoverificação deles, mas você não pode fazer a autoverificação nesta sessão porque ela não possui as suas chaves privadas da autoverificação. Complete as etapas de segurança desta sessão."; -"security_settings_crosssigning_info_ok" = "A autoverificação está ativada."; -"security_settings_crosssigning_bootstrap" = "Fazer a autoverificação"; -"security_settings_crosssigning_reset" = "Refazer a autoverificação"; -"identity_server_settings_disconnect_info" = "Desconectar-se do servidor de identidade significa que você não poderá ser descoberto por outros usuários e não poderá convidar outras pessoas por e-mail ou número de celular."; -"identity_server_settings_alert_disconnect_still_sharing_3pid" = "Você ainda está compartilhando seus dados pessoais no servidor de identidade %@.↵\n↵\nRecomendamos que você remova seus endereços de e-mail e números de telefone do servidor de identidade antes de desconectar."; -"call_no_stun_server_error_title" = "A chamada falhou por conta de má configuração no servidor"; -"widget_integration_manager_disabled" = "Você precisa ativar o Gerenciador de Integrações nas configurações"; -"service_terms_modal_description_for_identity_server_1" = "Encontrar outras pessoas por telefone ou e-mail"; -"service_terms_modal_description_for_identity_server_2" = "Seja encontrada/o por número de celular ou por e-mail"; -"device_verification_self_verify_wait_additional_information" = "Isso funciona no Element e em outros clientes da Matrix capazes de fazer autoverificação."; -"key_verification_verified_user_information" = "As mensagens com este usuário estão criptografadas de ponta a ponta e não podem ser lidas por terceiros."; -"device_verification_emoji_smiley" = "Sorriso"; +"user_verification_session_details_additional_information_untrusted_other_user" = "Até que esta(e) usuária(o) confie nesta sessão, mensagens enviadas para e desde ela são etiquetadas com avisos. Alternativamente, você pode verificá-la manualmente."; +"user_verification_session_details_verify_action_current_user" = "Verificar Interativamente"; +"user_verification_session_details_verify_action_current_user_manually" = "Verificar Manualmente por Texto"; +"user_verification_session_details_verify_action_other_user" = "Verificar manualmente"; +"auth_add_email_phone_message_2" = "Defina um email para recuperação de conta. Use depois email ou telefone para ser opcionalmente descobertável por pessoas que conhecem você."; +"auth_email_is_required" = "Nenhum servidor de identidade está configurado então você não pode adicionar um endereço de email a fim de resettar sua senha no futuro."; +"auth_softlogout_clear_data_message_1" = "Aviso: Seus dados pessoais (incluindo chaves de encriptação) ainda estão armazenados neste dispositivo."; +"auth_softlogout_clear_data_sign_out" = "Fazer signout"; +"room_creation_error_invite_user_by_email_without_identity_server" = "Nenhum servidor de identidade está configurado então você não pode adicionar um/uma participante com um email."; +"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "Nenhum servidor de identidade está configurado então você não pode começar um chat com um contato usando um email."; +"room_participants_action_security_status_warning" = "Aviso"; +"settings_three_pids_management_information_part1" = "Gerencie quais endereços de email ou números de telefone você pode usar para fazer login ou recuperar sua conta aqui. Controle quem pode encontrar você em "; +"settings_calls_stun_server_fallback_button" = "Permitir servidor fallback de assistência de chamadas"; +"settings_discovery_terms_not_signed" = "Concorde com os Termos de Serviço do Servidor de Identidade (%@) para permitir que você mesma(o) seja descobertável por endereço de email ou número de telefone."; +"settings_discovery_three_pids_management_information_part1" = "Gerencie quais endereços de email ou números de telefone outras(os) usuárias(os) podem usar para descobrir você e usar para convidar você a salas. Adicione ou remova endereços de email ou números de telefone desta lista em "; +"settings_discovery_three_pid_details_title_email" = "Gerenciar email"; +"settings_discovery_three_pid_details_information_email" = "Gerencie preferências para este endereço de email, que outras(os) usuárias(os) podem usar para descobrir você e usar para convidar você a salas. Adicione ou remova endereços de email em Contas."; +"settings_discovery_three_pid_details_cancel_email_validation_action" = "Cancelar validação de email"; +"security_settings_crosssigning" = "ASSINATURA CRUZADA"; +"security_settings_crosssigning_info_not_bootstrapped" = "Assinatura cruzada não está ainda configurada."; +"security_settings_crosssigning_info_exists" = "Sua conta tem uma identidade de assinatura cruzada, mas ainda não é confiada por esta sessão. Complete segurança desta sessão."; +"security_settings_crosssigning_info_trusted" = "Assinatura cruzada está ativada. Você pode confiar em outras(os) usuárias(os) e suas outras sessões baseada(o) em assinatura cruzada mas você não pode fazer assinar cruzado desta sessão porque ela não tem chaves privadas de assinatura cruzada. Complete segurança desta sessão."; +"security_settings_crosssigning_info_ok" = "Assinatura cruzada está pronta para uso."; +"security_settings_crosssigning_bootstrap" = "Configurar"; +"security_settings_crosssigning_reset" = "Resettar"; +"identity_server_settings_disconnect_info" = "Desconectar-se de seu servidor de identidade vai significar que você não vai ser descobertável por outras(os) usuárias(os) e ser capaz de convidar outras(os) por email ou telefone."; +"identity_server_settings_alert_disconnect_still_sharing_3pid" = "Você ainda está compartilhando seus dados pessoais no servidor de identidade %@.\n\nNós recomendamos que você remova seus endereços de email e números de telefone do servidor de identidade antes de se desconectar."; +"call_no_stun_server_error_title" = "Chamada falhou devido a servidor malconfigurado"; +"widget_integration_manager_disabled" = "Você precisa ativar Gerenciador de Integração em configurações"; +"service_terms_modal_description_for_identity_server_1" = "Encontrar outras(os) por telefone ou email"; +"service_terms_modal_description_for_identity_server_2" = "Ser encontrada(o) por telefone ou email"; +"device_verification_self_verify_wait_additional_information" = "Isto funciona com Element e outros clientes Matrix capazes de assinatura cruzada."; +"key_verification_verified_user_information" = "Mensagens com esta(e) usuária(o) são encriptadas ponta-a-ponta e não podem ser lidas por terceiros."; +"device_verification_emoji_smiley" = "Smiley"; // Generic errors -"error_invite_3pid_with_no_identity_server" = "Adicionar um servidor de identidade nas suas configurações para convidar por e-mail."; -"key_verification_bootstrap_not_setup_message" = "Você precisa fazer a autoverificação em primeiro lugar."; -"user_verification_sessions_list_user_trust_level_warning_title" = "Atenção"; -"user_verification_sessions_list_information" = "As mensagens com este usuário nesta sala estão criptografadas de ponta a ponta e não podem ser lidas por terceiros."; -"secrets_recovery_with_passphrase_information_default" = "Digite a sua senha de recuperação para acessar o seu histórico de mensagens seguras e a sua identidade autoverificada para confirmar outras sessões."; -"secrets_recovery_with_key_information_default" = "Digite a sua chave de recuperação para acessar o seu histórico de mensagens seguras e para confirmar outras sessões com sua identidade autoverificada."; +"error_invite_3pid_with_no_identity_server" = "Adicione um servidor de identidade em suas configurações para convidar por email."; +"key_verification_bootstrap_not_setup_message" = "Você precisa fazer bootstrap de assinatura cruzada primeiro."; +"user_verification_sessions_list_user_trust_level_warning_title" = "Aviso"; +"user_verification_sessions_list_information" = "Mensagens com esta(e) usuária(o) nesta sala são encriptadas ponta-a-ponta e não podem ser lidas por terceiros."; +"secrets_recovery_with_passphrase_information_default" = "Acesse seu histórico de mensagens seguras e sua identidade de assinatura cruzada para verificar outras sessões ao entrar sua Frase de Segurança."; +"secrets_recovery_with_key_information_default" = "Acesse seu histórico de mensagens seguras e sua identidade de assinatura cruzada para verificar outras sessões ao entrar sua Chave de Segurança."; "secrets_setup_recovery_key_done_action" = "Fechar"; -"secrets_setup_recovery_passphrase_validate_action" = "Fechar"; +"secrets_setup_recovery_passphrase_validate_action" = "Feito"; "pin_protection_settings_enabled_forced" = "PIN ativado"; -"pin_protection_settings_enable_pin" = "Ativar o PIN"; +"pin_protection_settings_enable_pin" = "Ativar PIN"; "biometrics_settings_enable_x" = "Ativar %@"; "biometrics_setup_title_x" = "Ativar %@"; "biometrics_setup_enable_button_title_x" = "Ativar %@"; -"biometrics_cant_unlocked_alert_message_x" = "Para desbloquear, use %@ ou faça login novamente e ative %@ novamente"; +"biometrics_cant_unlocked_alert_message_x" = "Para destrancar, use %@ ou faça login de volta e ative %@ de novo"; // Accessibility -"accessibility_checkbox_label" = "caixa de seleção"; +"accessibility_checkbox_label" = "checkbox"; // MARK: Clients "client_desktop_name" = "Element para Computador"; "client_web_name" = "Element Web"; "client_ios_name" = "Element para iOS"; "client_android_name" = "Element para Android"; -"auth_add_phone_message_2" = "Defina um número de telefone. Posteriormente, você pode permitir que as pessoas encontrem você através dele."; -"auth_phone_is_required" = "Nenhum servidor de identidade está configurado, portanto você não pode adicionar um número de telefone para redefinir sua senha no futuro."; -"auth_forgot_password_error_no_configured_identity_server" = "Nenhum servidor de identidade está configurado: adicione um para redefinir sua senha."; -"auth_reset_password_error_is_required" = "Nenhum servidor de identidade está configurado: adicione um nas configurações do servidor para redefinir sua senha."; -"auth_softlogout_signed_out" = "Você está desconectada/o"; -"auth_softlogout_sign_in" = "Entrar"; -"auth_softlogout_recover_encryption_keys" = "Faça login para recuperar as chaves de criptografia armazenadas exclusivamente neste aparelho. Você precisa delas para ler todas as suas mensagens seguras em qualquer aparelho."; +"auth_add_phone_message_2" = "Defina um número de telefone, e depois para ser opcionalmente descobertável por pessoas que conhecem você."; +"auth_phone_is_required" = "Nenhum servidor de identidade está configurado então você não pode adicionar um número de telefone a fim de resettar sua senha no futuro."; +"auth_forgot_password_error_no_configured_identity_server" = "Nenhum servidor de identidade está configurado: adicione um para resettar sua senha."; +"auth_reset_password_error_is_required" = "Nenhum servidor de identidade está configurado: adicione um em opções de servidor para resettar sua senha."; +"auth_softlogout_signed_out" = "Você está com signout feito"; +"auth_softlogout_sign_in" = "Fazer Signin"; +"auth_softlogout_recover_encryption_keys" = "Faça signin para recuperar chaves de encriptação armazenadas exclusivamente neste dispositivo. Você precisa delas para ler todas suas mensagens seguras em qualquer dispositivo."; "auth_softlogout_clear_data" = "Limpar dados pessoais"; -"auth_softlogout_clear_data_message_2" = "Limpar quando terminar de usar este aparelho, ou quando quiser fazer login em outra conta."; +"auth_softlogout_clear_data_message_2" = "Limpe-os se você estiver terminada(o) de usar este dispositivo, ou quando quiser fazer signin a uma outra conta."; "auth_softlogout_clear_data_button" = "Limpar todos os dados"; "auth_softlogout_clear_data_sign_out_title" = "Tem certeza?"; -"auth_softlogout_clear_data_sign_out_msg" = "Tem certeza de que deseja limpar todos os dados atualmente armazenados neste aparelho? Faça login novamente para acessar os dados e mensagens de sua conta."; +"auth_softlogout_clear_data_sign_out_msg" = "Tem certeza que você quer limpar todos os dados atualmente armazenados neste dispositivo? Faça signin de novo para acessar os dados e mensagens de sua conta."; "contacts_address_book_no_identity_server" = "Nenhum servidor de identidade configurado"; -"room_participants_remove_third_party_invite_prompt_msg" = "Tem certeza de que deseja cancelar este convite?"; +"room_participants_remove_third_party_invite_prompt_msg" = "Tem certeza que você quer revogar este convite?"; "room_participants_action_section_security" = "Segurança"; -"room_participants_action_security_status_verified" = "Confirmado"; -"room_participants_action_security_status_verify" = "Confirmar"; -"room_participants_action_security_status_complete_security" = "Segurança completa"; -"room_participants_security_information_room_encrypted" = "As mensagens nesta sala estão criptografadas de ponta a ponta.↵\n↵\nSuas mensagens são protegidas com cadeados e somente você e o destinatário têm as chaves exclusivas que permitam a sua leitura."; -"room_member_power_level_custom_in" = "Personalizado (%@) em %@"; -"room_member_power_level_short_custom" = "Personalizado"; -"room_accessiblity_scroll_to_bottom" = "Ir para as mensagens mais recentes"; +"room_participants_action_security_status_verified" = "Verificado"; +"room_participants_action_security_status_verify" = "Verificar"; +"room_participants_action_security_status_complete_security" = "Completar segurança"; +"room_participants_security_information_room_encrypted" = "Mensagens nesta sala são encriptadas ponta-a-ponta.\n\nSuas mensagens são asseguradas com cadeados e somente você e a/o recipiente têm as chaves únicas para destrancá-los."; +"room_member_power_level_custom_in" = "Personalizada(o) (%@) em %@"; +"room_member_power_level_short_custom" = "Perso"; +"room_accessiblity_scroll_to_bottom" = "Rolar para fundo"; "room_event_action_reaction_show_less" = "Mostrar menos"; "room_event_action_reaction_history" = "Histórico de reações"; -"room_message_edits_history_title" = "Edições na mensagem"; -"room_accessibility_upload" = "Enviar"; -"room_accessibility_hangup" = "Encerrar"; -"media_type_accessibility_image" = "Foto"; -"media_type_accessibility_location" = "Localização"; -"external_link_confirmation_title" = "Verificar este link"; -"external_link_confirmation_message" = "O link %@ redirecionará você para outro site: %@↵\n↵\nDeseja continuar?"; -"settings_discovery_settings" = "ENCONTRAR CONTATOS"; +"room_message_edits_history_title" = "Edições de mensagem"; +"room_accessibility_upload" = "Fazer upload"; +"room_accessibility_hangup" = "Desligar"; +"media_type_accessibility_image" = "Imagem"; +"media_type_accessibility_location" = "Local"; +"external_link_confirmation_title" = "Cheque duplamente este link"; +"external_link_confirmation_message" = "O link %@ vai levar você para um outro site: %@↵\n↵\nVocê tem certeza que você quer continuar?"; +"settings_discovery_settings" = "DESCOBERTA"; "settings_identity_server_settings" = "SERVIDOR DE IDENTIDADE"; -"settings_three_pids_management_information_part2" = "Encontrar contatos"; -"settings_labs_message_reaction" = "Adicionar reações em mensagens"; +"settings_three_pids_management_information_part2" = "Descoberta"; +"settings_labs_message_reaction" = "Reagir a mensagens com emoji"; "settings_add_3pid_password_title_msidsn" = "Adicionar número de telefone"; -"settings_add_3pid_password_message" = "Para continuar, por favor, digite sua senha"; +"settings_add_3pid_password_message" = "Para continuar, por favor entre sua senha"; "settings_add_3pid_invalid_password_message" = "Credenciais inválidas"; -"settings_key_backup_button_connect" = "Autorize esta sessão a fazer o backup de chaves"; -"settings_discovery_no_identity_server" = "No momento, você não está usando um servidor de identidade. Para descobrir e ser descoberto pelos contatos existentes, adicione um abaixo."; -"settings_discovery_error_message" = "Um erro ocorreu. Por favor, tente novamente mais tarde."; -"settings_discovery_three_pid_details_title_phone_number" = "Editar número de telefone"; -"settings_discovery_three_pid_details_information_phone_number" = "Configure este número de telefone, que outros usuários podem usar para descobrir sua conta e enviar um convite para salas. Adicione ou remova números de telefone em Contas."; -"settings_discovery_three_pid_details_enter_sms_code_action" = "Digite o código de ativação"; -"settings_identity_server_description" = "Usando o servidor de identidade definido acima, você pode descobrir e ser descoberto por contatos existentes que você conhece."; -"settings_identity_server_no_is" = "Nenhum servidor de identidade está configurado"; -"settings_identity_server_no_is_description" = "No momento, você não está usando um servidor de identidade. Para descobrir e ser descoberto pelos contatos existentes, adicione um acima."; +"settings_key_backup_button_connect" = "Conectar esta sessão a Backup de Chave"; +"settings_discovery_no_identity_server" = "Você não está atualmente usando um servidor de identidade. Para ser descobertável por contatos existentes, adicione um."; +"settings_discovery_error_message" = "Um erro ocorreu. Por favor retente."; +"settings_discovery_three_pid_details_title_phone_number" = "Gerenciar número de telefone"; +"settings_discovery_three_pid_details_information_phone_number" = "Gerencie preferências para este número de telefone, que outras(os) usuárias(os) podem usar para descobrir você e usar para convidar você a salas. Adicione ou remova números de telefone em Contas."; +"settings_discovery_three_pid_details_enter_sms_code_action" = "Entrar código de ativação de SMS"; +"settings_identity_server_description" = "Usando o servidor de identidade definido acima, você pode descobrir e ser descobertável por contatos existentes que você conhece."; +"settings_identity_server_no_is" = "Nenhum servidor de identidade configurado"; +"settings_identity_server_no_is_description" = "Você não está atualmente usando um servidor de identidade. Para descobrir e ser descobertável por contatos existentes que você conhece, adicione um acima."; // Security settings "security_settings_title" = "Segurança"; "security_settings_crypto_sessions" = "MINHAS SESSÕES"; "security_settings_crypto_sessions_loading" = "Carregando sessões…"; -"security_settings_secure_backup" = "BACKUP ONLINE"; -"security_settings_secure_backup_description" = "Previna-se contra a perda de acesso a mensagens e dados criptografados, fazendo backup das chaves de criptografia no seu servidor."; +"security_settings_secure_backup" = "BACKUP SEGURO"; +"security_settings_secure_backup_description" = "Faça backup de suas chaves de decriptação em caso você perca acesso a suas sessões. Suas chaves vão estar asseguradas com uma Chave de Segurança única."; "security_settings_secure_backup_setup" = "Configurar"; "security_settings_secure_backup_synchronise" = "Sincronizar"; -"security_settings_secure_backup_delete" = "Excluir"; -"security_settings_backup" = "BACKUP DE MENSAGENS"; -"security_settings_crosssigning_complete_security" = "Concluir segurança"; +"security_settings_secure_backup_delete" = "Deletar Backup"; +"security_settings_backup" = "BACKUP DE MENSAGEM"; +"security_settings_crosssigning_complete_security" = "Completar segurança"; "security_settings_cryptography" = "CRIPTOGRAFIA"; -"security_settings_advanced" = "AVANÇADO"; -"security_settings_complete_security_alert_title" = "Concluir segurança"; -"security_settings_complete_security_alert_message" = "Primeiro, você precisa concluir as etapas de segurança de sua sessão atual."; -"security_settings_coming_soon" = "Desculpe, este recurso ainda não está disponível no Element para iOS. Use outro cliente Matrix para configurar este recurso, e a definição valerá aqui."; -"manage_session_info" = "INFORMAÇÕES DA SESSÃO"; -"manage_session_trusted" = "Confiado por você"; -"manage_session_not_trusted" = "Não confiável"; -"manage_session_sign_out" = "Sair desta sessão"; +"security_settings_advanced" = "AVANÇADAS"; +"security_settings_complete_security_alert_title" = "Completar segurança"; +"security_settings_complete_security_alert_message" = "Você deveria completar segurança em sua sessão atual primeiro."; +"security_settings_coming_soon" = "Desculpe. Esta ação não está disponível em Element iOS ainda. Por favor use um outro cliente Matrix para configurá-la. Element iOS vai usá-la."; +"manage_session_info" = "INFO DE SESSÃO"; +"manage_session_trusted" = "Confiada por você"; +"manage_session_not_trusted" = "Não confiada"; +"manage_session_sign_out" = "Fazer signout desta sessão"; // Identity server settings -"identity_server_settings_title" = "Servidor de identidade"; -"identity_server_settings_description" = "No momento, você está usando %@ para descobrir e ser descoberto por seus contatos."; -"identity_server_settings_no_is_description" = "No momento, você não está usando um servidor de identidade. Para descobrir e ser descoberto pelos contatos existentes, adicione um acima."; -"identity_server_settings_place_holder" = "Digite um novo servidor de identidade"; +"identity_server_settings_title" = "Servidor de Identidade"; +"identity_server_settings_description" = "Vvocê está atualmente usando %@ para descobrir e ser descobertável por contatos existentes que você conhece."; +"identity_server_settings_no_is_description" = "Você não está atualmente usando um servidor de identidade. Para descobrir e ser descobertável por contatos existentes, adicione um acima."; +"identity_server_settings_place_holder" = "Entrar um servidor de identidade"; "identity_server_settings_add" = "Adicionar"; -"identity_server_settings_disconnect" = "Desconectar"; -"identity_server_settings_alert_no_terms_title" = "O servidor de identidade não tem termos de serviço"; -"identity_server_settings_alert_no_terms" = "O servidor de identidade que você escolheu não possui termos de serviço. Continue apenas se você confiar no proprietário do servidor."; -"identity_server_settings_alert_change" = "Desconectar-se do servidor de identidade %1$@ e conectar-se em %2$@ em vez disso?"; +"identity_server_settings_disconnect" = "Desconectar-se"; +"identity_server_settings_alert_no_terms_title" = "Servidor de identidade não tem termos de serviço"; +"identity_server_settings_alert_no_terms" = "O servidor de identidade que você tem escolhido não tem quaisquer termos de serviço. Somente continue se você confia na/do proprietária(o) do serviço."; +"identity_server_settings_alert_change" = "Desconectar-se do servidor de identidade %1$@ e conectar-se a %2$@ em vez disso?"; "identity_server_settings_alert_disconnect_title" = "Desconectar servidor de identidade"; "identity_server_settings_alert_disconnect" = "Desconectar-se do servidor de identidade %@?"; -"identity_server_settings_alert_disconnect_button" = "Desconectar"; -"identity_server_settings_alert_disconnect_still_sharing_3pid_button" = "Desconectar de qualquer maneira"; -"identity_server_settings_alert_error_terms_not_accepted" = "Você precisa aceitar os termos de %@ para defini-lo como servidor de identidade."; +"identity_server_settings_alert_disconnect_button" = "Desconectar-se"; +"identity_server_settings_alert_disconnect_still_sharing_3pid_button" = "Desconectar-se mesmo assim"; +"identity_server_settings_alert_error_terms_not_accepted" = "Você deve aceitar termos de %@ para defini-lo como servidor de identidade."; "identity_server_settings_alert_error_invalid_identity_server" = "%@ não é um servidor de identidade válido."; // Image picker "image_picker_action_camera" = "Tirar foto"; -"event_formatter_message_edited_mention" = "(editado)"; +"event_formatter_message_edited_mention" = "(editada)"; // Events formatter with you "event_formatter_widget_added_by_you" = "Você adicionou o widget: %@"; "event_formatter_widget_removed_by_you" = "Você removeu o widget: %@"; -"camera_unavailable" = "A câmera não está disponível no seu aparelho"; -"call_no_stun_server_error_message_2" = "Alternativamente, você pode tentar usar o servidor público em %@. No entanto, ele não é tão confiável e compartilhará o seu IP com esse servidor. Você também pode configurar isso nas Configurações"; -"call_no_stun_server_error_use_fallback_button" = "Tente usar %@"; +"camera_unavailable" = "A câmera está indisponível em seu dispositivo"; +"call_no_stun_server_error_message_2" = "Alternativamente, você pode tentar usar o servidor público em %@, mas isto não vai ser tão confiável, e vai compartilhar seu endereço de IP com esse servidor. Você também pode gerenciar isto em Configurações"; +"call_no_stun_server_error_use_fallback_button" = "Tentar usar %@"; // Widget -"widget_no_integrations_server_configured" = "O gerenciador de integrações não está configurado"; -"widget_integrations_server_failed_to_connect" = "Falha ao conectar-se no servidor de integrações"; +"widget_no_integrations_server_configured" = "Nenhum servidor de integrações configurado"; +"widget_integrations_server_failed_to_connect" = "Falha para conectar-se a servidor de integrações"; "widget_menu_refresh" = "Recarregar"; -"widget_menu_open_outside" = "Abrir no navegador"; -"widget_menu_revoke_permission" = "Remover para mim"; -"widget_menu_remove" = "Remover para todos"; +"widget_menu_open_outside" = "Abrir em browser"; +"widget_menu_revoke_permission" = "Revogar acesso para mim"; +"widget_menu_remove" = "Remover para todas as pessoas"; // Widget Picker "widget_picker_title" = "Integrações"; "widget_picker_manage_integrations" = "Gerenciar integrações…"; // Room widget permissions -"room_widget_permission_title" = "Carregar widget"; -"room_widget_permission_creator_info_title" = "Widget adicionado por:"; -"room_widget_permission_webview_information_title" = "A sua utilização pode definir cookies e compartilhar dados com %@:↵\n"; -"room_widget_permission_information_title" = "A sua utilização pode compartilhar dados com %@:↵\n"; -"room_widget_permission_user_id_permission" = "Sua ID de usuário"; +"room_widget_permission_title" = "Carregar Widget"; +"room_widget_permission_creator_info_title" = "Este widget foi adicionado por:"; +"room_widget_permission_webview_information_title" = "Usá-lo pode definir cookies e compartilhar dados com %@:\n"; +"room_widget_permission_information_title" = "Usá-lo pode compartilhar dados com %@:\n"; +"room_widget_permission_user_id_permission" = "Sua ID de usuária(o)"; "room_widget_permission_theme_permission" = "Seu tema"; -"room_widget_permission_widget_id_permission" = "ID do widget"; -"room_widget_permission_room_id_permission" = "ID da sala"; +"room_widget_permission_widget_id_permission" = "ID de widget"; +"room_widget_permission_room_id_permission" = "ID de sala"; // Service terms -"service_terms_modal_title" = "Termos de serviço"; -"service_terms_modal_message" = "Para continuar, você precisa aceitar os termos de serviço (%@)."; +"service_terms_modal_title" = "Termos De Serviço"; +"service_terms_modal_message" = "Para continuar você precisa aceitar os termos deste serviço (%@)."; "service_terms_modal_accept_button" = "Aceitar"; -"service_terms_modal_decline_button" = "Recusar"; +"service_terms_modal_decline_button" = "Declinar"; // Service terms - Variant for identity server when displayed out of a context -"service_terms_modal_title_identity_server" = "Encontrar contatos"; +"service_terms_modal_title_identity_server" = "Descoberta de contatos"; "service_terms_modal_message_identity_server" = "Aceite os termos do servidor de identidade (%@) para descobrir contatos."; "service_terms_modal_policy_checkbox_accessibility_hint" = "Marque para aceitar %@"; -"secure_key_backup_setup_intro_title" = "Backup online"; -"secure_key_backup_setup_intro_info" = "Previna-se contra a perda de acesso a mensagens e dados criptografados, fazendo backup das chaves de criptografia no seu servidor."; -"secure_key_backup_setup_intro_use_security_key_title" = "Use uma Chave de Segurança"; -"secure_key_backup_setup_intro_use_security_key_info" = "Gere uma chave de segurança para armazenar num lugar seguro, como um gerenciador de senhas ou um cofre."; -"secure_key_backup_setup_intro_use_security_passphrase_title" = "Use uma Frase de Segurança"; -"secure_key_backup_setup_intro_use_security_passphrase_info" = "Digite uma frase secreta que só você conhece, e gere uma chave para backup."; -"secure_key_backup_setup_existing_backup_error_title" = "Já existe um backup de mensagens"; -"secure_key_backup_setup_existing_backup_error_info" = "Desbloqueie-o para reutilizá-lo no backup online ou exclua-o para criar um novo backup de mensagens no backup online."; -"key_backup_setup_intro_setup_connect_action_with_existing_backup" = "Autorize este aparelho a fazer o backup de chaves"; -"device_verification_incoming_description_1" = "Confirme se esta sessão é sua. Confirmar sessões fornece segurança adicional, ao usar mensagens criptografadas de ponta a ponta."; -"device_verification_incoming_description_2" = "Se você confirmar essa sessão, você também a tornará confirmada para o seu contato."; +"secure_key_backup_setup_intro_title" = "Backup Seguro"; +"secure_key_backup_setup_intro_info" = "Salvaguardar-se contra perda de acesso a mensagens & dados encriptados ao fazer backup de chaves de encriptação em seu servidor."; +"secure_key_backup_setup_intro_use_security_key_title" = "Usar uma Chave de Segurança"; +"secure_key_backup_setup_intro_use_security_key_info" = "Gere uma chave de segurança para armazenar em algum lugar seguro como um gerenciador de senhas ou um cofre."; +"secure_key_backup_setup_intro_use_security_passphrase_title" = "Usar uma Frase de Segurança"; +"secure_key_backup_setup_intro_use_security_passphrase_info" = "Entre uma frase secreta que somente você conhece, e gere uma chave para backup."; +"secure_key_backup_setup_existing_backup_error_title" = "Um backup para mensagens já existe"; +"secure_key_backup_setup_existing_backup_error_info" = "Destranque-o para reusá-lo no backup seguro ou delete-o para criar um novo backup de mensagens no backup seguro."; +"key_backup_setup_intro_setup_connect_action_with_existing_backup" = "Conectar este dispositivo a Backup de Chave"; +"device_verification_incoming_description_1" = "Verifique esta sessão para marcá-la como confiada. Confiar em sessões de parceiras(os) dá a você paz de mente extra quando usando mensagens encriptadas ponta-a-ponta."; +"device_verification_incoming_description_2" = "Verificar esta sessão vai marcá-la como confiada, e também marcar sua sessão como confiada para a/o parceira(o)."; // MARK: Start -"device_verification_start_title" = "Confirmar comparando um texto curto"; -"device_verification_start_use_legacy" = "Não aparece nada? Nem todos os clientes suportam a confirmação interativa. Use a confirmação tradicional."; -"device_verification_start_verify_button" = "Iniciar a confirmação"; -"device_verification_start_use_legacy_action" = "Use a confirmação tradicional"; +"device_verification_start_title" = "Verificar ao comparar um string de texto curto"; +"device_verification_start_use_legacy" = "Nada aparecendo? Não todos os clientes suportam verificação interativa ainda. Use verificação legado."; +"device_verification_start_verify_button" = "Começar a Verificar"; +"device_verification_start_use_legacy_action" = "Usar Verificação Legado"; // New login "device_verification_self_verify_alert_title" = "Novo login. Foi você?"; -"device_verification_self_verify_alert_validate_action" = "Confirmar"; -"device_verification_self_verify_start_verify_action" = "Iniciar a confirmação"; -"device_verification_self_verify_start_information" = "Use esta sessão para confirmar a sua nova sessão, dando a ela acesso às mensagens criptografadas."; -"key_verification_self_verify_current_session_alert_title" = "Confirmar esta sessão"; -"key_verification_self_verify_current_session_alert_message" = "Outros usuários podem não confiar nela."; -"key_verification_self_verify_current_session_alert_validate_action" = "Confirmar"; -"key_verification_self_verify_unverified_sessions_alert_title" = "Revisar onde você está logado"; -"key_verification_self_verify_unverified_sessions_alert_message" = "Verifique todas as suas sessões para garantir que sua conta e mensagens estão seguras."; +"device_verification_self_verify_alert_validate_action" = "Verificar"; +"device_verification_self_verify_start_verify_action" = "Começar verificação"; +"device_verification_self_verify_start_information" = "Use esta sessão para verificar sua nova, garantindo-lhe acesso a mensagens encriptadas."; +"key_verification_self_verify_current_session_alert_title" = "Verificar esta sessão"; +"key_verification_self_verify_current_session_alert_message" = "Outras(os) usuárias(os) podem não confiar nela."; +"key_verification_self_verify_current_session_alert_validate_action" = "Verificar"; +"key_verification_self_verify_unverified_sessions_alert_title" = "Revisar onde você tem sido feito login"; +"key_verification_self_verify_unverified_sessions_alert_message" = "Verifique todas as suas sessões para assegurar que sua conta & mensagens estão seguras."; "key_verification_self_verify_unverified_sessions_alert_validate_action" = "Revisar"; -"device_verification_self_verify_wait_title" = "Concluir segurança"; -"device_verification_self_verify_wait_new_sign_in_title" = "Confirmar este login"; -"device_verification_self_verify_wait_information" = "Confirme esta sessão a partir de uma de suas outras sessões, concedendo acesso às mensagens criptografadas.↵\n↵\nUse o Element mais recente em seus outros aparelhos:"; -"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Usar chave de recuperação"; -"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Use a chave de recuperação, ou a frase de recuperação"; -"device_verification_self_verify_wait_recover_secrets_additional_information" = "Se você não tem acesso a uma sessão existente"; +"device_verification_self_verify_wait_title" = "Completar segurança"; +"device_verification_self_verify_wait_new_sign_in_title" = "Verificar este login"; +"device_verification_self_verify_wait_information" = "Confirme sua identidade ao verificar este login desde uma de suas outras sessões, garantindo-lhe acesso a mensagens encriptadas.\n\nUse o Element mais recente em seus outros dispositivos:"; +"device_verification_self_verify_wait_recover_secrets_without_passphrase" = "Usar Chave de Segurança"; +"device_verification_self_verify_wait_recover_secrets_with_passphrase" = "Usar Frase ou Chave de Segurança"; +"device_verification_self_verify_wait_recover_secrets_additional_information" = "Se você não consegue acessar uma sessão existente"; "key_verification_verify_sas_title_number" = "Comparar números"; -"key_verification_verify_sas_cancel_action" = "Não correspondem"; -"key_verification_verify_sas_validate_action" = "Correspondem"; -"key_verification_verify_sas_additional_information" = "Para maior segurança, use outro meio de comunicação confiável ou faça isso pessoalmente."; -"key_verification_manually_verify_device_instruction" = "Compare as seguintes informações com aquelas na sessão do outro usuário e confirme:"; -"key_verification_manually_verify_device_name_title" = "Nome da sessão"; -"key_verification_manually_verify_device_id_title" = "ID da sessão"; -"key_verification_manually_verify_device_key_title" = "Chave da sessão"; -"key_verification_manually_verify_device_additional_information" = "Se eles não corresponderem, a segurança da sua comunicação pode estar comprometida."; -"key_verification_manually_verify_device_validate_action" = "Confirmar"; -"device_verification_verified_title" = "Confirmado!"; -"device_verification_verified_got_it_button" = "Ok, entendi"; -"key_verification_verified_new_session_title" = "Sessão confirmada!"; -"key_verification_verified_other_session_information" = "Agora você poderá ler mensagens seguras em sua outra sessão, e os usuários saberão que podem confiar nela."; -"key_verification_verified_new_session_information" = "Agora você poderá ler mensagens seguras em seu outro aparelho, e os usuários saberão que podem confiar nele."; -"key_verification_verified_this_session_information" = "Agora você poderá ler mensagens seguras neste aparelho, e os usuários saberão que podem confiar nele."; +"key_verification_verify_sas_cancel_action" = "Eles não correspondem"; +"key_verification_verify_sas_validate_action" = "Eles correspondem"; +"key_verification_verify_sas_additional_information" = "Para segurança ótima, use um outro meio de comunicação confiado ou faça isto em pessoa."; +"key_verification_manually_verify_device_instruction" = "Confirme ao comparar o seguinte com as Configurações de Usuária(o) em sua outra sessão:"; +"key_verification_manually_verify_device_name_title" = "Nome de sessão"; +"key_verification_manually_verify_device_id_title" = "ID de sessão"; +"key_verification_manually_verify_device_key_title" = "Chave de sessão"; +"key_verification_manually_verify_device_additional_information" = "Se eles não corresponderem, a segurança de sua comunicação pode estar comprometida."; +"key_verification_manually_verify_device_validate_action" = "Verificar"; +"device_verification_verified_title" = "Verificado!"; +"device_verification_verified_got_it_button" = "Entendido"; +"key_verification_verified_new_session_title" = "Nova sessão verificada!"; +"key_verification_verified_other_session_information" = "Você pode agora ler mensagens seguras em sua outra sessão, e outras(os) usuárias(os) vão saber que elas(es) podem confiar nela."; +"key_verification_verified_new_session_information" = "Você poder agora ler mensagens seguras em seu novo dispositivo, e outras(os) usuárias(os) vão saber que elas(es) podem confiar nele."; +"key_verification_verified_this_session_information" = "Você pode agora ler mensagens seguras neste dispositivo, e outras(os) usuárias(os) vão saber que elas(es) podem confiar nele."; // MARK: Emoji "device_verification_emoji_dog" = "Cachorro"; "device_verification_emoji_cat" = "Gato"; @@ -1011,7 +1011,7 @@ "device_verification_emoji_butterfly" = "Borboleta"; "device_verification_emoji_flower" = "Flor"; "device_verification_emoji_tree" = "Árvore"; -"device_verification_emoji_cactus" = "Cacto"; +"device_verification_emoji_cactus" = "Cactus"; "device_verification_emoji_mushroom" = "Cogumelo"; "device_verification_emoji_globe" = "Globo"; "device_verification_emoji_moon" = "Lua"; @@ -1027,16 +1027,16 @@ "device_verification_emoji_hat" = "Chapéu"; "device_verification_emoji_glasses" = "Óculos"; "device_verification_emoji_spanner" = "Chave inglesa"; -"device_verification_emoji_santa" = "Papai-noel"; +"device_verification_emoji_santa" = "Noel"; "device_verification_emoji_thumbs up" = "Joinha"; -"device_verification_emoji_umbrella" = "Guarda-chuva"; +"device_verification_emoji_umbrella" = "Guardachuva"; "device_verification_emoji_hourglass" = "Ampulheta"; "device_verification_emoji_clock" = "Relógio"; "device_verification_emoji_gift" = "Presente"; "device_verification_emoji_light bulb" = "Lâmpada"; "device_verification_emoji_book" = "Livro"; "device_verification_emoji_pencil" = "Lápis"; -"device_verification_emoji_paperclip" = "Clipe de papel"; +"device_verification_emoji_paperclip" = "Clip de papel"; "device_verification_emoji_lock" = "Cadeado"; "device_verification_emoji_key" = "Chave"; "device_verification_emoji_hammer" = "Martelo"; @@ -1055,210 +1055,210 @@ "device_verification_emoji_folder" = "Pasta"; "device_verification_emoji_pin" = "Alfinete"; // MARK: File upload -"file_upload_error_title" = "Envio de arquivo"; -"file_upload_error_unsupported_file_type_message" = "Tipo de arquivo não compatível."; +"file_upload_error_title" = "Upload de arquivo"; +"file_upload_error_unsupported_file_type_message" = "Tipo de arquivo não suportado."; // MARK: Emoji picker "emoji_picker_title" = "Reações"; // MARK: Reaction history "reaction_history_title" = "Reações"; -"error_not_supported_on_mobile" = "Você não pode fazer isso no %@ para iOS."; +"error_not_supported_on_mobile" = "Você não pode fazer isto desde %@ mobile."; "key_verification_bootstrap_not_setup_title" = "Erro"; -"key_verification_tile_request_incoming_title" = "Solicitação de confirmação"; -"key_verification_tile_request_outgoing_title" = "Confirmação enviada"; -"key_verification_tile_request_status_data_loading" = "Carregando…"; -"key_verification_tile_request_status_expired" = "Expirado"; +"key_verification_tile_request_incoming_title" = "Requisição de verificação"; +"key_verification_tile_request_outgoing_title" = "Verificação enviada"; +"key_verification_tile_request_status_data_loading" = "Dados carregando…"; +"key_verification_tile_request_status_expired" = "Expirada"; "key_verification_tile_request_status_cancelled_by_me" = "Você cancelou"; "key_verification_tile_request_status_cancelled" = "%@ cancelou"; "key_verification_tile_request_status_accepted" = "Você aceitou"; "key_verification_tile_request_incoming_approval_accept" = "Aceitar"; -"key_verification_tile_request_incoming_approval_decline" = "Recusar"; -"key_verification_tile_conclusion_done_title" = "Confirmado"; -"key_verification_tile_conclusion_warning_title" = "Login não confiável"; -"key_verification_incoming_request_incoming_alert_message" = "%@ solicita confirmação"; -"key_verification_verify_qr_code_title" = "Confirmar através de QR Code"; -"key_verification_verify_qr_code_information" = "Escaneie o código para confirmar um ao outro com segurança."; -"key_verification_verify_qr_code_information_other_device" = "Escaneie o código abaixo para confirmar:"; -"key_verification_verify_qr_code_emoji_information" = "Confirmar comparando emojis únicos."; -"key_verification_verify_qr_code_cannot_scan_action" = "Não consegue escanear?"; -"key_verification_verify_qr_code_start_emoji_action" = "Confirmar por emojis"; -"key_verification_verify_qr_code_other_scan_my_code_title" = "O seu contato escaneou o código QR com sucesso?"; +"key_verification_tile_request_incoming_approval_decline" = "Declinar"; +"key_verification_tile_conclusion_done_title" = "Verificada"; +"key_verification_tile_conclusion_warning_title" = "Signin não-confiado"; +"key_verification_incoming_request_incoming_alert_message" = "%@ quer verificar"; +"key_verification_verify_qr_code_title" = "Verificar por scanning"; +"key_verification_verify_qr_code_information" = "Scanne o código para verificar seguramente um/uma a/o outra(o)."; +"key_verification_verify_qr_code_information_other_device" = "Scanne o código abaixo para verificar:"; +"key_verification_verify_qr_code_emoji_information" = "Verificar ao comparar emoji únicos."; +"key_verification_verify_qr_code_cannot_scan_action" = "Não dá pra scannar?"; +"key_verification_verify_qr_code_start_emoji_action" = "Verificar por emoji"; +"key_verification_verify_qr_code_other_scan_my_code_title" = "A/o outra(o) usuária(o) scannou o QR code com sucesso?"; "key_verification_verify_qr_code_scan_other_code_success_title" = "Código validado!"; -"key_verification_verify_qr_code_scan_other_code_success_message" = "O código QR foi validado com sucesso."; -"key_verification_scan_confirmation_scanned_user_information" = "Este escudo também aparece para %@?"; -"key_verification_scan_confirmation_scanned_device_information" = "O outro aparelho está mostrando o mesmo escudo?"; -"user_verification_start_verify_action" = "Iniciar a confirmação"; -"user_verification_start_information_part1" = "Para segurança extra, confirme· "; -"user_verification_start_information_part2" = " comparando um código único em ambos os aparelhos."; -"user_verification_start_additional_information" = "Para sua segurança, faça isso pessoalmente ou use outra forma de comunicação."; -"user_verification_sessions_list_user_trust_level_trusted_title" = "Confiável"; +"key_verification_verify_qr_code_scan_other_code_success_message" = "QR code tem sido validado com sucesso."; +"key_verification_scan_confirmation_scanned_user_information" = "%@ está mostrando o mesmo escudo?"; +"key_verification_scan_confirmation_scanned_device_information" = "O outro dispositivo está mostrando o mesmo escudo?"; +"user_verification_start_verify_action" = "Começar verificação"; +"user_verification_start_information_part1" = "Para segurança extra, verifique "; +"user_verification_start_information_part2" = " ao checar um código de uma vez em ambos seus dispositivos."; +"user_verification_start_additional_information" = "Para estar segura(o), faça isto em pessoa ou use uma outra forma de se comunicar."; +"user_verification_sessions_list_user_trust_level_trusted_title" = "Confiado"; "user_verification_sessions_list_user_trust_level_unknown_title" = "Desconhecido"; "user_verification_sessions_list_table_title" = "Sessões"; -"user_verification_sessions_list_session_trusted" = "Confiável"; -"user_verification_sessions_list_session_untrusted" = "Não confiável"; -"user_verification_session_details_trusted_title" = "Confiável"; -"user_verification_session_details_untrusted_title" = "Não confiável"; -"user_verification_session_details_information_trusted_current_user" = "Esta sessão é confiável para o envio de mensagens seguras porque você a confirmou:"; -"user_verification_session_details_information_trusted_other_user_part1" = "Esta sessão é confiável para o envio de mensagens seguras porque· "; -"user_verification_session_details_information_trusted_other_user_part2" = " ·confirmou:"; -"user_verification_session_details_information_untrusted_current_user" = "Confirme esta sessão para marcá-la como confiável e conceder a ela acesso a mensagens criptografadas:"; -"user_verification_session_details_information_untrusted_other_user" = " ·entrou usando uma nova sessão:"; -"user_verification_session_details_additional_information_untrusted_current_user" = "Se você não fez login nesta sessão, sua conta pode estar comprometida."; -"secrets_recovery_with_passphrase_title" = "Frase secreta de recuperação"; -"secrets_recovery_with_passphrase_information_verify_device" = "Use sua frase secreta de recuperação para confirmar este aparelho."; -"secrets_recovery_with_passphrase_passphrase_title" = "Digite"; -"secrets_recovery_with_passphrase_passphrase_placeholder" = "Digite a senha de recuperação"; -"secrets_recovery_with_passphrase_recover_action" = "Use a frase secreta"; -"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Não sabe sua frase de recuperação? Você pode· "; -"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "use sua chave de recuperação"; +"user_verification_sessions_list_session_trusted" = "Confiada"; +"user_verification_sessions_list_session_untrusted" = "Não confiada"; +"user_verification_session_details_trusted_title" = "Confiada"; +"user_verification_session_details_untrusted_title" = "Não Confiada"; +"user_verification_session_details_information_trusted_current_user" = "Esta sessão é confiada para mensageria segura porque você a verificou:"; +"user_verification_session_details_information_trusted_other_user_part1" = "Esta sessão é confiada para mensageria segura porque "; +"user_verification_session_details_information_trusted_other_user_part2" = " a verificou:"; +"user_verification_session_details_information_untrusted_current_user" = "Verifique esta sessão para marcá-la como confiada & garantir-lhe acesso a mensagens encriptadas:"; +"user_verification_session_details_information_untrusted_other_user" = " fez signin usando uma nova sessão:"; +"user_verification_session_details_additional_information_untrusted_current_user" = "Se você não fez signin a esta sessão, sua conta pode estar comprometida."; +"secrets_recovery_with_passphrase_title" = "Frase de Segurança"; +"secrets_recovery_with_passphrase_information_verify_device" = "Use sua Frase de Segurança para verificar este dispositivo."; +"secrets_recovery_with_passphrase_passphrase_title" = "Entrar"; +"secrets_recovery_with_passphrase_passphrase_placeholder" = "Entrar Frase de Segurança"; +"secrets_recovery_with_passphrase_recover_action" = "Usar Frase"; +"secrets_recovery_with_passphrase_lost_passphrase_action_part1" = "Não sabe sua Frase de Segurança? Você pode "; +"secrets_recovery_with_passphrase_lost_passphrase_action_part2" = "usar sua Chave de Segurança"; "secrets_recovery_with_passphrase_lost_passphrase_action_part3" = "."; -"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Não foi possível acessar o armazenamento secreto"; -"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Verifique se você digitou a frase de recuperação correta."; -"secrets_recovery_with_key_title" = "Chave de recuperação"; -"secrets_recovery_with_key_information_verify_device" = "Use sua chave de recuperação para confirmar este aparelho."; -"secrets_recovery_with_key_recovery_key_title" = "Digite"; -"secrets_recovery_with_key_recovery_key_placeholder" = "Digite a chave de recuperação"; -"secrets_recovery_with_key_recover_action" = "Usar chave"; -"secrets_recovery_with_key_invalid_recovery_key_title" = "Não foi possível acessar o armazenamento secreto"; -"secrets_recovery_with_key_invalid_recovery_key_message" = "Verifique se você digitou a chave de recuperação correta."; -"secrets_setup_recovery_key_title" = "Salve a sua chave de segurança"; -"secrets_setup_recovery_key_information" = "Guarde sua chave de recuperação em um lugar seguro. Ela pode ser usada para desbloquear suas mensagens e dados criptografados."; -"secrets_setup_recovery_key_loading" = "Acessar…"; +"secrets_recovery_with_passphrase_invalid_passphrase_title" = "Incapaz de acessar armazenamento secreto"; +"secrets_recovery_with_passphrase_invalid_passphrase_message" = "Por favor verifique que você entrou a Frase de Segurança correta."; +"secrets_recovery_with_key_title" = "Chave de Segurança"; +"secrets_recovery_with_key_information_verify_device" = "Use sua Chave de Segurança para verificar este dispositivo."; +"secrets_recovery_with_key_recovery_key_title" = "Entrar"; +"secrets_recovery_with_key_recovery_key_placeholder" = "Entrar Chave de Segurança"; +"secrets_recovery_with_key_recover_action" = "Usar Chave"; +"secrets_recovery_with_key_invalid_recovery_key_title" = "Incapaz de acessar armazenamento secreto"; +"secrets_recovery_with_key_invalid_recovery_key_message" = "Por favor verifique que você entrou a Chave de Segurança correta."; +"secrets_setup_recovery_key_title" = "Salvar sua Chave de Segurança"; +"secrets_setup_recovery_key_information" = "Armazene sua Chave de Segurança em algum lugar seguro. Ela pode ser usada para destrancar suas mensagens & dados encriptados."; +"secrets_setup_recovery_key_loading" = "Carregando…"; "secrets_setup_recovery_key_export_action" = "Salvar"; -"secrets_setup_recovery_key_storage_alert_title" = "Guarde num lugar seguro"; -"secrets_setup_recovery_key_storage_alert_message" = "✓ Imprima e guarde em algum lugar seguro\n✓ Salve em uma chave USB ou unidade de backup\n✓ Copie para o seu armazenamento em nuvem pessoal"; -"secrets_setup_recovery_passphrase_title" = "Defina uma Frase de Segurança"; -"secrets_setup_recovery_passphrase_information" = "Digite uma frase de segurança que só você conheça, usada para proteger segredos em seu servidor."; -"secrets_setup_recovery_passphrase_additional_information" = "Não use a senha da sua conta."; -"secrets_setup_recovery_passphrase_confirm_information" = "Digite sua frase de segurança novamente para confirmá-la."; +"secrets_setup_recovery_key_storage_alert_title" = "Mantenha-a segura"; +"secrets_setup_recovery_key_storage_alert_message" = "✓ Imprima-a e armazene-a em algum lugar seguro\n✓ Salve-a em uma chave USB ou drive de backup \n✓ Copie-a para seu armazenamento nuvem pessoal"; +"secrets_setup_recovery_passphrase_title" = "Definir uma Frase de Segurança"; +"secrets_setup_recovery_passphrase_information" = "Entre uma frase de segurança que só você conheça, usada para assegurar segredos em seu servidor."; +"secrets_setup_recovery_passphrase_additional_information" = "Não use a senha de sua conta."; +"secrets_setup_recovery_passphrase_confirm_information" = "Entre sua Frase de Segurança de novo para confirmá-la."; "secrets_setup_recovery_passphrase_confirm_passphrase_title" = "Confirmar"; -"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Confirme a frase secreta"; -"cross_signing_setup_banner_title" = "Configurar a criptografia"; -"cross_signing_setup_banner_subtitle" = "Confirme seus outros aparelhos com mais facilidade"; +"secrets_setup_recovery_passphrase_confirm_passphrase_placeholder" = "Confirmar frase"; +"cross_signing_setup_banner_title" = "Configurar encriptação"; +"cross_signing_setup_banner_subtitle" = "Verifique seus outros dispositivos mais fácil"; "major_update_title" = "Riot agora é Element"; "major_update_learn_more_action" = "Saiba mais"; -"major_update_done_action" = "Ok, entendi"; -"pin_protection_choose_pin" = "Crie um PIN de segurança"; +"major_update_done_action" = "Entendido"; +"pin_protection_choose_pin" = "Crie um PIN por segurança"; "pin_protection_confirm_pin" = "Confirme seu PIN"; -"pin_protection_confirm_pin_to_disable" = "Confirme o PIN para desativar o PIN"; -"pin_protection_enter_pin" = "Digite seu PIN"; -"pin_protection_forgot_pin" = "Esqueci o PIN"; -"pin_protection_reset_alert_title" = "Redefinir o PIN"; -"pin_protection_reset_alert_message" = "Para redefinir seu PIN, você precisará fazer um novo login e em seguida criar um novo PIN"; -"pin_protection_reset_alert_action_reset" = "Redefinir"; -"pin_protection_mismatch_error_title" = "PINs não coincidem"; -"pin_protection_mismatch_error_message" = "Por favor, tente novamente"; -"pin_protection_mismatch_too_many_times_error_message" = "Se você não se lembrar do PIN, toque no botão Esqueci o PIN."; -"pin_protection_settings_section_header_x" = "PIN e %@"; -"pin_protection_settings_section_footer" = "Para redefinir seu PIN, você precisará fazer login novamente e criar um novo PIN."; +"pin_protection_confirm_pin_to_disable" = "Confirme PIN para desativar PIN"; +"pin_protection_enter_pin" = "Entre seu PIN"; +"pin_protection_forgot_pin" = "Esqueci PIN"; +"pin_protection_reset_alert_title" = "Resettar PIN"; +"pin_protection_reset_alert_message" = "Para resettar seu PIN, você vai precisar re-fazer login e criar um novo"; +"pin_protection_reset_alert_action_reset" = "Resettar"; +"pin_protection_mismatch_error_title" = "PINs não correspondem"; +"pin_protection_mismatch_error_message" = "Por favor tente de novo"; +"pin_protection_mismatch_too_many_times_error_message" = "Se você não consegue se lembrar de seu PIN, toque no botão esqueci PIN."; +"pin_protection_settings_section_header_x" = "PIN & %@"; +"pin_protection_settings_section_footer" = "Para resettar seu PIN, você vai precisar re-fazer login e criar um novo."; "biometrics_mode_touch_id" = "Touch ID"; "biometrics_mode_face_id" = "Face ID"; -"biometrics_setup_subtitle" = "Poupe tempo"; +"biometrics_setup_subtitle" = "Poupe a si mesma(o) tempo"; "biometrics_desetup_title_x" = "Desativar %@"; "biometrics_desetup_subtitle" = "biometrics_desetup_subtitle"; "biometrics_desetup_disable_button_title_x" = "Desativar %@"; -"biometrics_usage_reason" = "A autenticação é necessária para acessar seu aplicativo"; -"biometrics_cant_unlocked_alert_title" = "Não foi possível desbloquear o app"; -"biometrics_cant_unlocked_alert_message_login" = "Entrar novamente"; -"biometrics_cant_unlocked_alert_message_retry" = "Tentar novamente"; -"pin_protection_kick_user_alert_message" = "Muitos erros, vocês foi desconectada/o"; -"room_details_advanced_e2e_encryption_disabled_for_dm" = "A criptografia não está ativada nesta sala."; -"room_details_advanced_e2e_encryption_enabled_for_dm" = "A criptografia está ativada nesta sala"; +"biometrics_usage_reason" = "Autenticação é necessitada para acessar seu app"; +"biometrics_cant_unlocked_alert_title" = "Não dá para destrancar app"; +"biometrics_cant_unlocked_alert_message_login" = "Fazer login de volta"; +"biometrics_cant_unlocked_alert_message_retry" = "Retentar"; +"pin_protection_kick_user_alert_message" = "Erros demais, você tem sido feito logout"; +"room_details_advanced_e2e_encryption_disabled_for_dm" = "Encriptação não está ativada aqui."; +"room_details_advanced_e2e_encryption_enabled_for_dm" = "Encriptação está ativada aqui"; "room_details_advanced_room_id_for_dm" = "ID:"; -"room_details_no_local_addresses_for_dm" = "Esta sala não tem endereços locais"; -"room_details_access_section_directory_toggle_for_dm" = "Exibir esta sala na lista pública de salas"; -"room_details_access_section_anyone_for_dm" = "Quem conhece o link da sala, incluindo convidados"; -"room_details_access_section_anyone_apart_from_guest_for_dm" = "Qualquer pessoa que tenha o link da sala, exceto convidados"; -"room_details_access_section_for_dm" = "Quem pode acessar esta sala?"; +"room_details_no_local_addresses_for_dm" = "Isto não tem nenhum endereço local"; +"room_details_access_section_directory_toggle_for_dm" = "Listar em diretório de salas"; +"room_details_access_section_anyone_for_dm" = "Qualquer pessoa que sabe o link, incluindo visitantes"; +"room_details_access_section_anyone_apart_from_guest_for_dm" = "Qualquer pessoa que sabe o link, a parte de visitantes"; +"room_details_access_section_for_dm" = "Quem pode acessar isto?"; "room_details_room_name_for_dm" = "Nome"; "room_details_photo_for_dm" = "Foto"; "room_details_title_for_dm" = "Detalhes"; -"room_participants_security_information_room_encrypted_for_dm" = "As mensagens nesta sala não estão criptografadas de ponta a ponta.\n\nSuas mensagens são protegidas com cadeados, apenas você e o destinatário têm as chaves exclusivas que permitem a leitura das mensagens."; -"room_participants_security_information_room_not_encrypted_for_dm" = "As mensagens nesta sala não estão criptografadas de ponta a ponta."; -"room_participants_filter_room_members_for_dm" = "Pesquisar integrantes da sala"; -"room_participants_leave_prompt_msg_for_dm" = "Deseja mesmo sair?"; +"room_participants_security_information_room_encrypted_for_dm" = "Mensagens aqui são encriptadas ponta-a-ponta.\n\nSuas mensagens são asseguradas com cadeados e somente você e a/o recipiente têm as chaves únicas para os destrancar."; +"room_participants_security_information_room_not_encrypted_for_dm" = "Mensagens aqui não são encriptadas ponta-a-ponta."; +"room_participants_filter_room_members_for_dm" = "Filtrar membros"; +"room_participants_leave_prompt_msg_for_dm" = "Tem certeza que você quer sair?"; "room_participants_leave_prompt_title_for_dm" = "Sair"; -"room_info_list_section_other" = "Outros"; -"room_info_list_several_members" = "%@ integrantes"; +"room_info_list_section_other" = "Outras"; +"room_info_list_several_members" = "%@ membros"; // MARK: - Room Info -"room_info_list_one_member" = "1 integrante"; -"create_room_placeholder_address" = "#saladeteste:matrix.org"; -"create_room_section_header_address" = "Endereço da sala"; -"create_room_show_in_directory" = "Exibir a sala na lista pública de salas"; -"create_room_section_footer_type" = "Pessoas entram em uma sala privada apenas com o convite da sala."; -"create_room_type_public" = "Sala pública"; -"create_room_type_private" = "Sala privada"; +"room_info_list_one_member" = "1 membro"; +"create_room_placeholder_address" = "#salateste:matrix.org"; +"create_room_section_header_address" = "Endereço de sala"; +"create_room_show_in_directory" = "Mostrar a sala no diretório"; +"create_room_section_footer_type" = "Pessoas se juntam a uma sala privada somente com o convite da sala."; +"create_room_type_public" = "Sala Pública"; +"create_room_type_private" = "Sala Privada"; "create_room_section_header_type" = "Tipo de sala"; -"create_room_section_footer_encryption" = "A criptografia não poderá ser desativada posteriormente."; -"create_room_enable_encryption" = "Ativar criptografia"; -"create_room_section_header_encryption" = "Criptografia da sala"; -"create_room_placeholder_topic" = "Descrição"; -"create_room_section_header_topic" = "Descrição da sala (opcional)"; +"create_room_section_footer_encryption" = "Encriptação não pode ser desativada em seguida."; +"create_room_enable_encryption" = "Ativar Encriptação"; +"create_room_section_header_encryption" = "Encriptação de sala"; +"create_room_placeholder_topic" = "Tópico"; +"create_room_section_header_topic" = "Tópico de sala (opcional)"; "create_room_placeholder_name" = "Nome"; -"create_room_section_header_name" = "Nome da sala"; +"create_room_section_header_name" = "Nome de sala"; // MARK: - Create Room -"create_room_title" = "Nova sala"; +"create_room_title" = "Nova Sala"; "searchable_directory_search_placeholder" = "Nome ou ID"; "searchable_directory_x_network" = "Rede %@"; // MARK: - Searchable Directory View Controller "searchable_directory_create_new_room" = "Criar uma nova sala"; -"pin_protection_explanatory" = "Configurar um PIN permite que você proteja dados como mensagens e contatos, de forma que somente você possa acessá-los inserindo o PIN ao iniciar o aplicativo."; -"pin_protection_not_allowed_pin" = "Por motivos de segurança, este PIN não está disponível. Por favor, escolha outra PIN"; -"pin_protection_choose_pin_welcome_after_register" = "Boas-vindas."; -"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Procurando outras possibilidades de confirmação..."; +"pin_protection_explanatory" = "Configurar um PIN permite você proteger dados como mensagens e contatos, para que somente você possa acessá-los entrando o PIN no início do app."; +"pin_protection_not_allowed_pin" = "Por razões de segurança, este PIN não está disponível. Por favor tente um outro PIN"; +"pin_protection_choose_pin_welcome_after_register" = "Boas vindas."; +"device_verification_self_verify_wait_recover_secrets_checking_availability" = "Checando por outras capabilidades de verificação ..."; // MARK: - PIN Protection -"pin_protection_choose_pin_welcome_after_login" = "Bem-vindo de volta."; +"pin_protection_choose_pin_welcome_after_login" = "Boas vindas de volta."; "more" = "Mais"; -"switch" = "Alterar"; -"joined" = "Entrou"; -"secrets_reset_authentication_message" = "Digite a senha da sua conta para confirmar"; -"secrets_reset_reset_action" = "Redefinir"; -"secrets_reset_warning_message" = "Você não terá mais o histórico de mensagens, aparelhos confiáveis e contatos confirmados."; -"secrets_reset_warning_title" = "Se você redefinir tudo"; -"secrets_reset_information" = "Apenas faça isso se você não tiver outro aparelho para confirmar este aparelho."; +"switch" = "Trocar"; +"joined" = "Juntou-Se"; +"secrets_reset_authentication_message" = "Entre a senha de sua conta para confirmar"; +"secrets_reset_reset_action" = "Resettar"; +"secrets_reset_warning_message" = "Você vai recomeçar com nada de histórico, mensagens, dispositivos confiados ou usuárias(os) confiadas(os)."; +"secrets_reset_warning_title" = "Se você resettar tudo"; +"secrets_reset_information" = "Somente faça isto se você não tem nenhum outro dispositivo com o qual você pode verificar este dispositivo."; // MARK: - Secrets reset -"secrets_reset_title" = "Remover tudo"; +"secrets_reset_title" = "Resettar tudo"; // MARK: - Secrets recovery -"secrets_recovery_reset_action_part_1" = "Esqueceu as senhas ou perdeu todas opções de recuperação? "; +"secrets_recovery_reset_action_part_1" = "Esqueceu ou perdeu todas opções de recuperação? "; "less" = "Menos"; -"secrets_recovery_reset_action_part_2" = "Redefinir tudo"; -"secrets_setup_recovery_passphrase_summary_information" = "Lembre-se da sua frase de segurança. Ela pode ser usada para desbloquear suas mensagens e dados criptografados."; -"secrets_setup_recovery_passphrase_summary_title" = "Salve a sua frase de segurança"; -"home_empty_view_information" = "O aplicativo de conversas seguro e completo para equipes, amigos e organizações. Toque no botão + abaixo para adicionar pessoas e salas."; +"secrets_recovery_reset_action_part_2" = "Resettar tudo"; +"secrets_setup_recovery_passphrase_summary_information" = "Lembre-se de sua Frase de Segurança. Ela pode ser usada para destrancar suas mensagens & dados encriptados."; +"secrets_setup_recovery_passphrase_summary_title" = "Salvar sua Frase de Segurança"; +"home_empty_view_information" = "O app de chat seguro tudo-em-um para equipes, amigas(os) e organizações. Toque no botão + abaixo para adicionar pessoas e salas."; // MARK: - Home -"home_empty_view_title" = "Boas-vindas ao %@,\n%@"; +"home_empty_view_title" = "Boas vindas a %@,\n%@"; "people_empty_view_title" = "Pessoas"; -"favourites_empty_view_information" = "Você pode adicionar aos favoritos de algumas maneiras - a mais rápida é simplesmente pressionar e segurar. Toque na estrela e eles aparecerão automaticamente aqui, para fins de segurança."; +"favourites_empty_view_information" = "Você pode favoritar de algumas formas - a mais rápida é só pressionar e segurar. Toque na estrela e elas vão automaticamente aparecer aqui para mantimento seguro."; // MARK: - Favourites -"favourites_empty_view_title" = "Salas e pessoas favoritas"; -"rooms_empty_view_information" = "Salas são ótimas para qualquer conversa em grupo, privada ou pública. Toque em + para encontrar salas existentes ou crie novas."; +"favourites_empty_view_title" = "Favoritar salas e pessoas"; +"rooms_empty_view_information" = "Salas são ótimas para qualquer chat de grupo, privado ou público. Toque no + para encontrar salas existentes, ou criar umas novas."; "rooms_empty_view_title" = "Salas"; -"people_empty_view_information" = "Converse com segurança com qualquer pessoa. Toque em + para começar a adicionar pessoas."; -"invite_friends_share_text" = "Ei, converse comigo no %@: %@"; +"people_empty_view_information" = "Faça chat seguramene com qualquer pessoa. Toque no + para começar a adicionar pessoas."; +"invite_friends_share_text" = "Hey, fale comigo em %@: %@"; // MARK: - Invite friends -"invite_friends_action" = "Convidar amigos para o %@"; -"pin_protection_settings_change_pin" = "Alterar o PIN"; -"pin_protection_confirm_pin_to_change" = "Confirme o PIN para alterá-lo"; -"bug_report_background_mode" = "Continuar em segundo plano"; -"social_login_button_title_sign_up" = "Registrar-se com %@"; -"social_login_button_title_sign_in" = "Entrar com %@"; +"invite_friends_action" = "Convidar amigas(os) para %@"; +"pin_protection_settings_change_pin" = "Mudar PIN"; +"pin_protection_confirm_pin_to_change" = "Confirme PIN para mudar PIN"; +"bug_report_background_mode" = "Continuar em background"; +"social_login_button_title_sign_up" = "Registrar-Se com %@"; +"social_login_button_title_sign_in" = "Fazer Signin com %@"; "social_login_button_title_continue" = "Continuar com %@"; "social_login_list_title_sign_up" = "Ou"; "social_login_list_title_sign_in" = "Ou"; @@ -1266,55 +1266,117 @@ // Social login "social_login_list_title_continue" = "Continuar com"; -"room_avatar_view_accessibility_hint" = "Alterar a imagem da sala"; +"room_avatar_view_accessibility_hint" = "Mudar avatar de sala"; // Mark: - Room avatar view -"room_avatar_view_accessibility_label" = "imagem"; +"room_avatar_view_accessibility_label" = "avatar"; "call_transfer_contacts_all" = "Todos"; -"call_transfer_contacts_recent" = "Recente"; -"call_transfer_users" = "Pessoas"; -"event_formatter_call_has_ended" = "Essa chamada foi encerrada"; -"room_intro_cell_information_multiple_dm_sentence2" = "Somente vocês estão nesta conversa, ao menos até que convidem alguém para participar."; -"room_intro_cell_information_dm_sentence2" = "Apenas vocês dois/duas estão nesta conversa, ninguém mais pode entrar."; +"call_transfer_contacts_recent" = "Recentes"; +"call_transfer_users" = "Usuárias(os)"; +"event_formatter_call_has_ended" = "Terminou %@"; +"room_intro_cell_information_multiple_dm_sentence2" = "Somente vocês estão nesta conversa, a menos que algum(a) de você convide alguém para se juntar."; +"room_intro_cell_information_dm_sentence2" = "Somente vocês dois/duas estão nesta conversa, ninguém mais pode juntar-se."; "room_intro_cell_information_dm_sentence1_part3" = ". "; -"room_intro_cell_information_dm_sentence1_part1" = "Este é o início de sua conversa com "; -"room_intro_cell_information_room_without_topic_sentence2_part2" = " para que as pessoas saibam do que se trata essa sala."; -"room_intro_cell_information_room_without_topic_sentence2_part1" = "Adicionar uma descrição"; -"room_intro_cell_information_room_with_topic_sentence2" = "Descrição: %@"; +"room_intro_cell_information_dm_sentence1_part1" = "Este é o começo de sua mensagem direta com "; +"room_intro_cell_information_room_without_topic_sentence2_part2" = " para deixar pessoas saberem do que esta sala se trata."; +"room_intro_cell_information_room_without_topic_sentence2_part1" = "Adicionar um tópico"; +"room_intro_cell_information_room_with_topic_sentence2" = "Tópico: %@"; "room_intro_cell_information_room_sentence1_part3" = ". "; "room_intro_cell_information_room_sentence1_part1" = "Este é o começo de "; // Mark: - Room creation introduction cell "room_intro_cell_add_participants_action" = "Adicionar pessoas"; -"call_transfer_error_message" = "Falha ao transferir a chamada"; +"call_transfer_error_message" = "Transferência de chamada falhou"; "call_transfer_error_title" = "Erro"; -"call_transfer_dialpad" = "Teclado de discagem"; +"call_transfer_dialpad" = "Pad de disco"; // MARK: - Call Transfer "call_transfer_title" = "Transferir"; // MARK: - Dial Pad -"dialpad_title" = "Teclado de discagem"; +"dialpad_title" = "Pad de disco"; "call_actions_unhold" = "Retomar"; "event_formatter_call_back" = "Ligar de volta"; -"event_formatter_call_you_declined" = "Você recusou esta chamada"; -"event_formatter_call_you_currently_in" = "Você está nesta chamada"; +"event_formatter_call_you_declined" = "Você declinou esta chamada"; +"event_formatter_call_you_currently_in" = "Chamada ativa"; "event_formatter_call_video" = "Chamada de vídeo"; "event_formatter_call_voice" = "Chamada de voz"; -"settings_show_NSFW_public_rooms" = "Exibir salas públicas com conteúdo sensível"; -"room_open_dialpad" = "Teclado de discagem"; +"settings_show_NSFW_public_rooms" = "Mostrar salas públicas NSFW"; +"room_open_dialpad" = "Pad de disco"; "room_place_voice_call" = "Chamada de voz"; -"room_event_action_delete_confirmation_message" = "Tem certeza de que deseja excluir esta mensagem não enviada?"; -"room_event_action_delete_confirmation_title" = "Excluir mensagem não enviada"; -"room_unsent_messages_cancel_message" = "Tem certeza de que deseja excluir todas as mensagens não enviadas nesta sala?"; -"room_unsent_messages_cancel_title" = "Excluir mensagens não enviadas"; +"room_event_action_delete_confirmation_message" = "Você tem certeza que você quer deletar esta mensagem não-enviada?"; +"room_event_action_delete_confirmation_title" = "Deletar mensagem não-enviada"; +"room_unsent_messages_cancel_message" = "Tem certeza que você quer deletar todas as mensagens não-enviadas nesta sala?"; +"room_unsent_messages_cancel_title" = "Deletar mensagens não-enviadas"; "callbar_return" = "Retornar"; "callbar_only_multiple_paused" = "%@ chamadas pausadas"; "callbar_only_single_paused" = "Chamada pausada"; -"callbar_active_and_multiple_paused" = "1 chamada em andamento (%@) · %@ chamadas pausadas"; -"callbar_active_and_single_paused" = "1 chamada em andamento (%@) · 1 chamada pausada"; +"callbar_active_and_multiple_paused" = "1 chamada ativa (%@) · %@ chamadas pausadas"; +"callbar_active_and_single_paused" = "1 chamada ativa (%@) · 1 chamada pausada"; // Call Bar -"callbar_only_single_active" = "Chamada em andamento (%@)"; +"callbar_only_single_active" = "Toque para retornar à chamada (%@)"; +"room_message_replying_to" = "Respondendo a %@"; +"room_message_editing" = "Editando"; + +// Chat +"room_slide_to_end_group_call" = "Deslizar para terminar a chamada para todas as pessoas"; +"callbar_only_single_active_group" = "Toque para Juntar-Se à chamada de grupo (%@)"; +"room_details_integrations" = "Integrações"; +"room_details_search" = "Pesquisar sala"; +"settings_labs_enable_ringing_for_group_calls" = "Toque para chamadas de grupo"; +"room_multiple_typing_notification" = "%@ e outras(os)"; +"room_no_privileges_to_create_group_call" = "Você precisa ser um/uma admin ou um/uma moderador(a) para começar uma chamada."; +"room_join_group_call" = "Juntar-se"; +"room_accessibility_video_call" = "Chamar por Vídeo"; +"space_beta_announce_information" = "Espaços são uma nova forma de agrupar salas e pessoas. Eles não estão em iOS ainda, mas você pode usá-los agora em Web e Desktop."; +"space_beta_announce_subtitle" = "A nova versão de comunidades"; +"space_beta_announce_title" = "Espaços estão vindo logo"; +"space_beta_announce_badge" = "BETA"; +"space_feature_unavailable_information" = "Espaços são uma nova forma de agrupar salas e pessoas.\n\nEles vão está aqui logo. Por enquanto, se você se juntar a um numa outra plataforma, você vai poder acessar quaisquer salas que você se juntar aqui."; +"space_feature_unavailable_subtitle" = "Espaços não estão em iOS ainda, mas você pode usá-los agora em Web e Desktop"; + +// Mark: - Spaces + +"space_feature_unavailable_title" = "Espaços não estão aqui ainda"; +"event_formatter_group_call_incoming" = "%@ em %@"; +"event_formatter_group_call_leave" = "Sair"; +"event_formatter_group_call_join" = "Juntar-se"; +"event_formatter_group_call" = "Chamada de grupo"; +"event_formatter_call_end_call" = "Terminar chamada"; +"event_formatter_call_retry" = "Retentar"; +"event_formatter_call_answer" = "Atender"; +"event_formatter_call_decline" = "Declinar"; +"event_formatter_call_connection_failed" = "Conexão falhou"; +"event_formatter_call_you_missed" = "Você perdeu esta chamada"; +"event_formatter_call_ringing" = "Tocando…"; +"event_formatter_call_connecting" = "Conectando…"; +"side_menu_app_version" = "Versão %@"; +"side_menu_action_feedback" = "Feedback"; +"side_menu_action_help" = "Ajuda"; +"side_menu_action_settings" = "Configurações"; +"side_menu_action_invite_friends" = "Convidar amigas(os)"; + +// Mark: - Side menu + +"side_menu_reveal_action_accessibility_label" = "Painel esquerdo"; +"user_avatar_view_accessibility_hint" = "Mudar avatar de usuária(o)"; + +// Mark: - User avatar view + +"user_avatar_view_accessibility_label" = "avatar"; +"secrets_recovery_with_key_information_unlock_secure_backup_with_key" = "Entre sua Chave de Segurança para continuar."; +"secrets_recovery_with_key_information_unlock_secure_backup_with_phrase" = "Entre sua Frase de Segurança para continuar."; + +// Success from secure backup +"key_backup_setup_success_from_secure_backup_info" = "Backup de suas chaves está sendo feito."; +"security_settings_secure_backup_restore" = "Restaurar de Backup"; +"security_settings_secure_backup_reset" = "Resettar"; +"security_settings_secure_backup_info_valid" = "Esta sessão está fazendo backup de suas chaves."; +"security_settings_secure_backup_info_checking" = "Checando…"; +"settings_ui_theme_picker_message_match_system_theme" = "\"Auto\" corresponde ao tema de sistema de seu dispositivo"; +"settings_ui_theme_picker_message_invert_colours" = "\"Auto\" usa as configurações \"Inverter Cores\" de seu dispositivo"; +"room_recents_unknown_room_error_message" = "Não dá para encontrar esta sala. Assegure que ela existe"; +"room_creation_dm_error" = "Nós não conseguimos criar sua DM. Por favor cheque as/os usuárias(os) que você quer convidar e tente de novo."; diff --git a/Riot/Assets/sv.lproj/Vector.strings b/Riot/Assets/sv.lproj/Vector.strings index 4ee654d30..d9b1a77a0 100644 --- a/Riot/Assets/sv.lproj/Vector.strings +++ b/Riot/Assets/sv.lproj/Vector.strings @@ -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."; diff --git a/Riot/Assets/th.lproj/Vector.strings b/Riot/Assets/th.lproj/Vector.strings index 11b90cf2d..0d59593dc 100644 --- a/Riot/Assets/th.lproj/Vector.strings +++ b/Riot/Assets/th.lproj/Vector.strings @@ -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" = "เพิ่มเติม"; diff --git a/Riot/Assets/third_party_licenses.html b/Riot/Assets/third_party_licenses.html index c7d99a22c..4dfc32ac7 100644 --- a/Riot/Assets/third_party_licenses.html +++ b/Riot/Assets/third_party_licenses.html @@ -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. +

+
  • + SideMenu (https://github.com/jonkykong/SideMenu/) +

    + Copyright (c) 2015 Jonathan Kent +

    + 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: +

    + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +

    + 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. +

    +
  • diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index 86ac88f2e..ae376f7cf 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -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" = "Безпечно спілкуйтеся з будь-ким. Торкніться +, щоб додати співрозмовників."; diff --git a/Riot/Assets/zh_Hans.lproj/Vector.strings b/Riot/Assets/zh_Hans.lproj/Vector.strings index 7621e4bb4..43a665081 100644 --- a/Riot/Assets/zh_Hans.lproj/Vector.strings +++ b/Riot/Assets/zh_Hans.lproj/Vector.strings @@ -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。 请检查您要邀请的用户,然后重试。"; diff --git a/Riot/Categories/MXSession+Riot.h b/Riot/Categories/MXSession+Riot.h index d5fe928de..168511ec2 100644 --- a/Riot/Categories/MXSession+Riot.h +++ b/Riot/Categories/MXSession+Riot.h @@ -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 diff --git a/Riot/Categories/MXSession+Riot.m b/Riot/Categories/MXSession+Riot.m index 1cc498024..901c58406 100644 --- a/Riot/Categories/MXSession+Riot.m +++ b/Riot/Categories/MXSession+Riot.m @@ -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 diff --git a/Riot/Categories/UIButton.swift b/Riot/Categories/UIButton.swift index 0e3af78ef..6f896bb58 100644 --- a/Riot/Categories/UIButton.swift +++ b/Riot/Categories/UIButton.swift @@ -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 + } + } } diff --git a/Riot/Categories/UIView.swift b/Riot/Categories/UIView.swift index 9edde2c23..b36d73bb6 100644 --- a/Riot/Categories/UIView.swift +++ b/Riot/Categories/UIView.swift @@ -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) diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index 08f3dbdf8..836c561d0 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -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") diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift index 8e7290c1a..c66d40f6a 100644 --- a/Riot/Generated/Storyboards.swift +++ b/Riot/Generated/Storyboards.swift @@ -97,6 +97,11 @@ internal enum StoryboardScene { internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromRecoveryKeyViewController.self) } + internal enum KeyBackupSetupSuccessFromSecureBackupViewController: StoryboardType { + internal static let storyboardName = "KeyBackupSetupSuccessFromSecureBackupViewController" + + internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromSecureBackupViewController.self) + } internal enum KeyVerificationDataLoadingViewController: StoryboardType { internal static let storyboardName = "KeyVerificationDataLoadingViewController" @@ -224,6 +229,11 @@ internal enum StoryboardScene { internal static let searchableDirectoryViewController = SceneType(storyboard: ShowDirectoryViewController.self, identifier: "SearchableDirectoryViewController") } + internal enum SideMenuViewController: StoryboardType { + internal static let storyboardName = "SideMenuViewController" + + internal static let initialScene = InitialSceneType(storyboard: SideMenuViewController.self) + } internal enum SimpleScreenTemplateViewController: StoryboardType { internal static let storyboardName = "SimpleScreenTemplateViewController" diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 8a7a8bae0..ba05c0233 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -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") diff --git a/Riot/Managers/AppInfo/AppInfo.swift b/Riot/Managers/AppInfo/AppInfo.swift new file mode 100644 index 000000000..457a7af87 --- /dev/null +++ b/Riot/Managers/AppInfo/AppInfo.swift @@ -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 + } +} diff --git a/Riot/Managers/AppVersion/AppVersion.swift b/Riot/Managers/AppInfo/AppVersion.swift similarity index 100% rename from Riot/Managers/AppVersion/AppVersion.swift rename to Riot/Managers/AppInfo/AppVersion.swift diff --git a/Riot/Managers/AppInfo/BuildInfo.h b/Riot/Managers/AppInfo/BuildInfo.h new file mode 100644 index 000000000..8817b6c41 --- /dev/null +++ b/Riot/Managers/AppInfo/BuildInfo.h @@ -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 + +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 diff --git a/Riot/Managers/AppInfo/BuildInfo.m b/Riot/Managers/AppInfo/BuildInfo.m new file mode 100644 index 000000000..b97e9fd2f --- /dev/null +++ b/Riot/Managers/AppInfo/BuildInfo.m @@ -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 diff --git a/Riot/Managers/Call/CallPresenter.swift b/Riot/Managers/Call/CallPresenter.swift index e3b4f6e31..4f5ad7e13 100644 --- a/Riot/Managers/Call/CallPresenter.swift +++ b/Riot/Managers/Call/CallPresenter.swift @@ -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 { diff --git a/Riot/Managers/Call/CallPresenterDelegate.swift b/Riot/Managers/Call/CallPresenterDelegate.swift index 57ee1c941..9c7f44687 100644 --- a/Riot/Managers/Call/CallPresenterDelegate.swift +++ b/Riot/Managers/Call/CallPresenterDelegate.swift @@ -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, diff --git a/Riot/Managers/Call/Operations/CallBarPresentOperation.swift b/Riot/Managers/Call/Operations/CallBarPresentOperation.swift deleted file mode 100644 index 31ec542f1..000000000 --- a/Riot/Managers/Call/Operations/CallBarPresentOperation.swift +++ /dev/null @@ -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?() - } - }) - } - -} diff --git a/Riot/Managers/Call/Operations/CallBarUpdateOperation.swift b/Riot/Managers/Call/Operations/CallBarUpdateOperation.swift deleted file mode 100644 index 23c7a5f5d..000000000 --- a/Riot/Managers/Call/Operations/CallBarUpdateOperation.swift +++ /dev/null @@ -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() - } - -} diff --git a/Riot/Managers/Call/Operations/CallVCPresentOperation.swift b/Riot/Managers/Call/Operations/CallVCPresentOperation.swift index fae80e51b..ce452d575 100644 --- a/Riot/Managers/Call/Operations/CallVCPresentOperation.swift +++ b/Riot/Managers/Call/Operations/CallVCPresentOperation.swift @@ -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?() }) } diff --git a/Riot/Managers/Call/PiPAnimator.swift b/Riot/Managers/Call/PiPAnimator.swift index 46171be6d..7df05af53 100644 --- a/Riot/Managers/Call/PiPAnimator.swift +++ b/Riot/Managers/Call/PiPAnimator.swift @@ -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) diff --git a/Riot/Managers/Call/PictureInPicturable.swift b/Riot/Managers/Call/PictureInPicturable.swift index b8ee9ae05..c37a904e8 100644 --- a/Riot/Managers/Call/PictureInPicturable.swift +++ b/Riot/Managers/Call/PictureInPicturable.swift @@ -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() } diff --git a/Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift b/Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift index 168dad3cb..3203fdf11 100644 --- a/Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift +++ b/Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift @@ -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 } diff --git a/Riot/Managers/PushNotification/PushNotificationService.m b/Riot/Managers/PushNotification/PushNotificationService.m index 350cd564f..bef062452 100644 --- a/Riot/Managers/PushNotification/PushNotificationService.m +++ b/Riot/Managers/PushNotification/PushNotificationService.m @@ -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(); diff --git a/Riot/Managers/UserSessions/UserSessionsService.swift b/Riot/Managers/UserSessions/UserSessionsService.swift index cd79fbd92..19d9b05fa 100644 --- a/Riot/Managers/UserSessions/UserSessionsService.swift +++ b/Riot/Managers/UserSessions/UserSessionsService.swift @@ -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 diff --git a/Riot/Modules/Application/AppAlertPresenter.swift b/Riot/Modules/Application/AppAlertPresenter.swift new file mode 100644 index 000000000..f60a5ef34 --- /dev/null +++ b/Riot/Modules/Application/AppAlertPresenter.swift @@ -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) + } +} diff --git a/Riot/Modules/Application/AppCoordinator.swift b/Riot/Modules/Application/AppCoordinator.swift index 3b69cc6e5..4469fbbfa 100755 --- a/Riot/Modules/Application/AppCoordinator.swift +++ b/Riot/Modules/Application/AppCoordinator.swift @@ -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) + } +} diff --git a/Riot/Modules/Application/AppDelegate.swift b/Riot/Modules/Application/AppDelegate.swift index 5a54a63b0..5ab09997b 100644 --- a/Riot/Modules/Application/AppDelegate.swift +++ b/Riot/Modules/Application/AppDelegate.swift @@ -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 diff --git a/Riot/Modules/Application/LegacyAppDelegate.h b/Riot/Modules/Application/LegacyAppDelegate.h index 076dcb45f..78269f348 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.h +++ b/Riot/Modules/Application/LegacyAppDelegate.h @@ -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 /** diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 9158de0df..ff81e5f57 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -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 () +@interface LegacyAppDelegate () { /** 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 diff --git a/Riot/Modules/Call/CallViewController.m b/Riot/Modules/Call/CallViewController.m index 631936080..9fc8596e5 100644 --- a/Riot/Modules/Call/CallViewController.m +++ b/Riot/Modules/Call/CallViewController.m @@ -37,8 +37,11 @@ BOOL promptForStunServerFallback; } +@property (nonatomic, weak) IBOutlet UIView *pipViewContainer; + @property (nonatomic, strong) id 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; } diff --git a/Riot/Modules/Call/CallViewController.xib b/Riot/Modules/Call/CallViewController.xib index d5cf47f3c..1f1c991a7 100644 --- a/Riot/Modules/Call/CallViewController.xib +++ b/Riot/Modules/Call/CallViewController.xib @@ -1,9 +1,9 @@ - + - + @@ -35,6 +35,7 @@ + @@ -294,7 +295,7 @@ - + @@ -339,7 +340,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.swift b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.swift new file mode 100644 index 000000000..c369cb5e9 --- /dev/null +++ b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromSecureBackupViewController.swift @@ -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) + } +} diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift index 7188a111e..8db3b8c04 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift @@ -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() { diff --git a/Riot/Modules/Room/Views/Avatar/RoomAvatarView.swift b/Riot/Modules/Room/Views/Avatar/RoomAvatarView.swift index e23add9c7..1b4612a36 100644 --- a/Riot/Modules/Room/Views/Avatar/RoomAvatarView.swift +++ b/Riot/Modules/Room/Views/Avatar/RoomAvatarView.swift @@ -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 - } - } } diff --git a/Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift b/Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift index 82185499c..bf6f4888d 100644 --- a/Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift +++ b/Riot/Modules/Room/Views/Avatar/RoomAvatarViewData.swift @@ -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 + } } diff --git a/Riot/Modules/Room/Views/BubbleCells/Call/Direct/RoomDirectCallStatusBubbleCell.swift b/Riot/Modules/Room/Views/BubbleCells/Call/Direct/RoomDirectCallStatusBubbleCell.swift index a3dbb63dc..6e6a1c42b 100644 --- a/Riot/Modules/Room/Views/BubbleCells/Call/Direct/RoomDirectCallStatusBubbleCell.swift +++ b/Riot/Modules/Room/Views/BubbleCells/Call/Direct/RoomDirectCallStatusBubbleCell.swift @@ -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 } diff --git a/Riot/Modules/Room/Views/BubbleCells/RoomCreationIntro/RoomCreationIntroCell.swift b/Riot/Modules/Room/Views/BubbleCells/RoomCreationIntro/RoomCreationIntroCell.swift index d0204a410..f53c943c2 100644 --- a/Riot/Modules/Room/Views/BubbleCells/RoomCreationIntro/RoomCreationIntroCell.swift +++ b/Riot/Modules/Room/Views/BubbleCells/RoomCreationIntro/RoomCreationIntroCell.swift @@ -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) diff --git a/Riot/Modules/Rooms/RoomsDirectoryCoordinator.swift b/Riot/Modules/Rooms/RoomsDirectoryCoordinator.swift index 5dbedb6e5..b1cc53b6e 100644 --- a/Riot/Modules/Rooms/RoomsDirectoryCoordinator.swift +++ b/Riot/Modules/Rooms/RoomsDirectoryCoordinator.swift @@ -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) + } } diff --git a/Riot/Modules/Rooms/RoomsDirectoryCoordinatorBridgePresenter.swift b/Riot/Modules/Rooms/RoomsDirectoryCoordinatorBridgePresenter.swift index 27ae84475..2edd0aaa3 100644 --- a/Riot/Modules/Rooms/RoomsDirectoryCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Rooms/RoomsDirectoryCoordinatorBridgePresenter.swift @@ -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 diff --git a/Riot/Modules/Rooms/RoomsDirectoryCoordinatorType.swift b/Riot/Modules/Rooms/RoomsDirectoryCoordinatorType.swift index 4838e1413..a33788a44 100644 --- a/Riot/Modules/Rooms/RoomsDirectoryCoordinatorType.swift +++ b/Riot/Modules/Rooms/RoomsDirectoryCoordinatorType.swift @@ -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. diff --git a/Riot/Modules/Rooms/ShowDirectory/Cells/Network/DirectoryNetworkTableHeaderFooterView.xib b/Riot/Modules/Rooms/ShowDirectory/Cells/Network/DirectoryNetworkTableHeaderFooterView.xib index cd6361ae3..ce0471da3 100644 --- a/Riot/Modules/Rooms/ShowDirectory/Cells/Network/DirectoryNetworkTableHeaderFooterView.xib +++ b/Riot/Modules/Rooms/ShowDirectory/Cells/Network/DirectoryNetworkTableHeaderFooterView.xib @@ -1,9 +1,9 @@ - + - + @@ -11,20 +11,20 @@ - + - + - + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/SideMenu/SideMenuCoordinator.swift b/Riot/Modules/SideMenu/SideMenuCoordinator.swift new file mode 100644 index 000000000..13414e382 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuCoordinator.swift @@ -0,0 +1,181 @@ +// File created from ScreenTemplate +// $ createScreen.sh SideMenu SideMenu +/* + 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 UIKit +import SideMenu +import SafariServices + +class SideMenuCoordinatorParameters { + let userSessionsService: UserSessionsService + let appInfo: AppInfo + + init(userSessionsService: UserSessionsService, appInfo: AppInfo) { + self.userSessionsService = userSessionsService + self.appInfo = appInfo + } +} + +final class SideMenuCoordinator: SideMenuCoordinatorType { + + // MARK: - Properties + + // MARK: Private + + private let parameters: SideMenuCoordinatorParameters + private var sideMenuViewModel: SideMenuViewModelType + + private lazy var sideMenuNavigationViewController: SideMenuNavigationController = { + return self.createSideMenuNavigationController(with: self.sideMenuViewController) + }() + + private let sideMenuViewController: SideMenuViewController + + // MARK: Public + + // Must be used only internally + var childCoordinators: [Coordinator] = [] + + weak var delegate: SideMenuCoordinatorDelegate? + + // MARK: - Setup + + init(parameters: SideMenuCoordinatorParameters) { + self.parameters = parameters + + let sideMenuViewModel = SideMenuViewModel(userSessionsService: self.parameters.userSessionsService, appInfo: parameters.appInfo) + self.sideMenuViewController = SideMenuViewController.instantiate(with: sideMenuViewModel) + self.sideMenuViewModel = sideMenuViewModel + } + + // MARK: - Public methods + + func start() { + self.sideMenuViewModel.coordinatorDelegate = self + + self.sideMenuNavigationViewController.sideMenuDelegate = self + + // Set the sideMenuNavigationViewController as default left menu + SideMenuManager.default.leftMenuNavigationController = self.sideMenuNavigationViewController + } + + func toPresentable() -> UIViewController { + return self.sideMenuNavigationViewController + } + + @discardableResult func addScreenEdgePanGesturesToPresent(to view: UIView) -> UIScreenEdgePanGestureRecognizer { + return self.sideMenuNavigationViewController.sideMenuManager.addScreenEdgePanGesturesToPresent(toView: view, forMenu: .left) + } + + @discardableResult func addPanGestureToPresent(to view: UIView) -> UIPanGestureRecognizer { + return self.sideMenuNavigationViewController.sideMenuManager.addPanGestureToPresent(toView: view) + } + + // MARK: - Private + + private func createSideMenuNavigationController(with rootViewController: UIViewController) -> SideMenuNavigationController { + + var sideMenuSettings = SideMenuSettings() + sideMenuSettings.presentationStyle = .viewSlideOut + + let navigationController = SideMenuNavigationController(rootViewController: rootViewController, settings: sideMenuSettings) + + // Present side menu to the left + navigationController.leftSide = true + + return navigationController + } + + private func createSettingsViewController() -> SettingsViewController { + let viewController: SettingsViewController = SettingsViewController.instantiate() + viewController.loadViewIfNeeded() + return viewController + } + + private func showSettings() { + let viewController = self.createSettingsViewController() + + // Push view controller and dismiss side menu + self.sideMenuNavigationViewController.pushViewController(viewController, animated: true) + } + + private func showBugReport() { + let bugReportViewController = BugReportViewController() + + // Show in fullscreen to animate presentation along side menu dismiss + bugReportViewController.modalPresentationStyle = .fullScreen + bugReportViewController.modalTransitionStyle = .crossDissolve + + self.sideMenuNavigationViewController.present(bugReportViewController, animated: true) + } + + private func showHelp() { + guard let helpURL = URL(string: BuildSettings.applicationHelpUrlString) else { + return + } + + let safariViewController = SFSafariViewController(url: helpURL) + + // Show in fullscreen to animate presentation along side menu dismiss + safariViewController.modalPresentationStyle = .fullScreen + self.sideMenuNavigationViewController.present(safariViewController, animated: true, completion: nil) + } + + private func showInviteFriends(from sourceView: UIView?) { + let myUserId = self.parameters.userSessionsService.mainUserSession?.userId ?? "" + + let inviteFriendsPresenter = InviteFriendsPresenter() + inviteFriendsPresenter.present(for: myUserId, from: self.sideMenuViewController, sourceView: sourceView, animated: true) + } +} + +// MARK: - SideMenuViewModelCoordinatorDelegate +extension SideMenuCoordinator: SideMenuViewModelCoordinatorDelegate { + + func sideMenuViewModel(_ viewModel: SideMenuViewModelType, didTapMenuItem menuItem: SideMenuItem, fromSourceView sourceView: UIView) { + + switch menuItem { + case .inviteFriends: + self.showInviteFriends(from: sourceView) + case .settings: + self.showSettings() + case .help: + self.showHelp() + case .feedback: + self.showBugReport() + } + + self.delegate?.sideMenuCoordinator(self, didTapMenuItem: menuItem, fromSourceView: sourceView) + } +} + +// MARK: - SideMenuNavigationControllerDelegate +extension SideMenuCoordinator: SideMenuNavigationControllerDelegate { + + func sideMenuWillAppear(menu: SideMenuNavigationController, animated: Bool) { + } + + func sideMenuDidAppear(menu: SideMenuNavigationController, animated: Bool) { + } + + func sideMenuWillDisappear(menu: SideMenuNavigationController, animated: Bool) { + } + + func sideMenuDidDisappear(menu: SideMenuNavigationController, animated: Bool) { + } +} diff --git a/Riot/Modules/SideMenu/SideMenuCoordinatorType.swift b/Riot/Modules/SideMenu/SideMenuCoordinatorType.swift new file mode 100644 index 000000000..f193c5a73 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuCoordinatorType.swift @@ -0,0 +1,31 @@ +// File created from ScreenTemplate +// $ createScreen.sh SideMenu SideMenu +/* + 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 + +protocol SideMenuCoordinatorDelegate: class { + func sideMenuCoordinator(_ coordinator: SideMenuCoordinatorType, didTapMenuItem menuItem: SideMenuItem, fromSourceView sourceView: UIView) +} + +/// `SideMenuCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. +protocol SideMenuCoordinatorType: Coordinator, Presentable { + var delegate: SideMenuCoordinatorDelegate? { get } + + @discardableResult func addScreenEdgePanGesturesToPresent(to view: UIView) -> UIScreenEdgePanGestureRecognizer + @discardableResult func addPanGestureToPresent(to view: UIView) -> UIPanGestureRecognizer +} diff --git a/Riot/Modules/SideMenu/SideMenuItem.swift b/Riot/Modules/SideMenu/SideMenuItem.swift new file mode 100644 index 000000000..9d522dec1 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuItem.swift @@ -0,0 +1,62 @@ +// +// 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 + +/// SideMenuItem represents side menu actions +enum SideMenuItem { + case inviteFriends + case settings + case help + case feedback +} + +extension SideMenuItem { + + var title: String { + let title: String + + switch self { + case .inviteFriends: + title = VectorL10n.sideMenuActionInviteFriends + case .settings: + title = VectorL10n.sideMenuActionSettings + case .help: + title = VectorL10n.sideMenuActionHelp + case .feedback: + title = VectorL10n.sideMenuActionFeedback + } + + return title + } + + var icon: UIImage { + let icon: UIImage + + switch self { + case .inviteFriends: + icon = Asset.Images.sideMenuActionIconShare.image + case .settings: + icon = Asset.Images.sideMenuActionIconSettings.image + case .help: + icon = Asset.Images.sideMenuActionIconHelp.image + case .feedback: + icon = Asset.Images.sideMenuActionIconFeedback.image + } + + return icon + } +} diff --git a/Riot/Modules/SideMenu/SideMenuPresentable.swift b/Riot/Modules/SideMenu/SideMenuPresentable.swift new file mode 100644 index 000000000..126bf4133 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuPresentable.swift @@ -0,0 +1,45 @@ +// +// 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 + +/// SideMenuPresentable absract a side menu presenter +protocol SideMenuPresentable { + + /// Show side menu + func show(from presentable: Presentable, animated: Bool, completion: (() -> Void)?) + + /// Hide side menu + func dismiss(animated: Bool, completion: (() -> Void)?) + + /// Add screen edge gesture to reveal menu + @discardableResult func addScreenEdgePanGesturesToPresent(to view: UIView) -> UIScreenEdgePanGestureRecognizer + + /// Add pan gesture to reveal menu, like pan to reveal from a navigation bar + @discardableResult func addPanGestureToPresent(to view: UIView) -> UIPanGestureRecognizer +} + +// MARK: Default implementation +extension SideMenuPresentable { + + func show(from presentable: Presentable, animated: Bool) { + return self.show(from: presentable, animated: animated, completion: nil) + } + + func dismiss(animated: Bool) { + return self.dismiss(animated: animated, completion: nil) + } +} diff --git a/Riot/Modules/SideMenu/SideMenuPresenter.swift b/Riot/Modules/SideMenu/SideMenuPresenter.swift new file mode 100644 index 000000000..ce278c646 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuPresenter.swift @@ -0,0 +1,51 @@ +// +// 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 SideMenuPresenter: SideMenuPresentable { + + // MARK: - Properties + + private let sideMenuCoordinator: SideMenuCoordinatorType + + // MARK: - Setup + + init(sideMenuCoordinator: SideMenuCoordinatorType) { + self.sideMenuCoordinator = sideMenuCoordinator + } + + // MARK: - Public + + func show(from presentable: Presentable, animated: Bool, completion: (() -> Void)?) { + let presentingViewController = presentable.toPresentable() + let sideMenuController = sideMenuCoordinator.toPresentable() + + presentingViewController.present(sideMenuController, animated: animated, completion: completion) + } + + func dismiss(animated: Bool, completion: (() -> Void)?) { + self.sideMenuCoordinator.toPresentable().dismiss(animated: animated, completion: completion) + } + + @discardableResult func addScreenEdgePanGesturesToPresent(to view: UIView) -> UIScreenEdgePanGestureRecognizer { + return sideMenuCoordinator.addScreenEdgePanGesturesToPresent(to: view) + } + + @discardableResult func addPanGestureToPresent(to view: UIView) -> UIPanGestureRecognizer { + return sideMenuCoordinator.addPanGestureToPresent(to: view) + } +} diff --git a/Riot/Modules/SideMenu/SideMenuVersionView.swift b/Riot/Modules/SideMenu/SideMenuVersionView.swift new file mode 100644 index 000000000..a1d62db74 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuVersionView.swift @@ -0,0 +1,77 @@ +// +// 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 + +/// SideMenuVersionView displays application version +final class SideMenuVersionView: UIView, NibOwnerLoadable { + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var label: UILabel! + + // MARK: Private + + private var theme: Theme! + + // MARK: Public + + // MARK: - Setup + + class func instantiate() -> SideMenuVersionView { + let view = SideMenuVersionView() + view.theme = ThemeService.shared().theme + return view + } + + private func commonInit() { + } + + convenience init() { + self.init(frame: CGRect.zero) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.loadNibContent() + self.commonInit() + } + + override init(frame: CGRect) { + super.init(frame: frame) + self.loadNibContent() + self.commonInit() + } + + // MARK: - Public + + func fill(with version: String) { + self.label.text = VectorL10n.sideMenuAppVersion(version) + } +} + +// MARK: - Themable +extension SideMenuVersionView: Themable { + + func update(theme: Theme) { + self.theme = theme + + self.label.textColor = theme.textSecondaryColor + } +} diff --git a/Riot/Modules/SideMenu/SideMenuVersionView.xib b/Riot/Modules/SideMenu/SideMenuVersionView.xib new file mode 100644 index 000000000..76f5243f1 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuVersionView.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/SideMenu/SideMenuViewAction.swift b/Riot/Modules/SideMenu/SideMenuViewAction.swift new file mode 100644 index 000000000..b494e07dc --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuViewAction.swift @@ -0,0 +1,25 @@ +// File created from ScreenTemplate +// $ createScreen.sh SideMenu SideMenu +/* + 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 + +/// SideMenuViewController view actions exposed to view model +enum SideMenuViewAction { + case loadData + case tap(menuItem: SideMenuItem, sourceView: UIView) +} diff --git a/Riot/Modules/SideMenu/SideMenuViewController.storyboard b/Riot/Modules/SideMenu/SideMenuViewController.storyboard new file mode 100644 index 000000000..8b43a409d --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuViewController.storyboard @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/SideMenu/SideMenuViewController.swift b/Riot/Modules/SideMenu/SideMenuViewController.swift new file mode 100644 index 000000000..0851ec8df --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuViewController.swift @@ -0,0 +1,221 @@ +// File created from ScreenTemplate +// $ createScreen.sh SideMenu SideMenu +/* + 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 UIKit + +final class SideMenuViewController: UIViewController { + + // MARK: - Constants + + private enum Constants { + static let sideMenuActionViewHeight: CGFloat = 44.0 + } + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet private weak var scrollView: UIScrollView! + + // User info + @IBOutlet private weak var userAvatarView: UserAvatarView! + @IBOutlet private weak var userDisplayNameLabel: UILabel! + @IBOutlet private weak var userIdLabel: UILabel! + + // Bottom menu items + + @IBOutlet private weak var menuItemsStackView: UIStackView! + + // MARK: Private + + private var viewModel: SideMenuViewModelType! + private var theme: Theme! + private var keyboardAvoider: KeyboardAvoider? + private var errorPresenter: MXKErrorPresentation! + private var activityPresenter: ActivityIndicatorPresenter! + + private var sideMenuActionViews: [SideMenuActionView] = [] + private weak var sideMenuVersionView: SideMenuVersionView? + + // MARK: - Setup + + class func instantiate(with viewModel: SideMenuViewModelType) -> SideMenuViewController { + let viewController = StoryboardScene.SideMenuViewController.initialScene.instantiate() + viewController.viewModel = viewModel + viewController.theme = ThemeService.shared().theme + return viewController + } + + // MARK: - Life cycle + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + + self.setupViews() + self.activityPresenter = ActivityIndicatorPresenter() + self.errorPresenter = MXKErrorAlertPresentation() + + self.registerThemeServiceDidChangeThemeNotification() + self.update(theme: self.theme) + + self.viewModel.viewDelegate = self + + self.viewModel.process(viewAction: .loadData) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + navigationController?.setNavigationBarHidden(true, animated: animated) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return self.theme.statusBarStyle + } + + // MARK: - Private + + private func update(theme: Theme) { + self.theme = theme + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } + + self.view.backgroundColor = theme.headerBackgroundColor + + self.userAvatarView.update(theme: theme) + self.userDisplayNameLabel.textColor = theme.textPrimaryColor + self.userIdLabel.textColor = theme.textSecondaryColor + + for sideMenuActionView in self.sideMenuActionViews { + sideMenuActionView.update(theme: theme) + } + + self.sideMenuVersionView?.update(theme: theme) + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil) + } + + @objc private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + private func setupViews() { + } + + private func render(viewState: SideMenuViewState) { + switch viewState { + case .loading: + self.renderLoading() + case .loaded(let viewData): + self.renderLoaded(viewData: viewData) + case .error(let error): + self.render(error: error) + } + } + + private func renderLoading() { + self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + } + + private func renderLoaded(viewData: SideMenuViewData) { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + + self.updateUserInformation(with: viewData.userAvatarViewData) + self.updateBottomMenuItems(with: viewData) + } + + private func updateUserInformation(with userAvatarViewData: UserAvatarViewData) { + self.userIdLabel.text = userAvatarViewData.userId + self.userDisplayNameLabel.text = userAvatarViewData.displayName + self.userDisplayNameLabel.isHidden = userAvatarViewData.displayName.isEmptyOrNil + + self.userAvatarView.fill(with: userAvatarViewData) + } + + private func updateBottomMenuItems(with viewData: SideMenuViewData) { + + self.menuItemsStackView.vc_removeAllSubviews() + self.sideMenuActionViews = [] + + for sideMenuItem in viewData.sideMenuItems { + let sideMenuActionView = SideMenuActionView.instantiate() + sideMenuActionView.translatesAutoresizingMaskIntoConstraints = false + let heightConstraint = sideMenuActionView.heightAnchor.constraint(equalToConstant: 0) + heightConstraint.priority = .defaultLow + heightConstraint.isActive = true + + sideMenuActionView.update(theme: self.theme) + sideMenuActionView.fill(with: sideMenuItem) + sideMenuActionView.delegate = self + + self.menuItemsStackView.addArrangedSubview(sideMenuActionView) + sideMenuActionView.widthAnchor.constraint(equalTo: menuItemsStackView.widthAnchor).isActive = true + + self.sideMenuActionViews.append(sideMenuActionView) + } + + if let appVersion = viewData.appVersion { + let sideMenuVersionView = SideMenuVersionView.instantiate() + sideMenuVersionView.translatesAutoresizingMaskIntoConstraints = false + sideMenuVersionView.update(theme: self.theme) + sideMenuVersionView.fill(with: appVersion) + + self.menuItemsStackView.addArrangedSubview(sideMenuVersionView) + sideMenuVersionView.widthAnchor.constraint(equalTo: menuItemsStackView.widthAnchor).isActive = true + + self.sideMenuVersionView = sideMenuVersionView + } + } + + private func render(error: Error) { + self.activityPresenter.removeCurrentActivityIndicator(animated: true) + self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil) + } + + + // MARK: - Actions +} + +// MARK: - SideMenuViewModelViewDelegate +extension SideMenuViewController: SideMenuViewModelViewDelegate { + + func sideMenuViewModel(_ viewModel: SideMenuViewModelType, didUpdateViewState viewSate: SideMenuViewState) { + self.render(viewState: viewSate) + } +} + +// MARK: - SideMenuActionViewDelegate +extension SideMenuViewController: SideMenuActionViewDelegate { + func sideMenuActionView(_ actionView: SideMenuActionView, didTapMenuItem sideMenuItem: SideMenuItem?) { + guard let sideMenuItem = sideMenuItem else { + return + } + + self.viewModel.process(viewAction: .tap(menuItem: sideMenuItem, sourceView: actionView)) + } +} diff --git a/Riot/Modules/SideMenu/SideMenuViewModel.swift b/Riot/Modules/SideMenu/SideMenuViewModel.swift new file mode 100644 index 000000000..532543e17 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuViewModel.swift @@ -0,0 +1,130 @@ +// File created from ScreenTemplate +// $ createScreen.sh SideMenu SideMenu +/* + 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 + +final class SideMenuViewModel: SideMenuViewModelType { + + // MARK: - Properties + + // MARK: Private + + private let userSessionsService: UserSessionsService + private let appInfo: AppInfo + + private var currentOperation: MXHTTPOperation? + + // MARK: Public + + weak var viewDelegate: SideMenuViewModelViewDelegate? + weak var coordinatorDelegate: SideMenuViewModelCoordinatorDelegate? + + // MARK: - Setup + + init(userSessionsService: UserSessionsService, appInfo: AppInfo) { + self.userSessionsService = userSessionsService + self.appInfo = appInfo + } + + deinit { + self.cancelOperations() + } + + // MARK: - Public + + func process(viewAction: SideMenuViewAction) { + switch viewAction { + case .loadData: + self.loadData() + case .tap(menuItem: let menuItem, sourceView: let sourceView): + self.coordinatorDelegate?.sideMenuViewModel(self, didTapMenuItem: menuItem, fromSourceView: sourceView) + } + } + + // MARK: - Private + + private func loadData() { + + self.update(viewState: .loading) + + guard let mainUserSession = self.userSessionsService.mainUserSession else { + return + } + self.updateView(with: mainUserSession) + + self.registerUserSessionsServiceNotifications() + } + + private func userAvatarViewData(from mxSession: MXSession) -> UserAvatarViewData? { + guard let userId = mxSession.myUserId, let mediaManager = mxSession.mediaManager else { + return nil + } + let userDisplayName = mxSession.myUser.displayname + let avatarUrl = mxSession.myUser.avatarUrl + + return UserAvatarViewData(userId: userId, + displayName: userDisplayName, + avatarUrl: avatarUrl, + mediaManager: mediaManager) + } + + private func update(viewState: SideMenuViewState) { + self.viewDelegate?.sideMenuViewModel(self, didUpdateViewState: viewState) + } + + private func cancelOperations() { + self.currentOperation?.cancel() + } + + private func updateView(with userSession: UserSession) { + guard let userAvatarViewData = self.userAvatarViewData(from: userSession.matrixSession) else { + return + } + + let sideMenuItems: [SideMenuItem] = [ + .inviteFriends, + .settings, + .help, + .feedback + ] + + let appVersion = self.appInfo.appVersion?.bundleShortVersion + + let viewData = SideMenuViewData(userAvatarViewData: userAvatarViewData, sideMenuItems: sideMenuItems, appVersion: appVersion) + + self.update(viewState: .loaded(viewData)) + } + + private func registerUserSessionsServiceNotifications() { + + // Listen only notifications from the current UserSessionsService instance + + NotificationCenter.default.addObserver(self, selector: #selector(userSessionDidChange(_:)), name: UserSessionsService.userSessionDidChange, object: self.userSessionsService) + } + + @objc private func userSessionDidChange(_ notification: Notification) { + guard let userSession = notification.userInfo?[UserSessionsService.NotificationUserInfoKey.userSession] as? UserSession else { + return + } + + // Main user session did change (maybe avatar or display name changed) + if let mainUserSession = self.userSessionsService.mainUserSession, mainUserSession.userId == userSession.userId { + self.updateView(with: mainUserSession) + } + } +} diff --git a/Riot/Modules/SideMenu/SideMenuViewModelType.swift b/Riot/Modules/SideMenu/SideMenuViewModelType.swift new file mode 100644 index 000000000..1ab51f3cf --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuViewModelType.swift @@ -0,0 +1,36 @@ +// File created from ScreenTemplate +// $ createScreen.sh SideMenu SideMenu +/* + 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 + +protocol SideMenuViewModelViewDelegate: class { + func sideMenuViewModel(_ viewModel: SideMenuViewModelType, didUpdateViewState viewSate: SideMenuViewState) +} + +protocol SideMenuViewModelCoordinatorDelegate: class { + func sideMenuViewModel(_ viewModel: SideMenuViewModelType, didTapMenuItem menuItem: SideMenuItem, fromSourceView sourceView: UIView) +} + +/// Protocol describing the view model used by `SideMenuViewController` +protocol SideMenuViewModelType { + + var viewDelegate: SideMenuViewModelViewDelegate? { get set } + var coordinatorDelegate: SideMenuViewModelCoordinatorDelegate? { get set } + + func process(viewAction: SideMenuViewAction) +} diff --git a/Riot/Modules/SideMenu/SideMenuViewState.swift b/Riot/Modules/SideMenu/SideMenuViewState.swift new file mode 100644 index 000000000..f47e19361 --- /dev/null +++ b/Riot/Modules/SideMenu/SideMenuViewState.swift @@ -0,0 +1,32 @@ +// File created from ScreenTemplate +// $ createScreen.sh SideMenu SideMenu +/* + 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 + +struct SideMenuViewData { + let userAvatarViewData: UserAvatarViewData + let sideMenuItems: [SideMenuItem] + let appVersion: String? +} + +/// SideMenuViewController view state +enum SideMenuViewState { + case loading + case loaded(_ viewData: SideMenuViewData) + case error(Error) +} diff --git a/Riot/Modules/SplitView/PlaceholderDetailViewController.swift b/Riot/Modules/SplitView/PlaceholderDetailViewController.swift index 6dd7d8b41..9fdd3ac2c 100644 --- a/Riot/Modules/SplitView/PlaceholderDetailViewController.swift +++ b/Riot/Modules/SplitView/PlaceholderDetailViewController.swift @@ -63,6 +63,10 @@ final class PlaceholderDetailViewController: UIViewController, Themable { self.view.backgroundColor = theme.backgroundColor self.logoImageView.tintColor = theme.tintColor + + if let navigationBar = self.navigationController?.navigationBar { + theme.applyStyle(onNavigationBar: navigationBar) + } } // MARK: - Private diff --git a/Riot/Modules/SplitView/SplitViewCoordinator.swift b/Riot/Modules/SplitView/SplitViewCoordinator.swift index b21353cb6..db35d8ff9 100644 --- a/Riot/Modules/SplitView/SplitViewCoordinator.swift +++ b/Riot/Modules/SplitView/SplitViewCoordinator.swift @@ -21,10 +21,12 @@ class SplitViewCoordinatorParameters { let router: RootRouterType let userSessionsService: UserSessionsService + let appNavigator: AppNavigatorProtocol - init(router: RootRouterType, userSessionsService: UserSessionsService) { + init(router: RootRouterType, userSessionsService: UserSessionsService, appNavigator: AppNavigatorProtocol) { self.router = router self.userSessionsService = userSessionsService + self.appNavigator = appNavigator } } @@ -122,7 +124,7 @@ final class SplitViewCoordinator: NSObject, SplitViewCoordinatorType { private func createTabBarCoordinator() -> TabBarCoordinator { - let coordinatorParameters = TabBarCoordinatorParameters(userSessionsService: self.parameters.userSessionsService) + let coordinatorParameters = TabBarCoordinatorParameters(userSessionsService: self.parameters.userSessionsService, appNavigator: self.parameters.appNavigator) let tabBarCoordinator = TabBarCoordinator(parameters: coordinatorParameters) tabBarCoordinator.delegate = self diff --git a/Riot/Modules/StartChat/StartChatViewController.m b/Riot/Modules/StartChat/StartChatViewController.m index 00b881568..428fa13fc 100644 --- a/Riot/Modules/StartChat/StartChatViewController.m +++ b/Riot/Modules/StartChat/StartChatViewController.m @@ -603,9 +603,8 @@ if (isDirect && inviteArray.count) { [[AppDelegate theDelegate] startDirectChatWithUserId:inviteArray.firstObject completion:^{ - + self->createBarButtonItem.enabled = YES; [self stopActivityIndicator]; - }]; } else @@ -625,7 +624,7 @@ MXLogDebug(@"[StartChatViewController] Create room failed"); // Alert user - [[AppDelegate theDelegate] showErrorAsAlert:error]; + [[AppDelegate theDelegate] showAlertWithTitle:nil message:NSLocalizedStringFromTable(@"room_creation_dm_error", @"Vector", nil)]; }; [self.mainSession vc_canEnableE2EByDefaultInNewRoomWithUsers:inviteArray success:^(BOOL canEnableE2E) { diff --git a/Riot/Modules/TabBar/MasterTabBarController.m b/Riot/Modules/TabBar/MasterTabBarController.m index 501ece829..60ff2441c 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.m +++ b/Riot/Modules/TabBar/MasterTabBarController.m @@ -34,7 +34,7 @@ @interface MasterTabBarController () { // Array of `MXSession` instances. - NSMutableArray *mxSessionArray; + NSMutableArray *mxSessionArray; // Tell whether the authentication screen is preparing. BOOL isAuthViewControllerPreparing; @@ -284,7 +284,7 @@ #pragma mark - -- (NSArray*)mxSessions +- (NSArray*)mxSessions { return [NSArray arrayWithArray:mxSessionArray]; } @@ -339,7 +339,7 @@ [self.groupsViewController displayList:groupsDataSource]; // Check whether there are others sessions - NSArray* mxSessions = self.mxSessions; + NSArray* mxSessions = self.mxSessions; if (mxSessions.count > 1) { for (MXSession *mxSession in mxSessions) @@ -356,6 +356,12 @@ - (void)addMatrixSession:(MXSession *)mxSession { + if ([mxSessionArray containsObject:mxSession]) + { + MXLogDebug(@"MasterTabBarController already has %@ in mxSessionArray", mxSession) + return; + } + // Check whether the controller'€™s view is loaded into memory. if (self.homeViewController) { @@ -394,6 +400,12 @@ - (void)removeMatrixSession:(MXSession *)mxSession { + if (![mxSessionArray containsObject:mxSession]) + { + MXLogDebug(@"MasterTabBarController does not contain %@ in mxSessionArray", mxSession) + return; + } + [recentsDataSource removeMatrixSession:mxSession]; // Check whether there are others sessions diff --git a/Riot/Modules/TabBar/TabBarCoordinator.swift b/Riot/Modules/TabBar/TabBarCoordinator.swift index 823d7f505..0efc1c03c 100644 --- a/Riot/Modules/TabBar/TabBarCoordinator.swift +++ b/Riot/Modules/TabBar/TabBarCoordinator.swift @@ -22,9 +22,11 @@ import UIKit class TabBarCoordinatorParameters { let userSessionsService: UserSessionsService + let appNavigator: AppNavigatorProtocol - init(userSessionsService: UserSessionsService) { + init(userSessionsService: UserSessionsService, appNavigator: AppNavigatorProtocol) { self.userSessionsService = userSessionsService + self.appNavigator = appNavigator } } @@ -80,6 +82,10 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { self.addMatrixSessionToMasterTabBarController(userSession.matrixSession) } + if BuildSettings.enableSideMenu { + self.setupSideMenuGestures() + } + self.registerUserSessionsServiceNotifications() } @@ -129,15 +135,24 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { // MARK: - Private methods - private func createMasterTabBarController() -> MasterTabBarController { + private func createMasterTabBarController() -> MasterTabBarController { let tabBarController = MasterTabBarController() - let settingsBarButtonItem: MXKBarButtonItem = MXKBarButtonItem(image: Asset.Images.settingsIcon.image, style: .plain) { [weak self] in - self?.showSettings() + if BuildSettings.enableSideMenu { + let sideMenuBarButtonItem: MXKBarButtonItem = MXKBarButtonItem(image: Asset.Images.sideMenuIcon.image, style: .plain) { [weak self] in + self?.showSideMenu() + } + sideMenuBarButtonItem.accessibilityLabel = VectorL10n.sideMenuRevealActionAccessibilityLabel + + tabBarController.navigationItem.leftBarButtonItem = sideMenuBarButtonItem + } else { + let settingsBarButtonItem: MXKBarButtonItem = MXKBarButtonItem(image: Asset.Images.settingsIcon.image, style: .plain) { [weak self] in + self?.showSettings() + } + settingsBarButtonItem.accessibilityLabel = VectorL10n.settingsTitle + + tabBarController.navigationItem.leftBarButtonItem = settingsBarButtonItem } - settingsBarButtonItem.accessibilityLabel = VectorL10n.settingsTitle - - tabBarController.navigationItem.leftBarButtonItem = settingsBarButtonItem let searchBarButtonItem: MXKBarButtonItem = MXKBarButtonItem(image: Asset.Images.searchIcon.image, style: .plain) { [weak self] in self?.showUnifiedSearch() @@ -229,8 +244,18 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { return viewController } + private func setupSideMenuGestures() { + self.parameters.appNavigator.sideMenu.addScreenEdgePanGesturesToPresent(to: self.masterNavigationController.view) + + self.parameters.appNavigator.sideMenu.addPanGestureToPresent(to: self.masterNavigationController.navigationBar) + } + // MARK: Navigation + private func showSideMenu() { + self.parameters.appNavigator.sideMenu.show(from: self.masterTabBarController, animated: true) + } + // FIXME: Should be displayed per tab. private func showSettings() { let viewController = self.createSettingsViewController() @@ -291,18 +316,12 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { // TODO: Remove Matrix session handling from the view controller private func addMatrixSessionToMasterTabBarController(_ matrixSession: MXSession) { - guard self.masterTabBarController.mxSessions.contains(matrixSession) == false else { - return - } MXLog.debug("[TabBarCoordinator] masterTabBarController.addMatrixSession") self.masterTabBarController.addMatrixSession(matrixSession) } // TODO: Remove Matrix session handling from the view controller private func removeMatrixSessionFromMasterTabBarController(_ matrixSession: MXSession) { - guard self.masterTabBarController.mxSessions.contains(matrixSession) else { - return - } MXLog.debug("[TabBarCoordinator] masterTabBarController.removeMatrixSession") self.masterTabBarController.removeMatrixSession(matrixSession) } diff --git a/Riot/Modules/User/Avatar/UserAvatarView.swift b/Riot/Modules/User/Avatar/UserAvatarView.swift new file mode 100644 index 000000000..9e57958f5 --- /dev/null +++ b/Riot/Modules/User/Avatar/UserAvatarView.swift @@ -0,0 +1,49 @@ +// +// 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 + +final class UserAvatarView: AvatarView { + + // MARK: - Setup + + private func commonInit() { + let avatarImageView = MXKImageView() + self.vc_addSubViewMatchingParent(avatarImageView) + self.avatarImageView = avatarImageView + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.commonInit() + } + + override init(frame: CGRect) { + super.init(frame: frame) + self.commonInit() + } + + // MARK: - Overrides + + override func updateAccessibilityTraits() { + if self.isUserInteractionEnabled { + self.vc_setupAccessibilityTraitsButton(withTitle: VectorL10n.userAvatarViewAccessibilityLabel, hint: VectorL10n.userAvatarViewAccessibilityHint, isEnabled: true) + } else { + self.vc_setupAccessibilityTraitsImage(withTitle: VectorL10n.userAvatarViewAccessibilityLabel) + } + } +} diff --git a/Riot/Managers/Call/Operations/CallBarDismissOperation.swift b/Riot/Modules/User/Avatar/UserAvatarViewData.swift similarity index 54% rename from Riot/Managers/Call/Operations/CallBarDismissOperation.swift rename to Riot/Modules/User/Avatar/UserAvatarViewData.swift index 02be105d1..ce7be8ba6 100644 --- a/Riot/Managers/Call/Operations/CallBarDismissOperation.swift +++ b/Riot/Modules/User/Avatar/UserAvatarViewData.swift @@ -1,5 +1,5 @@ // -// Copyright 2020 New Vector Ltd +// 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. @@ -16,22 +16,13 @@ import Foundation -class CallBarDismissOperation: AsyncOperation { +struct UserAvatarViewData: AvatarViewDataProtocol { + let userId: String + let displayName: String? + let avatarUrl: String? + let mediaManager: MXMediaManager - private var presenter: CallPresenter - private var completion: (() -> Void)? - - init(presenter: CallPresenter, - completion: (() -> Void)? = nil) { - self.presenter = presenter - self.completion = completion + var matrixItemId: String { + return userId } - - override func main() { - presenter.delegate?.callPresenter(presenter, dismissCallBar: { - self.finish() - self.completion?() - }) - } - } diff --git a/Riot/Navigator/AppNavigator.swift b/Riot/Navigator/AppNavigator.swift new file mode 100644 index 000000000..31ebd78b1 --- /dev/null +++ b/Riot/Navigator/AppNavigator.swift @@ -0,0 +1,26 @@ +// +// 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 + +/// AppNavigatorProtocol abstract a navigator at app level. +/// It enables to perform the navigation within the global app scope (open the side menu, open a room and so on) +/// Note: Use a destination enum like presented here https://www.swiftbysundell.com/articles/navigation-in-swift/#where-to-navigator or use simple methods like Element Android Navigator +protocol AppNavigatorProtocol { + + var sideMenu: SideMenuPresentable { get } + var alert: AlertPresentable { get } +} diff --git a/Riot/SupportingFiles/Riot-Bridging-Header.h b/Riot/SupportingFiles/Riot-Bridging-Header.h index 8b93ea99a..3292be7d4 100644 --- a/Riot/SupportingFiles/Riot-Bridging-Header.h +++ b/Riot/SupportingFiles/Riot-Bridging-Header.h @@ -35,3 +35,5 @@ #import "TypingUserInfo.h" #import "UnifiedSearchViewController.h" #import "SettingsViewController.h" +#import "BugReportViewController.h" +#import "BuildInfo.h" diff --git a/RiotNSE/NotificationService.swift b/RiotNSE/NotificationService.swift index 3ac8cd0bd..85bdde3d5 100644 --- a/RiotNSE/NotificationService.swift +++ b/RiotNSE/NotificationService.swift @@ -163,7 +163,7 @@ class NotificationService: UNNotificationServiceExtension { MXKAccountManager.shared()?.forceReloadAccounts() self.userAccount = MXKAccountManager.shared()?.activeAccounts.first if let userAccount = userAccount { - if NotificationService.backgroundSyncService == nil { + if NotificationService.backgroundSyncService?.credentials != userAccount.mxCredentials { MXLog.debug("[NotificationService] setup: MXBackgroundSyncService init: BEFORE") self.logMemory() NotificationService.backgroundSyncService = MXBackgroundSyncService(withCredentials: userAccount.mxCredentials) diff --git a/RiotShareExtension/Modules/Share/DataSources/ShareDataSource.m b/RiotShareExtension/Modules/Share/DataSources/ShareDataSource.m index 8952fdafe..e841769ea 100644 --- a/RiotShareExtension/Modules/Share/DataSources/ShareDataSource.m +++ b/RiotShareExtension/Modules/Share/DataSources/ShareDataSource.m @@ -74,17 +74,8 @@ // Sort rooms according to their last messages (most recent first) NSComparator comparator = ^NSComparisonResult(MXKRecentCellData *recentCellData1, MXKRecentCellData *recentCellData2) { - - NSComparisonResult result = NSOrderedAscending; - if (recentCellData2.roomSummary.lastMessageOriginServerTs > recentCellData1.roomSummary.lastMessageOriginServerTs) - { - result = NSOrderedDescending; - } - else if (recentCellData2.roomSummary.lastMessageOriginServerTs == recentCellData1.roomSummary.lastMessageOriginServerTs) - { - result = NSOrderedSame; - } - return result; + + return [recentCellData1.roomSummary.lastMessage compareOriginServerTs:recentCellData2.roomSummary.lastMessage]; }; [cellData sortUsingComparator:comparator];