diff --git a/CHANGES.rst b/CHANGES.rst index 52358d289..dd7582fd0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,8 +5,65 @@ Changes to be released in next version * 🙌 Improvements + * Add `gitter.im` to list of default room directories + * MasterTabBarController: Show/Hide Home Screen tabs (#4234). + * RoomVC: Enable / Disable VoIP feature in Rooms (#4236). + * UnifiedSearchRecentsDataSource: Show/Hide public directory (#4242). + * DirectoryRecentTableViewCell: Do not use "directory_search_results_more_than" string when there is no rooms and the search is on. * Make room settings screen configurable dynamically (#4219). +🐛 Bugfix + * PublicRoomsDirectoryDataSource: Fix search when NSFW filter is off. + +⚠ API Changes + * + +🗣 Translations + * + +🧱 Build + * + +Others + * + +Changes in 1.3.4 (2021-04-19) +================================================= + +✹ Features + * + +🙌 Improvements + * + +🐛 Bugfix + * RoomVC: Crash in refreshTypingNotification (#4230). + +⚠ API Changes + * + +🗣 Translations + * + +🧱 Build + * + +Others + * + +Improvements: + + +Changes in 1.3.3 (2021-04-16) +================================================= + +✹ Features + * + +🙌 Improvements + * +>>>>>>> develop + 🐛 Bugfix * @@ -22,6 +79,37 @@ Changes to be released in next version Others * +Improvements: + * Upgrade MatrixKit version ([v0.14.9](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.14.9)). + +Changes in 1.3.2 (2021-04-16) +================================================= + +✹ Features + * + +🙌 Improvements + * + +🐛 Bugfix + * Self-verification: Fix compatibility with Element-Web (#4217). + * Notifications: Fix sender display name that can miss (#4222). + +⚠ API Changes + * + +🗣 Translations + * + +🧱 Build + * + +Others + * + +Improvements: + * Upgrade MatrixKit version ([v0.14.9](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.14.9)). + Changes in 1.3.1 (2021-04-14) ================================================= diff --git a/Config/AppIdentifiers.xcconfig b/Config/AppIdentifiers.xcconfig index bad8deffa..fbb194172 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.3.2 -CURRENT_PROJECT_VERSION = 1.3.2 +MARKETING_VERSION = 1.3.5 +CURRENT_PROJECT_VERSION = 1.3.5 // Team diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index ccd00376c..99e79f797 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -150,7 +150,8 @@ final class BuildSettings: NSObject { static let publicRoomsAllowServerChange: Bool = true // List of homeservers for the public rooms directory static let publicRoomsDirectoryServers = [ - "matrix.org" + "matrix.org", + "gitter.im" ] @@ -214,6 +215,13 @@ final class BuildSettings: NSObject { /// Indicates should the app log out the user when number of biometrics failures reaches `maxAllowedNumberOfBiometricsFailures`. Defaults to `false` static let logOutUserWhenBiometricsFailuresExceeded: Bool = false + // MARK: - Main Tabs + + static let homeScreenShowFavouritesTab: Bool = true + static let homeScreenShowPeopleTab: Bool = true + static let homeScreenShowRoomsTab: Bool = true + static let homeScreenShowCommunitiesTab: Bool = true + // MARK: - General Settings Screen static let settingsScreenShowUserFirstName: Bool = false @@ -249,6 +257,11 @@ final class BuildSettings: NSObject { static let roomCreationScreenRoomIsEncrypted: Bool = true static let roomCreationScreenAllowRoomTypeConfiguration: Bool = true static let roomCreationScreenRoomIsPublic: Bool = false + + // MARK: - Room Screen + + static let roomScreenAllowVoIPForDirectRoom: Bool = true + static let roomScreenAllowVoIPForNonDirectRoom: Bool = true // MARK: - Room Settings Screen @@ -280,4 +293,7 @@ final class BuildSettings: NSObject { static let authScreenShowPhoneNumber = true static let authScreenShowForgotPassword = true static let authScreenShowCustomServerOptions = true + + // Mark: - Unified Search + static let unifiedSearchScreenShowPublicDirectory = true } diff --git a/Podfile b/Podfile index 21ad40ed5..f711d8ec5 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.14.8' +$matrixKitVersion = '= 0.14.9' # $matrixKitVersion = :local # $matrixKitVersion = {'develop' => 'develop'} diff --git a/Podfile.lock b/Podfile.lock index 9471ce325..f17b32fa9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -55,28 +55,28 @@ PODS: - MatomoTracker (7.4.1): - MatomoTracker/Core (= 7.4.1) - MatomoTracker/Core (7.4.1) - - MatrixKit (0.14.8): + - MatrixKit (0.14.9): - Down (~> 0.10.0) - DTCoreText (~> 1.6.25) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixKit/Core (= 0.14.8) - - MatrixSDK (= 0.18.8) - - MatrixKit/Core (0.14.8): + - MatrixKit/Core (= 0.14.9) + - MatrixSDK (= 0.18.9) + - MatrixKit/Core (0.14.9): - Down (~> 0.10.0) - DTCoreText (~> 1.6.25) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.18.8) - - MatrixSDK (0.18.8): - - MatrixSDK/Core (= 0.18.8) - - MatrixSDK/Core (0.18.8): + - MatrixSDK (= 0.18.9) + - MatrixSDK (0.18.9): + - MatrixSDK/Core (= 0.18.9) + - MatrixSDK/Core (0.18.9): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) - OLMKit (~> 3.2.2) - Realm (= 10.7.2) - - MatrixSDK/JingleCallStack (0.18.8): + - MatrixSDK/JingleCallStack (0.18.9): - JitsiMeetSDK (= 3.2.0) - MatrixSDK/Core - OLMKit (3.2.2): @@ -101,7 +101,7 @@ PODS: - BlueRSA (~> 1.0) - KituraContracts (~> 1.2) - LoggerAPI (~> 1.7) - - SwiftLint (0.43.0) + - SwiftLint (0.43.1) - zxcvbn-ios (1.0.4) - ZXingObjC (3.6.5): - ZXingObjC/All (= 3.6.5) @@ -115,7 +115,7 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - MatomoTracker (~> 7.4.1) - - MatrixKit (= 0.14.8) + - MatrixKit (= 0.14.9) - MatrixSDK - MatrixSDK/JingleCallStack - OLMKit @@ -186,8 +186,8 @@ SPEC CHECKSUMS: LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b MatomoTracker: 24a846c9d3aa76933183fe9d47fd62c9efa863fb - MatrixKit: 23f7cba7d6132d7ded14a27ff56dde76850118e4 - MatrixSDK: 3b50bb8d80d2dd58e8639baf66ff9399b8752fc3 + MatrixKit: ee8e8d82c2d5fe24ec205d53b15dcaa87e9a913d + MatrixSDK: 74ea0905116cba4cf5709410894a95bbc007307e OLMKit: 20d1c564033a1ae7148f8f599378d4c798363905 ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d Realm: e523da9ade306c5ae87e85dc09fdef148d3e1cc1 @@ -195,10 +195,10 @@ SPEC CHECKSUMS: SwiftBase32: 9399c25a80666dc66b51e10076bf591e3bbb8f17 SwiftGen: 67860cc7c3cfc2ed25b9b74cfd55495fc89f9108 SwiftJWT: 88c412708f58c169d431d344c87bc79a87c830ae - SwiftLint: 0c645fdc6feed3e390c1701ab3cc669f88b42752 + SwiftLint: 99f82d07b837b942dd563c668de129a03fc3fb52 zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 1956486be09b57b05152ce8486f70f5397e26c72 +PODFILE CHECKSUM: 761363c2101ec4039b1b7bcc34f084465ac7f11e COCOAPODS: 1.10.1 diff --git a/Riot/Assets/de.lproj/Localizable.strings b/Riot/Assets/de.lproj/Localizable.strings index eeceaadd2..155ecd848 100644 --- a/Riot/Assets/de.lproj/Localizable.strings +++ b/Riot/Assets/de.lproj/Localizable.strings @@ -41,11 +41,11 @@ /* Incoming unnamed voice conference invite from a specific person */ "VOICE_CONF_FROM_USER" = "Gruppen-Anruf von %@"; /* Incoming unnamed video conference invite from a specific person */ -"VIDEO_CONF_FROM_USER" = "Video-Gruppen-Anruf von %@"; +"VIDEO_CONF_FROM_USER" = "Videogruppenanruf von %@"; /* Incoming named voice conference invite from a specific person */ "VOICE_CONF_NAMED_FROM_USER" = "Gruppen-Anruf von %@: '%@'"; /* Incoming named video conference invite from a specific person */ -"VIDEO_CONF_NAMED_FROM_USER" = "Video-Gruppen-Anruf von %@: '%@'"; +"VIDEO_CONF_NAMED_FROM_USER" = "Videogruppenanruf von %@: '%@'"; /* A single unread message in a room */ "SINGLE_UNREAD_IN_ROOM" = "Du hast eine Nachricht in %@ bekommen"; /* A single unread message */ diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index 5b4213b72..96493461a 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -1327,3 +1327,9 @@ "callbar_only_single_active" = "Laufender 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" = "Einbindungen"; +"room_details_search" = "Raum suchen"; +"room_multiple_typing_notification" = "%@ und andere"; +"room_accessibility_video_call" = "Videoanruf"; +"room_message_replying_to" = "%@ anworten"; +"room_message_editing" = "Bearbeitung"; diff --git a/Riot/Assets/ja.lproj/Vector.strings b/Riot/Assets/ja.lproj/Vector.strings index 6d5d1d5cc..a3d3a68e7 100644 --- a/Riot/Assets/ja.lproj/Vector.strings +++ b/Riot/Assets/ja.lproj/Vector.strings @@ -246,7 +246,7 @@ // Room Preview "room_preview_invitation_format" = "あなたは %@ さんに呌ばれおこの郚屋ぞ参加したした"; "room_preview_subtitle" = "これは郚屋の䞋芋です。発蚀があっおも郚屋は曎新されたせん。"; -"room_preview_unlinked_email_warning" = "このアカりントに関連付けられおいない %@ 宛に招埅が送信されたした。別のアカりントでログむンするか、この電子メヌルアドレスをこのアカりントに远加するこずができたす。"; +"room_preview_unlinked_email_warning" = "このアカりントに関連付けられおいない %@ 宛に招埅が送信されたした。別のアカりントでログむンするか、メヌルアドレスをこのアカりントに远加するこずができたす。"; "room_preview_try_join_an_unknown_room" = "あなたは %@ ぞ接続しようずしおいたす。この䌚議に参加したすか"; "room_preview_try_join_an_unknown_room_default" = "郚屋"; // Settings @@ -291,7 +291,7 @@ "settings_global_settings_info" = "あなたの %@ webクラむアント䞊で、党䜓の通知蚭定が可胜です"; "settings_pin_rooms_with_missed_notif" = "通知の届かなかった郚屋をピン止めする"; "settings_on_denied_notification" = "%@で通知されないように蚭定されおいたす。あなたの端末蚭定で蚱可しおください"; -"settings_callkit_info" = "画面がロックされおいるずきに着信がありたした。Elementの着信はシステムの通話履歎で確認しおください。 iCloudが有効になっおいる堎合、この通話履歎はAppleず共有されたす。"; +"settings_callkit_info" = "画面がロックされおいるずきに着信がありたした。Elementの着信はシステムの通話履歎で確認できたす。 iCloudが有効になっおいる堎合、この通話履歎はAppleず共有されたす。"; "settings_ui_language" = "蚀語"; "settings_ui_theme" = "倖芳"; "settings_ui_theme_auto" = "自動"; @@ -322,14 +322,14 @@ "settings_fail_to_update_password" = "パスワヌドの曎新に倱敗したした"; "settings_password_updated" = "あなたのパスワヌドは曎新されたした"; "settings_crypto_device_name" = "セッション名: "; -"settings_crypto_device_id" = "\n装眮固有ID: "; +"settings_crypto_device_id" = "\nセッションID: "; "settings_crypto_device_key" = "\n端末鍵: "; "settings_crypto_export" = "暗号鍵を倖郚ぞ保存"; -"settings_crypto_blacklist_unverified_devices" = "認蚌された端末のみで暗号化"; +"settings_crypto_blacklist_unverified_devices" = "怜蚌されたセッションのみで暗号化"; // Room Details "room_details_title" = "郚屋の詳现"; "room_details_people" = "参加者"; -"room_details_files" = "添付ファむル"; +"room_details_files" = "アップロヌド"; "room_details_settings" = "蚭定"; "room_details_photo" = "郚屋の画像アむコン"; "room_details_room_name" = "郚屋名"; @@ -365,7 +365,7 @@ "room_details_advanced_enable_e2e_encryption" = "暗号化を開始(譊告: 郚屋の暗号を䞭止するこずはできたせん)"; "room_details_advanced_e2e_encryption_enabled" = "この郚屋の発蚀は暗号化されおいたす"; "room_details_advanced_e2e_encryption_disabled" = "この郚屋の発蚀は暗号化されおいたせん。"; -"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "認蚌された端末のみで暗号化"; +"room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "怜蚌されたセッションのみで暗号化"; "room_details_fail_to_update_avatar" = "郚屋のアむコン画像の曎新に倱敗したした"; "room_details_fail_to_update_room_name" = "郚屋名の曎新に倱敗したした"; "room_details_fail_to_update_topic" = "郚屋の説明の曎新に倱敗したした"; @@ -424,8 +424,8 @@ // Call "call_incoming_voice_prompt" = "%@ さんから通話の着信䞭"; "call_incoming_video_prompt" = "%@ さんから映像぀き通話の着信䞭"; -"call_incoming_voice" = "通話着信䞭..."; -"call_incoming_video" = "映像぀き通話の着信䞭..."; +"call_incoming_voice" = "通話着信䞭 "; +"call_incoming_video" = "ビデオ通話の着信䞭 "; "call_already_displayed" = "すでに通話䞭です。"; "call_jitsi_error" = "䌚議通話ぞの参加に倱敗したした。"; // No VoIP support @@ -434,8 +434,8 @@ // Crash report "google_analytics_use_prompt" = "匿名の誀動䜜報告ず䜿甚状況デヌタを自動的に報告しお%@の改善に圹立おたすか"; // Crypto -"e2e_enabling_on_app_update" = "Elementはend-to-end暗号化をサポヌトするようになりたしたが、再床有効にするにはログむンする必芁がありたす。\n\nアプリの蚭定から再ログむンできたす。今すぐ、たたは埌からでも構いたせん。"; -"e2e_need_log_in_again" = "この端末の゚ンドツヌ゚ンド暗号鍵を生成し、接続先サヌバに公開鍵を送信するには、再床ログむンする必芁がありたす。\n䞀床回線を切断したす。ご䞍䟿おかけしおすみたせん。"; +"e2e_enabling_on_app_update" = "Elementぱンドツヌ゚ンド暗号化をサポヌトするようになりたしたが、有効にするには再びログむンする必芁がありたす。\n\nアプリの蚭定から再ログむンできたす。今すぐ、たたは埌からでも構いたせん。"; +"e2e_need_log_in_again" = "このセッションの゚ンドツヌ゚ンド暗号化キヌを生成し、公開キヌをホヌムサヌバヌに送信するには、再床ログむンする必芁がありたす。\nこれは䞀床だけです。 ご䞍䟿おかけしおすみたせん。"; // Bug report "bug_report_title" = "䞍具合報告"; "bug_report_description" = "誀動䜜の内容ず状況の説明をお願い臎したす。あなたは䜕をしたしたか䜕が起こるず思いたすか実際䜕が起こったのですか"; @@ -526,7 +526,7 @@ // Group rooms "group_rooms_filter_rooms" = "コミュニティルヌムをフィルタリング"; "event_formatter_rerequest_keys_part1_link" = "暗号鍵の再芁求"; -"event_formatter_rerequest_keys_part2" = " あなたの他の端末から。"; +"event_formatter_rerequest_keys_part2" = " あなたの他のセッションから。"; "homeserver_connection_lost" = "ホヌムサヌバヌに接続できたせんでした。"; "widget_sticker_picker_no_stickerpacks_alert" = "珟圚、ステッカヌパックを有効にしおいたせん。"; "widget_sticker_picker_no_stickerpacks_alert_add_now" = "今すぐ远加したすか"; @@ -607,3 +607,422 @@ // Call Bar "callbar_only_single_active" = "アクティブな通話(%@)"; "settings_add_3pid_password_title_msidsn" = "電話番号の远加する"; +"device_verification_emoji_scissors" = "ハサミ"; +"device_verification_emoji_paperclip" = "ペヌパヌクリップ"; +"device_verification_emoji_pencil" = "鉛筆"; +"device_verification_emoji_book" = "本"; +"device_verification_emoji_light bulb" = "電球"; +"device_verification_emoji_gift" = "ギフト"; +"device_verification_emoji_clock" = "時蚈"; +"device_verification_emoji_hourglass" = "スバ時蚈"; +"device_verification_emoji_umbrella" = "雹"; +"device_verification_emoji_thumbs up" = "芪指を立おる"; +"device_verification_emoji_spanner" = "スパナ"; +"device_verification_emoji_santa" = "サンタ"; +"device_verification_emoji_glasses" = "メガネ"; +"device_verification_emoji_hat" = "ハット"; +"device_verification_emoji_robot" = "ロボット"; +"device_verification_emoji_smiley" = "笑顔"; +"device_verification_emoji_heart" = "ハヌト"; +"device_verification_emoji_cake" = "ケヌキ"; +"device_verification_emoji_pizza" = "ピザ"; + +// Room widget permissions +"room_widget_permission_title" = "りィゞェットを読み蟌む"; +"widget_picker_manage_integrations" = "むンテグレヌションを管理する "; + +// Widget Picker +"widget_picker_title" = "むンテグレヌションマネヌゞャヌ"; +"widget_integration_manager_disabled" = "蚭定でむンテグレヌションマネヌゞャヌを有効にする必芁がありたす"; +"widget_menu_remove" = "すべお取り陀く"; +"widget_menu_revoke_permission" = "アクセスを取り消す"; +"widget_menu_open_outside" = "ブラりザを開く"; +"widget_menu_refresh" = "リフレッシュ"; +"widget_integrations_server_failed_to_connect" = "むンテグレヌションサヌバヌぞの説を句が倱敗したした"; + +// Widget +"widget_no_integrations_server_configured" = "むンテグレヌションサヌバヌが蚭定されおいたせん"; +"bug_report_background_mode" = "バックグラりンドで継続する"; +"e2e_key_backup_wrong_version_button_wasme" = "これはわたしです"; +"e2e_key_backup_wrong_version_button_settings" = "蚭定"; +"e2e_key_backup_wrong_version" = "新しいメッセヌゞキヌのバックアップが怜出されたした。\n\nこれがあなたによるものでばい堎合は、蚭定から新しいパスフレヌズを蚭定しおください。"; + +// Key backup wrong version +"e2e_key_backup_wrong_version_title" = "新しいキヌのバックアップ"; +"call_no_stun_server_error_use_fallback_button" = "%@を䜿っおみおください"; +"call_actions_unhold" = "やり盎す"; +"call_no_stun_server_error_message_2" = "代わりに、%@のパブリックサヌバヌを䜿甚するこずもできたすが、これは信頌性が䜎くあなたのIPアドレスがそのサヌバヌず共有されおしたいたす。これは、蚭定から管理するこずができたす"; +"call_no_stun_server_error_message_1" = "通話を確実に機胜させるためには、ホヌムサヌバヌ%@の管理者にTURNサヌバヌの蚭定を䟝頌しおください。"; +"call_no_stun_server_error_title" = "サヌバヌの蚭定が間違っおいるため通話に倱敗したした"; +"room_does_not_exist" = "%@は存圚したせん"; +"photo_library_access_not_granted" = "%@はフォトラむブラリにアクセスする暩限がありたせん"; +"camera_unavailable" = "お䜿いの端末ではカメラを利甚できたせん"; +"event_formatter_widget_removed_by_you" = "りィゞェットを削陀したした: %@"; +"event_formatter_jitsi_widget_removed_by_you" = "VoIPカンファレンスを削陀したした"; +"event_formatter_jitsi_widget_added_by_you" = "VoIPカンファレンスを远加したした"; + +// Events formatter with you +"event_formatter_widget_added_by_you" = "りィゞェットを远加したした: %@"; +"event_formatter_call_back" = "かけ盎す"; +"event_formatter_call_you_declined" = "通話を拒吊したした"; +"event_formatter_call_you_currently_in" = "通話䞭です"; +"event_formatter_call_has_ended" = "通話は有効です"; +"event_formatter_call_video" = "ビデオ通話"; +"event_formatter_call_voice" = "音声通話"; +"event_formatter_message_edited_mention" = "線集枈み"; +"image_picker_action_library" = "ラむブラリを遞ぶ"; + +// Image picker +"image_picker_action_camera" = "写真を撮る"; + +// Media picker +"media_picker_title" = "メディアラむブラリ"; +"room_details_advanced_e2e_encryption_disabled_for_dm" = "ここは暗号化が有効ではありたせん。"; +"room_details_advanced_e2e_encryption_enabled_for_dm" = "ここは暗号化が有効です"; +"room_details_advanced_room_id_for_dm" = "ID:"; +"room_details_no_local_addresses_for_dm" = "ここにはロヌカルアドレスがありたせん"; +"room_details_access_section_directory_toggle_for_dm" = "ルヌムディレクトリに掲茉する"; +"room_details_access_section_anyone_apart_from_guest_for_dm" = "ゲスト以倖のリンクを知っおいる人"; +"room_details_access_section_anyone_for_dm" = "ゲストを含め、リンクを知っおいる人なら誰でも"; +"room_details_access_section_for_dm" = "誰がアクセスできるのか"; +"room_details_photo_for_dm" = "写真"; +"room_details_integrations" = "むンテグレヌション"; +"room_details_search" = "郚屋ルヌムを探す"; +"room_details_title_for_dm" = "詳现"; +"identity_server_settings_alert_error_invalid_identity_server" = "%@は有効なIDサヌバヌではありたせん。"; +"identity_server_settings_alert_error_terms_not_accepted" = "IDサヌバヌずしお蚭定するには%@の条件を受け入れる必芁がありたす。"; +"identity_server_settings_alert_disconnect_still_sharing_3pid_button" = "ずにかく切断する"; +"identity_server_settings_alert_disconnect_still_sharing_3pid" = "あなたはただIDサヌバヌ%@で個人デヌタを共有しおいたす。\n\n切断する前にメヌルアドレスず電話番号をIDサヌバヌから削陀するこずをお勧めしたす。"; +"identity_server_settings_alert_disconnect_button" = "接続を解陀"; +"identity_server_settings_alert_disconnect" = "IDサヌバヌ%@を接続解陀したすか"; +"identity_server_settings_alert_disconnect_title" = "IDサヌバヌを接続解陀"; +"identity_server_settings_alert_change" = "IDサヌバヌ%1$@を切断し、代わりに %2$@に接続したすか"; +"identity_server_settings_alert_change_title" = "IDサヌバヌを倉曎する"; +"identity_server_settings_alert_no_terms" = "遞択したIDサヌバヌには利甚芏玄がありたせん。そのサヌバヌの所有者を信頌できる堎合にのみ続行しおください。"; +"identity_server_settings_alert_no_terms_title" = "IDサヌバヌには利甚芏玄がありたせん"; +"identity_server_settings_disconnect" = "接続を解陀"; +"identity_server_settings_disconnect_info" = "IDサヌバヌずの接続を解陀するず、他のナヌザヌから発芋されなくなり、メヌルや電話で他のナヌザヌを招埅するこずができるようになりたす。"; +"identity_server_settings_change" = "倉曎する"; +"identity_server_settings_add" = "远加する"; +"identity_server_settings_place_holder" = "IDサヌバヌを入力する"; +"identity_server_settings_no_is_description" = "珟圚、ID サヌバヌを䜿甚しおいたせん。知り合いを発芋したり、発芋できるようにするには、䞊蚘に远加しおください。"; +"identity_server_settings_description" = "あなたは%@を䜿っお、あなたの知り合いを発芋し、たた向こうから発芋できるようにしおいたす。"; +"security_settings_complete_security_alert_title" = "セキュリティを完了したす"; +"security_settings_crosssigning_complete_security" = "セキュリティヌを完了する"; +"security_settings_crosssigning_bootstrap" = "独立したクロス眲名"; +"settings_devices_description" = "セッションのパブリックネヌムはコミュニケヌションをずる盞手に衚瀺されたす"; +"settings_key_backup_delete_confirmation_prompt_title" = "バックアップの削陀"; +"settings_key_backup_info_valid" = "このセッションは鍵のバックアップをされおいたす。"; +"settings_key_backup_info_algorithm" = "アルゎリズム: %@"; +"settings_key_backup_info_version" = "キヌのバックアップバヌゞョン: %@"; +"settings_key_backup_info_none" = "あなたのキヌはこのセッションからバックアップされおいたせん。"; +"settings_key_backup_info_checking" = "確認䞭 "; +"settings_add_3pid_password_message" = "続けるにはパスワヌドを入力しおください"; +"settings_add_3pid_invalid_password_message" = "無効な認蚌情報"; +"settings_add_3pid_password_title_email" = "メヌルアドレスを远加する"; +"settings_integrations_allow_description" = "むンテグレヌションマネヌゞャヌ%@を䜿甚しお、ボット、ブリッゞ、りィゞェット、ステッカヌパックを管理したす。\n\n蚭定デヌタを受け取り、お客様に代わっおりィゞェットの倉曎、ルヌム招埅の送信、暩限の蚭定を行うこずができたす。"; +"settings_integrations_allow_button" = "マネヌゞむンテグレヌション"; +"settings_calls_stun_server_fallback_button" = "フォヌルバックコヌルアシストサヌバを蚱可する"; +"settings_key_backup" = "キヌのバックアップ"; +"settings_integrations" = "むンテグレヌション"; +"settings_discovery_settings" = "ディスカバリヌ"; +"room_multiple_typing_notification" = "%@ずその他のナヌザヌが入力䞭です"; +"external_link_confirmation_message" = "リンク%@は別のサむトに移動したす: %@\n\n本圓に続けたすか"; +"room_event_action_delete_confirmation_title" = "未送信メッセヌゞを削陀"; +"room_unsent_messages_cancel_message" = "この郚屋にある未送信のメッセヌゞをすべお削陀しおもよろしいですか"; +"room_unsent_messages_cancel_title" = "未送信メッセヌゞを削陀"; +"room_message_replying_to" = "%@に返信䞭"; +"room_message_editing" = "線集䞭"; +"room_accessiblity_scroll_to_bottom" = "いちばん䞋たでスクロヌル"; +"room_member_power_level_short_custom" = "カスタム"; +"room_member_power_level_short_moderator" = "モデレヌタヌ"; +"room_member_power_level_custom_in" = "カスタム (%@) in %@"; +"room_member_power_level_short_admin" = "管理者"; +"room_member_power_level_moderator_in" = "モデレヌタヌは%@"; +"room_member_power_level_admin_in" = "管理者は%@"; +"room_participants_security_loading" = "読み蟌み䞭 "; +"room_participants_action_security_status_loading" = "読み蟌み䞭 "; +"room_participants_action_security_status_warning" = "譊告"; +"room_participants_action_security_status_complete_security" = "セキュリティヌを完了する"; +"room_participants_action_security_status_verify" = "怜蚌"; +"room_participants_action_security_status_verified" = "怜蚌枈み"; +"room_participants_action_section_security" = "セキュリティ"; +"room_participants_start_new_chat_error_using_user_email_without_identity_server" = "IDサヌバヌが蚭定されおいないため、メヌルアドレスを䜿っお連絡先ずチャットを開始するこずができたせん。"; +"room_participants_filter_room_members_for_dm" = "メンバヌをフィルタヌ"; +"room_participants_remove_third_party_invite_prompt_msg" = "招埅を取り消しおよろしいですか"; +"room_participants_leave_prompt_msg_for_dm" = "退出しおよろしいですか"; +"room_participants_leave_prompt_title_for_dm" = "退出する"; +"contacts_address_book_no_identity_server" = "IDサヌバヌが蚭定されおいたせん"; +"rooms_empty_view_information" = "ルヌムはプラむベヌトでもパブリックでも、あらゆるグルヌプチャットに最適です。+をタップするず既にある郚屋を探したり、新しい郚屋を䜜るこずができたす。"; +"rooms_empty_view_title" = "ルヌム"; +"people_empty_view_information" = "誰ずでも安党にチャットできたす。をタップするず䌚話盞手を远加できたす。"; +"people_empty_view_title" = "人々"; +"room_creation_error_invite_user_by_email_without_identity_server" = "IDサヌバヌが蚭定されおいないため、メヌルで参加者を远加するこずができたせん。"; + +// Errors +"error_user_already_logged_in" = "他のホヌムサヌバヌに接続しようずしおいるようですね。サむンアりトしたすか"; +"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" = "続きはこちら"; +"auth_softlogout_clear_data_sign_out_msg" = "このデバむスに珟圚保存されおいるすべおのデヌタを消去しおよろしいですか再びサむンむンするずアカりントデヌタやメッセヌゞにアクセスできたす。"; +"auth_softlogout_clear_data_sign_out_title" = "本圓によろしいですか"; +"auth_softlogout_clear_data_button" = "すべおのデヌタをクリアする"; +"auth_softlogout_clear_data_message_2" = "このデバむスの䜿甚を終了する堎合や、別のアカりントにサむンむンしたい堎合は、クリアしおください。"; +"auth_softlogout_clear_data_message_1" = "譊告: 個人デヌタ暗号化キヌを含むがこのデバむスにただ保存されおいたす。"; +"callbar_return" = "かけ盎す"; +"callbar_active_and_multiple_paused" = "1぀のアクティブな通話(%@) · %@ 通話の䞀時停止"; +"callbar_only_multiple_paused" = "%@ 通話の䞀時停止"; +"callbar_only_single_paused" = "通話の䞀時停止"; +"store_promotional_text" = "オヌプンネットワヌク䞊でプラむバシヌを保護したチャットアプリ。あなた自身でコントロヌルできるように非䞭倮集暩化分散化されおいたす。デヌタマむニング、バックドア、サヌドパヌティによるアクセスはありたせん。"; +"auth_softlogout_clear_data" = "個人デヌタをクリアする"; +"auth_softlogout_recover_encryption_keys" = "サむンむンしお、このデバむスにのみ保存されおいる暗号化キヌを埩元したす。どのデバむスでも、あなたのセキュアなメッセヌゞをすべお読むために必芁です。"; +"auth_softlogout_reason" = "ホヌムサヌバヌ(%1$@)の管理者が%2$@(%3$@)からサむンアりトさせたした。"; +"auth_softlogout_sign_in" = "サむンむン"; +"auth_softlogout_signed_out" = "サむンアりトしたした"; +"auth_autodiscover_invalid_response" = "無効なホヌムサヌバヌ発芋レスポンス"; +"auth_accept_policies" = "このホヌムサヌバヌのポリシヌを確認しお同意しおください:"; +"auth_reset_password_error_is_required" = "IDサヌバヌが蚭定されおいたせん: パスワヌドをリセットするためにサヌバヌオプションに远加しおください。"; +"auth_forgot_password_error_no_configured_identity_server" = "IDサヌバヌが蚭定されおいたせん: パスワヌドをリセットするためにIDサヌバヌを远加しおください。"; +"auth_phone_is_required" = "IDサヌバヌが蚭定されおいないので、パスワヌドをリセットするために電話番号を远加するこずはできたせん。"; +"auth_email_is_required" = "IDサヌバヌが蚭定されおいないので、パスワヌドをリセットするためにメヌルアドレスを远加するこずはできたせん。"; +"auth_add_email_phone_message_2" = "アカりント回埩のためにメヌルを蚭定したす。これを行うずメヌルアドレスや電話番号を䜿っお、あなたのこずを知っおいる人が発芋できるようになりたす。"; +"auth_add_phone_message_2" = "電話番号を蚭定し、オプションずしお自分を知っおいる人が発芋できるようにしたす。"; +"auth_add_email_message_2" = "アカりント回埩のためにメヌルを蚭定し、オプションずしお自分のこずを知っおいる人が発芋できるようにしたす。"; +"less" = "たたむ"; +"more" = "もっず"; +"switch" = "切り替え"; +"joined" = "参加枈み"; +"skip" = "スキップ"; + +// Identity server settings +"identity_server_settings_title" = "IDサヌバヌ"; + +// AuthenticatedSessionViewControllerFactory +"authenticated_session_flow_not_supported" = "このアプリは、ホヌムサヌバヌの認蚌機構をサポヌトしおいたせん。"; +"manage_session_sign_out" = "セッションからサむンアりト"; +"manage_session_not_trusted" = "信頌できない"; +"manage_session_trusted" = "信頌枈み"; +"manage_session_name" = "セッション名"; +"manage_session_info" = "セッションの情報"; + +// Manage session +"manage_session_title" = "セッションを管理"; +"security_settings_user_password_description" = "アカりントのパスワヌドを入力しお本人確認を行う"; +"security_settings_coming_soon" = "申し蚳ありたせん。このアクションはElement iOSではただ利甚できたせん。他のMatrixクラむアントを䜿っお蚭定しおください。将来的にはElement iOSでも実装される予定です。"; +"security_settings_complete_security_alert_message" = "珟圚のセッションのセキュリティを完了させる必芁がありたす。"; +"security_settings_blacklist_unverified_devices_description" = "すべおのセッションを怜蚌しお、信頌できるものずしおマヌクしメッセヌゞを送信したす。"; +"security_settings_blacklist_unverified_devices" = "信頌しおいないセッションにはメッセヌゞを送信しない"; +"security_settings_advanced" = "䞊玚者向け"; +"security_settings_export_keys_manually" = "手動でキヌを゚クスポヌトする"; +"security_settings_cryptography" = "暗号技術"; +"security_settings_crosssigning_reset" = "クロス眲名をリセット"; +"security_settings_crosssigning_info_ok" = "クロス眲名が有効です。"; +"security_settings_crosssigning_info_trusted" = "クロス眲名が有効になっおいたす。クロス眲名に基づいお他のナヌザヌや自分の他のセッションを信頌するこずはできたすが、このセッションにはクロス眲名甚の秘密鍵がないため、このセッションからクロス眲名を行うこずはできたせん。このセッションのセキュリティを完了しおください。"; +"security_settings_crosssigning_info_exists" = "アカりントにはクロス眲名IDがありたすが、このセッションはただ信頌されおいたせん。 このセッションのセキュリティを完了しおください。"; +"security_settings_crosssigning_info_not_bootstrapped" = "クロス眲名がただ行われおいたせん。"; +"security_settings_crosssigning" = "クロス眲名"; +"security_settings_backup" = "メッセヌゞのバックアップ"; +"security_settings_secure_backup_delete" = "削陀"; +"security_settings_secure_backup_synchronise" = "同期"; +"security_settings_secure_backup_setup" = "セットアップ"; +"security_settings_secure_backup_description" = "暗号化キヌをサヌバヌにバックアップするこずにより、暗号化されたメッセヌゞずデヌタぞのアクセスが倱われるのを防ぎたす。"; +"security_settings_secure_backup" = "安党なバックアップ"; +"security_settings_crypto_sessions_description_2" = "ログむンが認識されない堎合は、パスワヌドを倉曎しおバックアップをリセットしおください。"; +"security_settings_crypto_sessions_loading" = "セッションを読み蟌み䞭 "; +"security_settings_crypto_sessions" = "セッション"; + +// Security settings +"security_settings_title" = "セキュリティ"; +"settings_show_NSFW_public_rooms" = "NSFWパブリックルヌムを衚瀺する"; +"settings_identity_server_no_is_description" = "珟圚、ID サヌバヌを䜿甚しおいたせん。知り合いを発芋したり発芋されるようにするには1぀連絡先を远加したす。"; +"settings_identity_server_no_is" = "IDサヌバヌが蚭定されおいたせん"; +"settings_identity_server_description" = "䞊蚘で蚭定したIDサヌバヌを䜿っお、自分の知り合いを発芋したり、発芋されたりするこずができたす。"; +"settings_discovery_three_pid_details_enter_sms_code_action" = "SMSアクティベヌションコヌドを入力する"; +"settings_discovery_three_pid_details_cancel_email_validation_action" = "メヌルの怜蚌をキャンセル"; +"settings_discovery_three_pid_details_revoke_action" = "取り消し"; +"settings_discovery_three_pid_details_share_action" = "共有"; +"settings_discovery_three_pid_details_title_email" = "メヌルアドレスを管理する"; +"settings_discovery_three_pid_details_title_phone_number" = "電話番号を管理する"; +"settings_discovery_three_pid_details_information_phone_number" = "他のナヌザヌがあなたを発芋したり、ルヌムに招埅する際に䜿甚できる電話番号の蚭定を管理したす。アカりントぞ電話番号の远加や削陀ができたす。"; +"settings_discovery_three_pid_details_information_email" = "他のナヌザヌがあなたを発芋したり、ルヌムに招埅する際に䜿甚できるメヌルアドレスの蚭定を管理したす。アカりントぞメヌルアドレスの远加や削陀ができたす。"; +"settings_discovery_error_message" = "゚ラヌが発生したした。再詊行しおください。"; +"settings_discovery_three_pids_management_information_part3" = "。"; +"settings_discovery_three_pids_management_information_part2" = "ナヌザヌ蚭定"; +"settings_discovery_three_pids_management_information_part1" = "他のナヌザヌがあなたを発芋したり、郚屋に招埅する際に䜿甚するメヌルアドレスや電話番号を管理できたす。このリストにメヌルアドレスや電話番号を远加したり、削陀したりするこずができたす。 "; +"settings_discovery_terms_not_signed" = "メヌルアドレスや電話番号で自分を発芋できるようにするには、IDサヌバヌ%@の利甚芏玄に同意する必芁がありたす。"; +"settings_discovery_no_identity_server" = "珟圚、IDサヌバヌを䜿甚しおいたせん。知り合いがあなたを発芋できるようにするには、IDサヌバヌを远加しおください。"; +"settings_key_backup_delete_confirmation_prompt_msg" = "よろしいですか鍵が適切にバックアップされおいないず、暗号化されたメッセヌゞを倱うこずがありたす。"; +"settings_key_backup_button_connect" = "このセッションをキヌバックアップに接続する"; +"settings_key_backup_button_delete" = "バックアップの消去"; +"settings_key_backup_button_restore" = "バックアップからの埩旧"; +"settings_key_backup_button_create" = "キヌバックアップをする"; +"settings_key_backup_info_trust_signature_invalid_device_unverified" = "バックアップには%@からの無効な眲名がありたす"; +"settings_key_backup_info_trust_signature_invalid_device_verified" = "バックアップには%@からの無効な眲名がありたす"; +"settings_key_backup_info_trust_signature_valid_device_unverified" = "バックアップには%@からの眲名がありたす"; +"settings_key_backup_info_trust_signature_valid_device_verified" = "バックアップには%@による有効な眲名がありたす"; +"settings_key_backup_info_trust_signature_valid" = "バックアップにはこのセッションの有効な眲名がありたす"; +"settings_key_backup_info_trust_signature_unknown" = "バックアップにはID: %@によるセッションの眲名がありたす"; +"settings_key_backup_info_progress_done" = "キヌのバックアップが完了したした"; +"settings_key_backup_info_progress" = "%@のキヌをバックアップしおいたす "; +"settings_key_backup_info_not_valid" = "このセッションではキヌをバックアップしおいたせんが、埩元しお今埌远加できる既存のバックアップがありたす。"; +"settings_key_backup_info_signout_warning" = "このデバむスにのみ存圚するキヌの消倱を防ぐために、サむンアりトする前にこのセッションをキヌバックアップに接続しおください。"; +"settings_key_backup_info" = "暗号化されたメッセヌゞぱンドツヌ゚ンドで暗号化されおいたす。送信者ず受信者だけがこのメッセヌゞを読むための鍵を持っおいたす。"; +"settings_labs_message_reaction" = "絵文字でメッセヌゞに反応する"; +"settings_calls_stun_server_fallback_description" = "ホヌムサヌバヌがフォヌルバックコヌルアシストサヌバヌを提䟛しおいない堎合は@を蚱可したすIPアドレスは通話䞭に共有されたす。"; +"settings_security" = "セキュリティヌ"; +"settings_three_pids_management_information_part3" = "。"; +"settings_three_pids_management_information_part2" = "ディスカバリヌ"; +"store_full_description" = "Elementはたったく新しいタむプのメッセンゞャヌアプリです。\n\n1. あなた自身がプラむバシヌをコントロヌルするこずを可胜にしたす。\n2. Matrixネットワヌクにいる誰ずでも通信できるこずはもちろん、Slackなどのアプリずの連携によっお他のネットワヌクずも通信ができたす。\n3. 広告、デヌタ収集、バックドア、ナヌザヌの囲い蟌みから逃れるこずができたす。\n4. ゚ンドツヌ゚ンド暗号化ずクロス眲名によっおあなたを保護したす。\n\nElementは非䞭倮集暩型でオヌプン゜ヌスであるため、他のメッセンゞャヌアプリずは完党に異なっおいたす。\n\nElementはあなた自身でサヌバヌをホストするこずも、サヌバヌを遞ぶこずもできたす。これによっおあなたのデヌタず䌚話に関するプラむバシヌや所有暩はあなた自身で管理できるようになりたす。さらに、あなたは他のElementナヌザヌず話せるだけでなくオヌプンネットワヌクぞのアクセスも可胜です。ずおもセキュアです。\n\nElementは、オヌプンな分散型通信の暙準芏栌であるMatrixで動䜜するため、これらすべおを実珟するこずができおいたす。\n\nElementではあなたの䌚話をどのサヌバヌでホストするか決めるこずができたす。アプリでは、さたざたな方法で遞択できたす。\n\n1. matrix.orgの公開サヌバヌで無料のアカりントを取埗したす。\n2. あなた自身のハヌドりェアでサヌバヌを動かし、アカりントを管理したす。\n3. Element Matrix Servicesのホスティングプラットフォヌムに登録するこずで、カスタムサヌバヌ䞊のアカりントを取埗できたす。\n\nなぜElementを遞ぶべきなのか\n\nデヌタの所有暩: 自分でデヌタやメッセヌゞを保管する堎所を決めるこずができたす。あなたが所有暩を持っおコントロヌルするこずで、第䞉者にあなたのデヌタを枡したり、ビッグデヌタを収集する巚倧テック䌁業に䟝存する必芁がなくなりたす。\n\n開かれたネットワヌクず共同䜜業: Matrixネットワヌク内の他の誰ずでも、あるいはElementや他のMatrixアプリを䜿っおいるかどうかに関わらず、たたSlack、IRC、XMPPのような他のメッセヌゞングシステムを䜿っおいるかどうかに関わらず、チャットするこずができたす。\n\nはるかに安党: 本物の゚ンドツヌ゚ンド暗号化䌚話に参加しおいる者のみがメッセヌゞを読めるず䌚話参加者の真正性を確認するためクロス眲名によっお。\n\n完党なるコミュニケヌションの蚪れ: テキスト、音声通話、ビデオ通話、ファむル共有、画面共有、連携機胜、ボット、りィゞェットなどのコミュニケヌションに必芁な機胜の党おが実装されおいたす。ルヌムやコミュニティを立ち䞊げお連絡を取り合い、物事をスムヌズに成し遂げるこずができたす。\n\nい぀でもどこでも: すべおのデバむスずりェブhttps://app.element.ioでメッセヌゞの履歎が完党に同期されるため、どこにいおも連絡を取るこずができたす。"; +"user_verification_session_details_additional_information_untrusted_other_user" = "ナヌザヌがこのセッションを信頌するたでは、セッションずの間で送受信されるメッセヌゞには譊告が衚瀺されたす。たた、手動で怜蚌するこずもできたす。"; +"user_verification_session_details_information_untrusted_other_user" = " 新しいセッションを䜿っおサむンむンしたした:"; +"user_verification_session_details_information_untrusted_current_user" = "このセッションを怜蚌するこずで、信頌できるものずしおマヌクし、暗号化されたメッセヌゞぞのアクセスを蚱可したす。"; +"user_verification_session_details_information_trusted_other_user_part2" = " 怜蚌枈み:"; +"user_verification_session_details_information_trusted_other_user_part1" = "このセッションは安党なものずしお信頌されおいたす。なぜなら "; +"user_verification_session_details_information_trusted_current_user" = "このセッションは、怜蚌されたため安党なものずしお信頌されおいたす。"; +"user_verification_session_details_untrusted_title" = "信頌できない"; + +// Session details + +"user_verification_session_details_trusted_title" = "信頌枈み"; +"user_verification_sessions_list_session_untrusted" = "信頌できない"; +"user_verification_sessions_list_session_trusted" = "信頌枈み"; +"user_verification_sessions_list_table_title" = "セッション䞀芧"; +"user_verification_sessions_list_information" = "この郚屋にいるこのナヌザヌずのメッセヌゞぱンドツヌ゚ンドで暗号化されおおり第䞉者が読み取るこずはできたせん。"; +"user_verification_sessions_list_user_trust_level_unknown_title" = "未知"; +"user_verification_sessions_list_user_trust_level_warning_title" = "譊告"; + +// Sessions list + +"user_verification_sessions_list_user_trust_level_trusted_title" = "信頌枈み"; +"user_verification_start_additional_information" = "安心しおご利甚いただくために、盎接お䌚いするか、別の方法でご連絡ください。"; +"user_verification_start_waiting_partner" = "%@を埅っおいたす "; +"user_verification_start_information_part2" = " 䞡方のデバむスでワンタむムコヌドを確認したす。"; +"user_verification_start_information_part1" = "セキュリティを高めるために "; + +// MARK: - User verification + +// Start + +"user_verification_start_verify_action" = "怜蚌を開始する"; +"key_verification_scan_confirmation_scanned_device_information" = "もう䞀方のデバむスにも同じシヌルドが衚瀺されおいたすか"; +"key_verification_scan_confirmation_scanned_user_information" = "%@は同じシヌルドを衚瀺しおいたすか"; + +// Scanned +"key_verification_scan_confirmation_scanned_title" = "たもなくです"; +"key_verification_scan_confirmation_scanning_device_waiting_other" = "他のデバむスを埅っおいたす "; + +// MARK: Scan confirmation + +// Scanning +"key_verification_scan_confirmation_scanning_title" = "もう少しです。確認を埅っおいたす "; +"key_verification_scan_confirmation_scanning_user_waiting_other" = "%@を埅っおいたす "; +"key_verification_verify_qr_code_scan_other_code_success_message" = "QRコヌドの認蚌に成功したした。"; +"key_verification_verify_qr_code_scan_other_code_success_title" = "コヌドが有効になりたした"; +"key_verification_verify_qr_code_other_scan_my_code_title" = "盞手がQRコヌドを読み取っおくれたしたか"; +"key_verification_verify_qr_code_start_emoji_action" = "絵文字による怜蚌"; +"key_verification_verify_qr_code_cannot_scan_action" = "スキャンできたせんか"; +"key_verification_verify_qr_code_scan_code_action" = "コヌドを読み取る"; +"key_verification_verify_qr_code_emoji_information" = "ナニヌクな絵文字を比范しお怜蚌したす。"; +"key_verification_verify_qr_code_information_other_device" = "以䞋のコヌドをスキャンしお確認しおください:"; +"key_verification_verify_qr_code_information" = "コヌドをスキャンしお、お互いをしっかりず確認したす。"; + +// MARK: QR code + +"key_verification_verify_qr_code_title" = "スキャンしお確認する"; + +// Incoming key verification request + +"key_verification_incoming_request_incoming_alert_message" = "%@は怜蚌を求めおいたす"; +"key_verification_tile_conclusion_warning_title" = "信頌されおいないサむンむン"; +"key_verification_tile_conclusion_done_title" = "怜蚌枈み"; +"key_verification_tile_request_incoming_approval_decline" = "华䞋"; +"key_verification_tile_request_incoming_approval_accept" = "承認"; +"key_verification_tile_request_status_accepted" = "あなたは承認したした"; +"key_verification_tile_request_status_cancelled" = "%@はキャンセルしたした"; +"key_verification_tile_request_status_cancelled_by_me" = "あなたはキャンセルしたした"; +"key_verification_tile_request_status_expired" = "期限切れ"; +"key_verification_tile_request_status_waiting" = "お埅ちください "; +"key_verification_tile_request_status_data_loading" = "日時を読み蟌み "; +"key_verification_tile_request_outgoing_title" = "怜蚌の送信"; + +// Tiles + +"key_verification_tile_request_incoming_title" = "怜蚌リク゚スト"; +"key_verification_bootstrap_not_setup_message" = "たずはクロス眲名を行う必芁がありたす。"; + +// MARK: - Key Verification + +"key_verification_bootstrap_not_setup_title" = "゚ラヌ"; +"error_not_supported_on_mobile" = "%@モバむルからはできたせん。"; + + +// Generic errors +"error_invite_3pid_with_no_identity_server" = "メヌルで招埅するために蚭定からIDサヌバヌを远加したす。"; + +// MARK: Reaction history +"reaction_history_title" = "リアクションの履歎"; +"emoji_picker_places_category" = "旅ず堎所"; +"emoji_picker_flags_category" = "囜旗"; +"emoji_picker_symbols_category" = "シンボル"; +"emoji_picker_objects_category" = "オブゞェクト"; +"emoji_picker_foods_category" = "食べ物ず飲み物"; +"emoji_picker_nature_category" = "動物ず自然"; +"emoji_picker_people_category" = "笑顔ずみんな"; + +// MARK: Emoji picker +"emoji_picker_title" = "ピッカヌ"; + +// MARK: File upload +"file_upload_error_title" = "ファむルのアップロヌド゚ラヌ"; +"file_upload_error_unsupported_file_type_message" = "ファむルのタむプがサポヌトされおいたせん。"; +"device_verification_emoji_pin" = "ピン"; +"device_verification_emoji_folder" = "フォルダヌ"; +"device_verification_emoji_headphones" = "ヘッドフォン"; +"device_verification_emoji_anchor" = "アンカヌ"; +"device_verification_emoji_bell" = "ベル"; +"device_verification_emoji_trumpet" = "トランペット"; +"device_verification_emoji_guitar" = "ギタヌ"; +"device_verification_emoji_ball" = "ボヌル"; +"device_verification_emoji_trophy" = "トロフィヌ"; +"device_verification_emoji_rocket" = "ロケット"; +"device_verification_emoji_aeroplane" = "飛行機"; +"device_verification_emoji_bicycle" = "自転車"; +"device_verification_emoji_train" = "電車"; +"device_verification_emoji_flag" = "フラグ"; +"device_verification_emoji_telephone" = "テレフォン"; +"device_verification_emoji_hammer" = "ハンマヌ"; +"device_verification_emoji_key" = "鍵"; +"device_verification_emoji_lock" = "錠"; +"settings_three_pids_management_information_part1" = "ログむンやアカりントの回埩に䜿甚できるメヌルアドレスや電話番号をここで管理したす。誰があなたのこずを発芋できるかを管理する "; +"settings_identity_server_settings" = "IDサヌバヌ"; +"external_link_confirmation_title" = "このリンクを再確認しおください"; +"media_type_accessibility_sticker" = "スティッカヌ"; +"media_type_accessibility_file" = "ファむル"; +"media_type_accessibility_location" = "堎所"; +"media_type_accessibility_video" = "動画"; +"media_type_accessibility_audio" = "音声"; +"media_type_accessibility_image" = "画像"; +"room_open_dialpad" = "ダむダルパッド"; +"room_place_voice_call" = "ビデオ通話"; +"room_accessibility_hangup" = "通話を切る"; +"room_event_action_delete_confirmation_message" = "この未送信メッセヌゞを削陀しおもよろしいですか"; +"room_accessibility_video_call" = "ビデオ通話"; +"room_accessibility_call" = "通話"; +"room_accessibility_integrations" = "統合"; +"room_accessibility_search" = "怜玢"; +"room_accessibility_upload" = "アップロヌド"; +"room_message_edits_history_title" = "メッセヌゞを線集"; +"room_action_reply" = "返信"; +"room_action_send_file" = "ファむルを送る"; +"room_action_camera" = "写真やビデオの撮圱"; +"room_event_action_reaction_history" = "反応の履歎"; +"room_event_action_reaction_show_less" = "すべお閉じる"; +"room_event_action_reaction_show_all" = "すべおを芋る"; +"room_event_action_edit" = "線集"; +"room_event_action_reply" = "返信"; diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 427cabc4a..1f08d677c 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -60,6 +60,13 @@ final class RiotSettings: NSObject { static let roomSettingsScreenShowFlairSettings = "roomSettingsScreenShowFlairSettings" static let roomSettingsScreenShowAdvancedSettings = "roomSettingsScreenShowAdvancedSettings" static let roomSettingsScreenAdvancedShowEncryptToVerifiedOption = "roomSettingsScreenAdvancedShowEncryptToVerifiedOption" + static let homeScreenShowFavouritesTab = "homeScreenShowFavouritesTab" + static let homeScreenShowPeopleTab = "homeScreenShowPeopleTab" + static let homeScreenShowRoomsTab = "homeScreenShowRoomsTab" + static let homeScreenShowCommunitiesTab = "homeScreenShowCommunitiesTab" + static let roomScreenAllowVoIPForDirectRoom = "roomScreenAllowVoIPForDirectRoom" + static let roomScreenAllowVoIPForNonDirectRoom = "roomScreenAllowVoIPForNonDirectRoom" + static let unifiedSearchScreenShowPublicDirectory = "unifiedSearchScreenShowPublicDirectory" } static let shared = RiotSettings() @@ -258,6 +265,29 @@ final class RiotSettings: NSObject { } } + // MARK: - Room Screen + + var roomScreenAllowVoIPForDirectRoom: Bool { + get { + guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom) != nil else { + return BuildSettings.roomScreenAllowVoIPForDirectRoom + } + return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom) + } set { + defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom) + } + } + var roomScreenAllowVoIPForNonDirectRoom: Bool { + get { + guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowVoIPForNonDirectRoom) != nil else { + return BuildSettings.roomScreenAllowVoIPForNonDirectRoom + } + return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowVoIPForNonDirectRoom) + } set { + defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowVoIPForNonDirectRoom) + } + } + // MARK: - Room Creation Screen var roomCreationScreenAllowEncryptionConfiguration: Bool { @@ -313,6 +343,49 @@ final class RiotSettings: NSObject { defaults.set(newValue, forKey: UserDefaultsKeys.allowInviteExernalUsers) } } + + // MARK: - Main Tabs + + var homeScreenShowFavouritesTab: Bool { + get { + guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowFavouritesTab) != nil else { + return BuildSettings.homeScreenShowFavouritesTab + } + return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowFavouritesTab) + } set { + defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowFavouritesTab) + } + } + var homeScreenShowPeopleTab: Bool { + get { + guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowPeopleTab) != nil else { + return BuildSettings.homeScreenShowPeopleTab + } + return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowPeopleTab) + } set { + defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowPeopleTab) + } + } + var homeScreenShowRoomsTab: Bool { + get { + guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowRoomsTab) != nil else { + return BuildSettings.homeScreenShowRoomsTab + } + return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowRoomsTab) + } set { + defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowRoomsTab) + } + } + var homeScreenShowCommunitiesTab: Bool { + get { + guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowCommunitiesTab) != nil else { + return BuildSettings.homeScreenShowCommunitiesTab + } + return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowCommunitiesTab) + } set { + defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowCommunitiesTab) + } + } // MARK: General Settings @@ -500,4 +573,17 @@ final class RiotSettings: NSObject { } } + // Mark: - Unified Search + + var unifiedSearchScreenShowPublicDirectory: Bool { + get { + guard defaults.object(forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory) != nil else { + return BuildSettings.unifiedSearchScreenShowPublicDirectory + } + return defaults.bool(forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory) + } set { + defaults.set(newValue, forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory) + } + } + } diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 501021ddc..ef261c069 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -2274,21 +2274,29 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni if (mainSession.crypto.crossSigning) { - NSLog(@"[AppDelegate] handleAppState: crossSigning.state: %@", @(mainSession.crypto.crossSigning.state)); - - switch (mainSession.crypto.crossSigning.state) - { - case MXCrossSigningStateCrossSigningExists: - NSLog(@"[AppDelegate] handleAppState: presentVerifyCurrentSessionAlertIfNeededWithSession"); - [_masterTabBarController presentVerifyCurrentSessionAlertIfNeededWithSession:mainSession]; - break; - case MXCrossSigningStateCanCrossSign: - NSLog(@"[AppDelegate] handleAppState: presentReviewUnverifiedSessionsAlertIfNeededWithSession"); - [_masterTabBarController presentReviewUnverifiedSessionsAlertIfNeededWithSession:mainSession]; - break; - default: - break; - } + // Get the up-to-date cross-signing state + MXWeakify(self); + [mainSession.crypto.crossSigning refreshStateWithSuccess:^(BOOL stateUpdated) { + MXStrongifyAndReturnIfNil(self); + + NSLog(@"[AppDelegate] handleAppState: crossSigning.state: %@", @(mainSession.crypto.crossSigning.state)); + + switch (mainSession.crypto.crossSigning.state) + { + case MXCrossSigningStateCrossSigningExists: + NSLog(@"[AppDelegate] handleAppState: presentVerifyCurrentSessionAlertIfNeededWithSession"); + [self.masterTabBarController presentVerifyCurrentSessionAlertIfNeededWithSession:mainSession]; + break; + case MXCrossSigningStateCanCrossSign: + NSLog(@"[AppDelegate] handleAppState: presentReviewUnverifiedSessionsAlertIfNeededWithSession"); + [self.masterTabBarController presentReviewUnverifiedSessionsAlertIfNeededWithSession:mainSession]; + break; + default: + break; + } + } failure:^(NSError * _Nonnull error) { + NSLog(@"[AppDelegate] handleAppState: crossSigning.state: %@. Error: %@", @(mainSession.crypto.crossSigning.state), error); + }]; } // TODO: We should wait that cross-signing screens are done before going further but it seems fine. Those screens @@ -3934,6 +3942,18 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni [self.incomingKeyVerificationRequestAlertController dismissViewControllerAnimated:NO completion:nil]; } + if (self.userNewSignInAlertController + && [session.myUserId isEqualToString:senderId]) + { + // If it is a self verification for my device, we can discard the new signin alert. + // Note: It will not work well with several devices to verify at the same time. + NSLog(@"[AppDelegate] presentNewKeyVerificationRequest: Remove the alert for new sign in detected"); + [self.userNewSignInAlertController dismissViewControllerAnimated:NO completion:^{ + self.userNewSignInAlertController = nil; + [self presentNewKeyVerificationRequestAlertForSession:session senderName:senderName senderId:senderId request:keyVerificationRequest]; + }]; + } + NSString *senderInfo; if (senderName) @@ -3955,7 +3975,6 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni } }; - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"key_verification_tile_request_incoming_title", @"Vector", nil) message:senderInfo preferredStyle:UIAlertControllerStyleAlert]; diff --git a/Riot/Modules/GlobalSearch/DataSources/UnifiedSearchRecentsDataSource.m b/Riot/Modules/GlobalSearch/DataSources/UnifiedSearchRecentsDataSource.m index df95e8ff8..1a4605ba6 100644 --- a/Riot/Modules/GlobalSearch/DataSources/UnifiedSearchRecentsDataSource.m +++ b/Riot/Modules/GlobalSearch/DataSources/UnifiedSearchRecentsDataSource.m @@ -22,6 +22,7 @@ #import "DirectoryRecentTableViewCell.h" #import "MXRoom+Riot.h" +#import "Riot-Swift.h" @interface UnifiedSearchRecentsDataSource() { @@ -85,7 +86,10 @@ } // The public rooms directory cell is then visible whatever the search activity. - self.directorySection = sectionsOffset++; + if (RiotSettings.shared.unifiedSearchScreenShowPublicDirectory) + { + self.directorySection = sectionsOffset++; + } if (_hideRecents) { diff --git a/Riot/Modules/GlobalSearch/Views/DirectoryRecentTableViewCell.m b/Riot/Modules/GlobalSearch/Views/DirectoryRecentTableViewCell.m index 0ebf282f1..63cdbfbce 100644 --- a/Riot/Modules/GlobalSearch/Views/DirectoryRecentTableViewCell.m +++ b/Riot/Modules/GlobalSearch/Views/DirectoryRecentTableViewCell.m @@ -54,7 +54,7 @@ self.titleLabel.text = NSLocalizedStringFromTable(@"directory_search_results_title", @"Vector", nil); // Do we need to display like ">20 results found" or "18 results found"? - NSString *descriptionLabel = publicRoomsDirectoryDataSource.moreThanRoomsCount ? NSLocalizedStringFromTable(@"directory_search_results_more_than", @"Vector", nil) : NSLocalizedStringFromTable(@"directory_search_results", @"Vector", nil); + NSString *descriptionLabel = (publicRoomsDirectoryDataSource.moreThanRoomsCount && publicRoomsDirectoryDataSource.roomsCount > 0) ? NSLocalizedStringFromTable(@"directory_search_results_more_than", @"Vector", nil) : NSLocalizedStringFromTable(@"directory_search_results", @"Vector", nil); self.descriptionLabel.text = [NSString stringWithFormat:descriptionLabel, publicRoomsDirectoryDataSource.roomsCount, diff --git a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift index badcf9dcf..6da9e3ccf 100644 --- a/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift +++ b/Riot/Modules/KeyVerification/Device/SelfVerifyWait/KeyVerificationSelfVerifyWaitViewModel.swift @@ -91,6 +91,21 @@ final class KeyVerificationSelfVerifyWaitViewModel: KeyVerificationSelfVerifyWai } else { // be sure that session has completed its first sync if session.state >= MXSessionStateRunning { + + // Always send request instead of waiting for an incoming one as per recent EW changes + print("[KeyVerificationSelfVerifyWaitViewModel] loadData: Send a verification request to all devices instead of waiting") + + let keyVerificationService = KeyVerificationService() + self.verificationManager.requestVerificationByToDevice(withUserId: self.session.myUserId, deviceIds: nil, methods: keyVerificationService.supportedKeyVerificationMethods(), success: { [weak self] (keyVerificationRequest) in + guard let self = self else { + return + } + + self.keyVerificationRequest = keyVerificationRequest + + }, failure: { [weak self] error in + self?.update(viewState: .error(error)) + }) continueLoadData() } else { // show loader diff --git a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m index ff77c5cb0..03fb2f94c 100644 --- a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m +++ b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m @@ -261,7 +261,7 @@ static NSString *const kNSFWKeyword = @"nsfw"; [self->rooms addObjectsFromArray:publicRooms]; self->nextBatch = publicRoomsResponse.nextBatch; - if (!self->_searchPattern || !self.showNSFWRooms) + if (!self->_searchPattern) { // When there is no search, we can use totalRoomCountEstimate returned by the server self->_roomsCount = publicRoomsResponse.totalRoomCountEstimate; diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 648c8ca90..10eabeb65 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -1400,7 +1400,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; - (BOOL)supportCallOption { - return BuildSettings.allowVoIPUsage && self.roomDataSource.mxSession.callManager && self.roomDataSource.room.summary.membersCount.joined >= 2; + BOOL callOptionAllowed = (self.roomDataSource.room.isDirect && RiotSettings.shared.roomScreenAllowVoIPForDirectRoom) || (!self.roomDataSource.room.isDirect && RiotSettings.shared.roomScreenAllowVoIPForNonDirectRoom); + return callOptionAllowed && BuildSettings.allowVoIPUsage && self.roomDataSource.mxSession.callManager && self.roomDataSource.room.summary.membersCount.joined >= 2; } - (BOOL)isCallActive @@ -4134,7 +4135,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; if (needsUpdate) { - BOOL needsReload = roomDataSource.currentTypingUsers == nil; +// BOOL needsReload = roomDataSource.currentTypingUsers == nil; + // Quick fix for https://github.com/vector-im/element-ios/issues/4230 + BOOL needsReload = YES; roomDataSource.currentTypingUsers = typingUsers; if (needsReload) { diff --git a/Riot/Modules/TabBar/MasterTabBarController.m b/Riot/Modules/TabBar/MasterTabBarController.m index d532bfdca..dd7a3e9f2 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.m +++ b/Riot/Modules/TabBar/MasterTabBarController.m @@ -130,6 +130,8 @@ }]; [self userInterfaceThemeDidChange]; + + [self updateTabs]; } - (void)userInterfaceThemeDidChange @@ -880,38 +882,75 @@ #pragma mark - +- (void)updateTabs +{ + if (RiotSettings.shared.homeScreenShowCommunitiesTab && RiotSettings.shared.homeScreenShowRoomsTab + && RiotSettings.shared.homeScreenShowPeopleTab && RiotSettings.shared.homeScreenShowFavouritesTab) + { + return; + } + + NSMutableArray *newTabs = [NSMutableArray arrayWithArray:self.viewControllers]; + if (!RiotSettings.shared.homeScreenShowCommunitiesTab) + { + [newTabs removeObjectAtIndex:TABBAR_GROUPS_INDEX]; + } + if (!RiotSettings.shared.homeScreenShowRoomsTab) + { + [newTabs removeObjectAtIndex:TABBAR_ROOMS_INDEX]; + } + if (!RiotSettings.shared.homeScreenShowPeopleTab) + { + [newTabs removeObjectAtIndex:TABBAR_PEOPLE_INDEX]; + } + if (!RiotSettings.shared.homeScreenShowFavouritesTab) + { + [newTabs removeObjectAtIndex:TABBAR_FAVOURITES_INDEX]; + } + self.viewControllers = newTabs; +} + - (void)refreshTabBarBadges { // Use a middle dot to signal missed notif in favourites - [self setMissedDiscussionsMark:(recentsDataSource.missedFavouriteDiscussionsCount? @"\u00B7": nil) - onTabBarItem:TABBAR_FAVOURITES_INDEX - withBadgeColor:(recentsDataSource.missedHighlightFavouriteDiscussionsCount ? ThemeService.shared.theme.noticeColor : ThemeService.shared.theme.noticeSecondaryColor)]; + if (RiotSettings.shared.homeScreenShowFavouritesTab) + { + [self setMissedDiscussionsMark:(recentsDataSource.missedFavouriteDiscussionsCount? @"\u00B7": nil) + onTabBarItem:TABBAR_FAVOURITES_INDEX + withBadgeColor:(recentsDataSource.missedHighlightFavouriteDiscussionsCount ? ThemeService.shared.theme.noticeColor : ThemeService.shared.theme.noticeSecondaryColor)]; + } // Update the badge on People and Rooms tabs - if (recentsDataSource.unsentMessagesDirectDiscussionsCount) + if (RiotSettings.shared.homeScreenShowPeopleTab) { - [self setBadgeValue:@"!" - onTabBarItem:TABBAR_PEOPLE_INDEX - withBadgeColor:ThemeService.shared.theme.noticeColor]; - } - else - { - [self setMissedDiscussionsCount:recentsDataSource.missedDirectDiscussionsCount - onTabBarItem:TABBAR_PEOPLE_INDEX - withBadgeColor:(recentsDataSource.missedHighlightDirectDiscussionsCount ? ThemeService.shared.theme.noticeColor : ThemeService.shared.theme.noticeSecondaryColor)]; + if (recentsDataSource.unsentMessagesDirectDiscussionsCount) + { + [self setBadgeValue:@"!" + onTabBarItem:TABBAR_PEOPLE_INDEX + withBadgeColor:ThemeService.shared.theme.noticeColor]; + } + else + { + [self setMissedDiscussionsCount:recentsDataSource.missedDirectDiscussionsCount + onTabBarItem:TABBAR_PEOPLE_INDEX + withBadgeColor:(recentsDataSource.missedHighlightDirectDiscussionsCount ? ThemeService.shared.theme.noticeColor : ThemeService.shared.theme.noticeSecondaryColor)]; + } } - if (recentsDataSource.unsentMessagesGroupDiscussionsCount) + if (RiotSettings.shared.homeScreenShowRoomsTab) { - [self setMissedDiscussionsCount:recentsDataSource.unsentMessagesGroupDiscussionsCount - onTabBarItem:TABBAR_ROOMS_INDEX - withBadgeColor:ThemeService.shared.theme.noticeColor]; - } - else - { - [self setMissedDiscussionsCount:recentsDataSource.missedGroupDiscussionsCount - onTabBarItem:TABBAR_ROOMS_INDEX - withBadgeColor:(recentsDataSource.missedHighlightGroupDiscussionsCount ? ThemeService.shared.theme.noticeColor : ThemeService.shared.theme.noticeSecondaryColor)]; + if (recentsDataSource.unsentMessagesGroupDiscussionsCount) + { + [self setMissedDiscussionsCount:recentsDataSource.unsentMessagesGroupDiscussionsCount + onTabBarItem:TABBAR_ROOMS_INDEX + withBadgeColor:ThemeService.shared.theme.noticeColor]; + } + else + { + [self setMissedDiscussionsCount:recentsDataSource.missedGroupDiscussionsCount + onTabBarItem:TABBAR_ROOMS_INDEX + withBadgeColor:(recentsDataSource.missedHighlightGroupDiscussionsCount ? ThemeService.shared.theme.noticeColor : ThemeService.shared.theme.noticeSecondaryColor)]; + } } } @@ -922,39 +961,47 @@ - (void)setBadgeValue:(NSString *)value onTabBarItem:(NSUInteger)index withBadgeColor:(UIColor*)badgeColor { - if (value) + NSInteger itemIndex = [self indexOfTabItemWithTag:index]; + if (itemIndex != NSNotFound) { - self.tabBar.items[index].badgeValue = value; - - self.tabBar.items[index].badgeColor = badgeColor; - - [self.tabBar.items[index] setBadgeTextAttributes:@{ - NSForegroundColorAttributeName: ThemeService.shared.theme.baseTextPrimaryColor - } - forState:UIControlStateNormal]; - } - else - { - self.tabBar.items[index].badgeValue = nil; + if (value) + { + self.tabBar.items[itemIndex].badgeValue = value; + + self.tabBar.items[itemIndex].badgeColor = badgeColor; + + [self.tabBar.items[itemIndex] setBadgeTextAttributes:@{ + NSForegroundColorAttributeName: ThemeService.shared.theme.baseTextPrimaryColor + } + forState:UIControlStateNormal]; + } + else + { + self.tabBar.items[itemIndex].badgeValue = nil; + } } } - (void)setMissedDiscussionsMark:(NSString*)mark onTabBarItem:(NSUInteger)index withBadgeColor:(UIColor*)badgeColor { - if (mark) + NSInteger itemIndex = [self indexOfTabItemWithTag:index]; + if (itemIndex != NSNotFound) { - self.tabBar.items[index].badgeValue = mark; - - self.tabBar.items[index].badgeColor = badgeColor; - - [self.tabBar.items[index] setBadgeTextAttributes:@{ - NSForegroundColorAttributeName: ThemeService.shared.theme.baseTextPrimaryColor - } - forState:UIControlStateNormal]; - } - else - { - self.tabBar.items[index].badgeValue = nil; + if (mark) + { + self.tabBar.items[itemIndex].badgeValue = mark; + + self.tabBar.items[itemIndex].badgeColor = badgeColor; + + [self.tabBar.items[itemIndex] setBadgeTextAttributes:@{ + NSForegroundColorAttributeName: ThemeService.shared.theme.baseTextPrimaryColor + } + forState:UIControlStateNormal]; + } + else + { + self.tabBar.items[itemIndex].badgeValue = nil; + } } } @@ -975,6 +1022,19 @@ return badgeValue; } +- (NSInteger)indexOfTabItemWithTag:(NSUInteger)tag +{ + for (int i = 0 ; i < self.tabBar.items.count ; i++) + { + if (self.tabBar.items[i].tag == tag) + { + return i; + } + } + + return NSNotFound; +} + #pragma mark - - (void)promptUserBeforeUsingAnalytics diff --git a/RiotNSE/NotificationService.swift b/RiotNSE/NotificationService.swift index 45f9b2b6e..a7def37e1 100644 --- a/RiotNSE/NotificationService.swift +++ b/RiotNSE/NotificationService.swift @@ -264,147 +264,188 @@ class NotificationService: UNNotificationServiceExtension { NSLog("[NotificationService] notificationContentForEvent: Attempt to fetch the room state") - NotificationService.backgroundSyncService.roomState(forRoomId: roomId, completion: { (response) in + self.context(ofEvent: event, inRoom: roomId, completion: { (response) in switch response { - case .success(let roomState): - var notificationTitle: String? - var notificationBody: String? - - var threadIdentifier: String? = roomId - let eventSenderName = roomState.members.memberName(event.sender) - let currentUserId = account.mxCredentials.userId - let roomDisplayName = roomSummary?.displayname - let pushRule = NotificationService.backgroundSyncService.pushRule(matching: event, roomState: roomState) - - switch event.eventType { - case .callInvite: - let offer = event.content["offer"] as? [AnyHashable: Any] - let sdp = offer?["sdp"] as? String - let isVideoCall = sdp?.contains("m=video") ?? false + case .success(let (roomState, eventSenderName)): + var notificationTitle: String? + var notificationBody: String? - if isVideoCall { - notificationBody = NSString.localizedUserNotificationString(forKey: "VIDEO_CALL_FROM_USER", arguments: [eventSenderName as Any]) - } else { - notificationBody = NSString.localizedUserNotificationString(forKey: "VOICE_CALL_FROM_USER", arguments: [eventSenderName as Any]) - } + var threadIdentifier: String? = roomId + let currentUserId = account.mxCredentials.userId + let roomDisplayName = roomSummary?.displayname + let pushRule = NotificationService.backgroundSyncService.pushRule(matching: event, roomState: roomState) - // call notifications should stand out from normal messages, so we don't stack them - threadIdentifier = nil - self.sendVoipPush(forEvent: event) - case .roomMessage, .roomEncrypted: - if isRoomMentionsOnly { - // A local notification will be displayed only for highlighted notification. - var isHighlighted = false - - // Check whether is there an highlight tweak on it - for ruleAction in pushRule?.actions ?? [] { - guard let action = ruleAction as? MXPushRuleAction else { continue } - guard action.actionType == MXPushRuleActionTypeSetTweak else { continue } - guard action.parameters["set_tweak"] as? String == "highlight" else { continue } - // Check the highlight tweak "value" - // If not present, highlight. Else check its value before highlighting - if nil == action.parameters["value"] || true == (action.parameters["value"] as? Bool) { - isHighlighted = true - break + switch event.eventType { + case .callInvite: + let offer = event.content["offer"] as? [AnyHashable: Any] + let sdp = offer?["sdp"] as? String + let isVideoCall = sdp?.contains("m=video") ?? false + + if isVideoCall { + notificationBody = NSString.localizedUserNotificationString(forKey: "VIDEO_CALL_FROM_USER", arguments: [eventSenderName as Any]) + } else { + notificationBody = NSString.localizedUserNotificationString(forKey: "VOICE_CALL_FROM_USER", arguments: [eventSenderName as Any]) + } + + // call notifications should stand out from normal messages, so we don't stack them + threadIdentifier = nil + self.sendVoipPush(forEvent: event) + case .roomMessage, .roomEncrypted: + if isRoomMentionsOnly { + // A local notification will be displayed only for highlighted notification. + var isHighlighted = false + + // Check whether is there an highlight tweak on it + for ruleAction in pushRule?.actions ?? [] { + guard let action = ruleAction as? MXPushRuleAction else { continue } + guard action.actionType == MXPushRuleActionTypeSetTweak else { continue } + guard action.parameters["set_tweak"] as? String == "highlight" else { continue } + // Check the highlight tweak "value" + // If not present, highlight. Else check its value before highlighting + if nil == action.parameters["value"] || true == (action.parameters["value"] as? Bool) { + isHighlighted = true + break + } + } + + if !isHighlighted { + // Ignore this notif. + NSLog("[NotificationService] notificationContentForEvent: Ignore non highlighted notif in mentions only room") + onComplete(nil) + return + } + } + + var msgType = event.content["msgtype"] as? String + let messageContent = event.content["body"] as? String + + if event.isEncrypted && !self.showDecryptedContentInNotifications { + // Hide the content + msgType = nil + } + + // Display the room name only if it is different than the sender name + if roomDisplayName != nil && roomDisplayName != eventSenderName { + notificationTitle = NSString.localizedUserNotificationString(forKey: "MSG_FROM_USER_IN_ROOM_TITLE", arguments: [eventSenderName as Any, roomDisplayName as Any]) + + if msgType == kMXMessageTypeText { + notificationBody = messageContent + } else if msgType == kMXMessageTypeEmote { + notificationBody = NSString.localizedUserNotificationString(forKey: "ACTION_FROM_USER", arguments: [eventSenderName as Any, messageContent as Any]) + } else if msgType == kMXMessageTypeImage { + notificationBody = NSString.localizedUserNotificationString(forKey: "IMAGE_FROM_USER", arguments: [eventSenderName as Any, messageContent as Any]) + } else { + // Encrypted messages falls here + notificationBody = NSString.localizedUserNotificationString(forKey: "MESSAGE", arguments: []) + } + } else { + notificationTitle = eventSenderName + + switch msgType { + case kMXMessageTypeText: + notificationBody = messageContent + break + case kMXMessageTypeEmote: + notificationBody = NSString.localizedUserNotificationString(forKey: "ACTION_FROM_USER", arguments: [eventSenderName as Any, messageContent as Any]) + break + case kMXMessageTypeImage: + notificationBody = NSString.localizedUserNotificationString(forKey: "IMAGE_FROM_USER", arguments: [eventSenderName as Any, messageContent as Any]) + break + default: + // Encrypted messages falls here + notificationBody = NSString.localizedUserNotificationString(forKey: "MESSAGE", arguments: []) + break + } } - } - - if !isHighlighted { - // Ignore this notif. - NSLog("[NotificationService] notificationContentForEvent: Ignore non highlighted notif in mentions only room") - onComplete(nil) - return - } - } - - var msgType = event.content["msgtype"] as? String - let messageContent = event.content["body"] as? String - - if event.isEncrypted && !self.showDecryptedContentInNotifications { - // Hide the content - msgType = nil - } - - // Display the room name only if it is different than the sender name - if roomDisplayName != nil && roomDisplayName != eventSenderName { - notificationTitle = NSString.localizedUserNotificationString(forKey: "MSG_FROM_USER_IN_ROOM_TITLE", arguments: [eventSenderName as Any, roomDisplayName as Any]) - - if msgType == kMXMessageTypeText { - notificationBody = messageContent - } else if msgType == kMXMessageTypeEmote { - notificationBody = NSString.localizedUserNotificationString(forKey: "ACTION_FROM_USER", arguments: [eventSenderName as Any, messageContent as Any]) - } else if msgType == kMXMessageTypeImage { - notificationBody = NSString.localizedUserNotificationString(forKey: "IMAGE_FROM_USER", arguments: [eventSenderName as Any, messageContent as Any]) - } else { - // Encrypted messages falls here - notificationBody = NSString.localizedUserNotificationString(forKey: "MESSAGE", arguments: []) - } - } else { - notificationTitle = eventSenderName - - switch msgType { - case kMXMessageTypeText: - notificationBody = messageContent - break - case kMXMessageTypeEmote: - notificationBody = NSString.localizedUserNotificationString(forKey: "ACTION_FROM_USER", arguments: [eventSenderName as Any, messageContent as Any]) - break - case kMXMessageTypeImage: - notificationBody = NSString.localizedUserNotificationString(forKey: "IMAGE_FROM_USER", arguments: [eventSenderName as Any, messageContent as Any]) break + case .roomMember: + if roomDisplayName != nil && roomDisplayName != eventSenderName { + notificationBody = NSString.localizedUserNotificationString(forKey: "USER_INVITE_TO_NAMED_ROOM", arguments: [eventSenderName as Any, roomDisplayName as Any]) + } else { + notificationBody = NSString.localizedUserNotificationString(forKey: "USER_INVITE_TO_CHAT", arguments: [eventSenderName as Any]) + } + case .sticker: + if roomDisplayName != nil && roomDisplayName != eventSenderName { + notificationTitle = NSString.localizedUserNotificationString(forKey: "MSG_FROM_USER_IN_ROOM_TITLE", arguments: [eventSenderName as Any, roomDisplayName as Any]) + } else { + notificationTitle = eventSenderName + } + + notificationBody = NSString.localizedUserNotificationString(forKey: "STICKER_FROM_USER", arguments: [eventSenderName as Any]) default: - // Encrypted messages falls here - notificationBody = NSString.localizedUserNotificationString(forKey: "MESSAGE", arguments: []) break - } - } - break - case .roomMember: - if roomDisplayName != nil && roomDisplayName != eventSenderName { - notificationBody = NSString.localizedUserNotificationString(forKey: "USER_INVITE_TO_NAMED_ROOM", arguments: [eventSenderName as Any, roomDisplayName as Any]) - } else { - notificationBody = NSString.localizedUserNotificationString(forKey: "USER_INVITE_TO_CHAT", arguments: [eventSenderName as Any]) - } - case .sticker: - if roomDisplayName != nil && roomDisplayName != eventSenderName { - notificationTitle = NSString.localizedUserNotificationString(forKey: "MSG_FROM_USER_IN_ROOM_TITLE", arguments: [eventSenderName as Any, roomDisplayName as Any]) - } else { - notificationTitle = eventSenderName } - notificationBody = NSString.localizedUserNotificationString(forKey: "STICKER_FROM_USER", arguments: [eventSenderName as Any]) - default: - break - } - - if self.localAuthenticationService.isProtectionSet { - NSLog("[NotificationService] notificationContentForEvent: Resetting title and body because app protection is set") - notificationBody = NSString.localizedUserNotificationString(forKey: "MESSAGE_PROTECTED", arguments: []) - notificationTitle = nil - } - - guard notificationBody != nil else { - NSLog("[NotificationService] notificationContentForEvent: notificationBody is nil") + if self.localAuthenticationService.isProtectionSet { + NSLog("[NotificationService] notificationContentForEvent: Resetting title and body because app protection is set") + notificationBody = NSString.localizedUserNotificationString(forKey: "MESSAGE_PROTECTED", arguments: []) + notificationTitle = nil + } + + guard notificationBody != nil else { + NSLog("[NotificationService] notificationContentForEvent: notificationBody is nil") + onComplete(nil) + return + } + + let notificationContent = self.notificationContent(withTitle: notificationTitle, + body: notificationBody, + threadIdentifier: threadIdentifier, + userId: currentUserId, + event: event, + pushRule: pushRule) + + NSLog("[NotificationService] notificationContentForEvent: Calling onComplete.") + onComplete(notificationContent) + case .failure(let error): + NSLog("[NotificationService] notificationContentForEvent: error: \(error)") onComplete(nil) - return - } - - let notificationContent = self.notificationContent(withTitle: notificationTitle, - body: notificationBody, - threadIdentifier: threadIdentifier, - userId: currentUserId, - event: event, - pushRule: pushRule) - - NSLog("[NotificationService] notificationContentForEvent: Calling onComplete.") - onComplete(notificationContent) - case .failure(let error): - NSLog("[NotificationService] notificationContentForEvent: error: \(error)") - onComplete(nil) } }) } + /// Get the context of an event. + /// - Parameters: + /// - event: the event + /// - roomId: the id of the room of the event. + /// - completion: Completion block that will return the room state and the sender display name. + private func context(ofEvent event: MXEvent, inRoom roomId: String, + completion: @escaping (MXResponse<(MXRoomState, String)>) -> Void) { + // First get the room state + NotificationService.backgroundSyncService.roomState(forRoomId: roomId) { (response) in + switch response { + case .success(let roomState): + // Extract the member name from room state member + let eventSender = event.sender! + let eventSenderName = roomState.members.memberName(eventSender) ?? eventSender + + // Check if we are happy with it + if eventSenderName != eventSender + || roomState.members.member(withUserId: eventSender) != nil { + completion(.success((roomState, eventSenderName))) + return + } + + // Else, if the room member is not known, use the user profile to avoid to display a Matrix id + NotificationService.backgroundSyncService.profile(ofMember: eventSender, inRoom: roomId) { (response) in + switch response { + case .success((let displayName, _)): + guard let displayName = displayName else { + completion(.success((roomState, eventSender))) + return + } + completion(.success((roomState, displayName))) + + case .failure(_): + completion(.success((roomState, eventSender))) + } + } + case .failure(let error): + completion(.failure(error)) + } + } + } + private func notificationContent(withTitle title: String?, body: String?, threadIdentifier: String?,