diff --git a/.github/workflows/triage-move-labelled.yml b/.github/workflows/triage-move-labelled.yml
index f45257f264..164e3ed914 100644
--- a/.github/workflows/triage-move-labelled.yml
+++ b/.github/workflows/triage-move-labelled.yml
@@ -92,7 +92,8 @@ jobs:
name: Spaces issues to Delight project board
runs-on: ubuntu-latest
if: >
- contains(github.event.issue.labels.*.name, 'Team: Delight')
+ contains(github.event.issue.labels.*.name, 'Team: Delight') ||
+ contains(github.event.issue.labels.*.name, 'Z-AppLayout')
steps:
- uses: octokit/graphql-action@v2.x
with:
diff --git a/CHANGES.md b/CHANGES.md
index 9eec0ef006..8e9b16b55b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,46 @@
+## Changes in 1.8.25 (2022-08-09)
+
+🙌 Improvements
+
+- Upgrade MatrixSDK version ([v0.23.14](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.23.14)).
+- App Layout: Feature flag new App Layout ([#6406](https://github.com/vector-im/element-ios/issues/6406))
+- App Layout: Update All chats screen with latest design ([#6407](https://github.com/vector-im/element-ios/issues/6407))
+- App Layout: Change the App theme according to new design ([#6409](https://github.com/vector-im/element-ios/issues/6409))
+- App Layout: Implemented the new Space selector bottom sheet ([#6410](https://github.com/vector-im/element-ios/issues/6410))
+- Authentication: Update the ReCaptcha icon. ([#6427](https://github.com/vector-im/element-ios/issues/6427))
+- Location sharing: Improve live location sharing expanded map state when no more live location shares. ([#6488](https://github.com/vector-im/element-ios/issues/6488))
+- Location sharing: Render fallback UI when tile server unavailable. ([#6493](https://github.com/vector-im/element-ios/issues/6493))
+- In-app notifications will now also be delivered to Notification Centre. ([#6503](https://github.com/vector-im/element-ios/issues/6503))
+- Authentication: Don't show personalisation steps after registering with a generic SSO provider. ([#6530](https://github.com/vector-im/element-ios/issues/6530))
+
+🐛 Bugfixes
+
+- Room Directory: Show the "switch" button even if there are no public rooms in the homeserver's room directory. ([#4700](https://github.com/vector-im/element-ios/issues/4700))
+- Share Extension: Fix a bug where sending multiple images sometimes resulted in additional duplicates being sent. ([#5922](https://github.com/vector-im/element-ios/issues/5922))
+- Stop using an ephemeral web browser session for SSO authentication. ([#6462](https://github.com/vector-im/element-ios/issues/6462))
+- Media Attachments Viewer: Fixed an issue where dismissing GIFs would show the WebView playing the animation below the interaction transition animation. ([#6475](https://github.com/vector-im/element-ios/issues/6475))
+- Media: Fix a bug where the navigation bar shown when viewing an image wasn't taking the safe area into account. ([#6486](https://github.com/vector-im/element-ios/issues/6486))
+- Home: Use the correct status bar colour when using the dark theme with dark mode disabled. ([#6487](https://github.com/vector-im/element-ios/issues/6487))
+- Authentication: Always start a new authentication flow with the default homeserver (or the provisioning link if set). ([#6489](https://github.com/vector-im/element-ios/issues/6489))
+- Universal Links: Fix an infinite loop when handling a universal link for an unjoined room (or in some cases a crash). ([#6492](https://github.com/vector-im/element-ios/issues/6492))
+- App Layout: Conditionally hide favourite and people list tabs ([#6515](https://github.com/vector-im/element-ios/issues/6515))
+- Apply current theme to all the UI components ([#6526](https://github.com/vector-im/element-ios/issues/6526))
+- Some UI tweaks for New App Layout ([#6534](https://github.com/vector-im/element-ios/issues/6534))
+- Widgets: Fix a crash when loading the widget manager. ([#6539](https://github.com/vector-im/element-ios/issues/6539))
+
+⚠️ API Changes
+
+- Update the app's bundle name to show Element during SSO. ([#6462](https://github.com/vector-im/element-ios/issues/6462))
+
+📄 Documentation
+
+- Add docs/Customisation.md. ([#6473](https://github.com/vector-im/element-ios/issues/6473))
+
+🚧 In development 🚧
+
+- App Layout: Edit layout experiment ([#6079](https://github.com/vector-im/element-ios/issues/6079))
+
+
## Changes in 1.8.24 (2022-07-26)
✨ Features
diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig
index d15503f1b2..11f0ce3d14 100644
--- a/Config/AppVersion.xcconfig
+++ b/Config/AppVersion.xcconfig
@@ -15,5 +15,5 @@
//
// Version
-MARKETING_VERSION = 1.8.24
-CURRENT_PROJECT_VERSION = 1.8.24
+MARKETING_VERSION = 1.8.25
+CURRENT_PROJECT_VERSION = 1.8.25
diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift
index 60d7b7528d..0e62091630 100644
--- a/Config/BuildSettings.swift
+++ b/Config/BuildSettings.swift
@@ -235,7 +235,7 @@ final class BuildSettings: NSObject {
static let allowInviteExernalUsers: Bool = true
// MARK: - Side Menu
- static let enableSideMenu: Bool = true
+ static let enableSideMenu: Bool = true && !newAppLayoutEnabled
static let sideMenuShowInviteFriends: Bool = true
/// Whether to read the `io.element.functional_members` state event and exclude any service members when computing a room's name and avatar.
@@ -419,4 +419,7 @@ final class BuildSettings: NSObject {
static let showUnsupportedEventsInRoomHistory: Bool = false
static let sortRoomMembersUsingLastSeenTime: Bool = true
static let syncLocalContacts: Bool = false
+
+ // MARK: - New App Layout
+ static let newAppLayoutEnabled = false
}
diff --git a/Podfile b/Podfile
index fdaa63bdff..4b6d3de3a2 100644
--- a/Podfile
+++ b/Podfile
@@ -16,7 +16,7 @@ use_frameworks!
# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK 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
-$matrixSDKVersion = '= 0.23.13'
+$matrixSDKVersion = '= 0.23.14'
# $matrixSDKVersion = :local
# $matrixSDKVersion = { :branch => 'develop'}
# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } }
diff --git a/Podfile.lock b/Podfile.lock
index 9342eb19ad..cbd9fced3d 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -56,9 +56,9 @@ PODS:
- LoggerAPI (1.9.200):
- Logging (~> 1.1)
- Logging (1.4.0)
- - MatrixSDK (0.23.13):
- - MatrixSDK/Core (= 0.23.13)
- - MatrixSDK/Core (0.23.13):
+ - MatrixSDK (0.23.14):
+ - MatrixSDK/Core (= 0.23.14)
+ - MatrixSDK/Core (0.23.14):
- AFNetworking (~> 4.0.0)
- GZIP (~> 1.3.0)
- libbase58 (~> 0.1.4)
@@ -66,9 +66,9 @@ PODS:
- OLMKit (~> 3.2.5)
- Realm (= 10.27.0)
- SwiftyBeaver (= 1.9.5)
- - MatrixSDK/CryptoSDK (0.23.13):
+ - MatrixSDK/CryptoSDK (0.23.14):
- MatrixSDKCrypto (= 0.1.0)
- - MatrixSDK/JingleCallStack (0.23.13):
+ - MatrixSDK/JingleCallStack (0.23.14):
- JitsiMeetSDK (= 5.0.2)
- MatrixSDK/Core
- MatrixSDKCrypto (0.1.0)
@@ -123,8 +123,8 @@ DEPENDENCIES:
- KeychainAccess (~> 4.2.2)
- KTCenterFlowLayout (~> 1.3.1)
- libPhoneNumber-iOS (~> 0.9.13)
- - MatrixSDK (= 0.23.13)
- - MatrixSDK/JingleCallStack (= 0.23.13)
+ - MatrixSDK (= 0.23.14)
+ - MatrixSDK/JingleCallStack (= 0.23.14)
- OLMKit
- PostHog (~> 1.4.4)
- ReadMoreTextView (~> 3.0.1)
@@ -221,7 +221,7 @@ SPEC CHECKSUMS:
libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
Logging: beeb016c9c80cf77042d62e83495816847ef108b
- MatrixSDK: 4e14176a819982d9aec9d19e30afad9f63968a32
+ MatrixSDK: a62f8aafa25623f261599fdc2e734043da548440
MatrixSDKCrypto: 4b9146d5ef484550341be056a164c6930038028e
OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5
PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f
@@ -241,6 +241,6 @@ SPEC CHECKSUMS:
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
-PODFILE CHECKSUM: c7d08e5d0654296048d53c9c6720783efcf897bd
+PODFILE CHECKSUM: 010dde83f230d559fc7987ccdbb0f0069418a319
COCOAPODS: 1.11.2
diff --git a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme
index f973b344c6..6eba9ae711 100644
--- a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme
+++ b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme
@@ -27,9 +27,18 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- onlyGenerateCoverageForSpecifiedTargets = "NO"
shouldUseLaunchSchemeArgsEnv = "YES"
- disableMainThreadChecker = "YES">
+ disableMainThreadChecker = "YES"
+ onlyGenerateCoverageForSpecifiedTargets = "NO">
+
+
+
+
@@ -42,15 +51,6 @@
-
-
-
-
@@ -58,13 +58,13 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ disableMainThreadChecker = "YES"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
- allowLocationSimulation = "YES"
- disableMainThreadChecker = "YES">
+ allowLocationSimulation = "YES">
-
+
-
+
@@ -166,7 +166,34 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -231,6 +258,7 @@
+
@@ -304,7 +332,7 @@
-
+
@@ -497,7 +525,7 @@
-
+
diff --git a/Riot/Assets/Images.xcassets/Authentication/authentication_recaptcha_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/Authentication/authentication_recaptcha_icon.imageset/Contents.json
new file mode 100644
index 0000000000..a6455cb69d
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/Authentication/authentication_recaptcha_icon.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "recaptcha_pumpkin.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/Riot/Assets/Images.xcassets/Authentication/authentication_recaptcha_icon.imageset/recaptcha_pumpkin.svg b/Riot/Assets/Images.xcassets/Authentication/authentication_recaptcha_icon.imageset/recaptcha_pumpkin.svg
new file mode 100644
index 0000000000..7515e4e997
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/Authentication/authentication_recaptcha_icon.imageset/recaptcha_pumpkin.svg
@@ -0,0 +1,5 @@
+
+
+
diff --git a/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/Contents.json b/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/Contents.json
index da4a164c91..73c00596a7 100644
--- a/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/Contents.json
+++ b/Riot/Assets/Images.xcassets/Home/RoomContextualMenu/Contents.json
@@ -1,6 +1,6 @@
{
"info" : {
- "version" : 1,
- "author" : "xcode"
+ "author" : "xcode",
+ "version" : 1
}
-}
\ No newline at end of file
+}
diff --git a/Riot/Assets/Images.xcassets/Home/home_my_spaces_action.imageset/Contents.json b/Riot/Assets/Images.xcassets/Home/home_my_spaces_action.imageset/Contents.json
new file mode 100644
index 0000000000..d50c95b024
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/Home/home_my_spaces_action.imageset/Contents.json
@@ -0,0 +1,25 @@
+{
+ "images" : [
+ {
+ "filename" : "home_my_spaces_action.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true,
+ "template-rendering-intent" : "template"
+ }
+}
diff --git a/Riot/Assets/Images.xcassets/Home/home_my_spaces_action.imageset/home_my_spaces_action.svg b/Riot/Assets/Images.xcassets/Home/home_my_spaces_action.imageset/home_my_spaces_action.svg
new file mode 100644
index 0000000000..3b956bb6b2
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/Home/home_my_spaces_action.imageset/home_my_spaces_action.svg
@@ -0,0 +1,6 @@
+
diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_map_error.imageset/Contents.json b/Riot/Assets/Images.xcassets/Room/Location/location_map_error.imageset/Contents.json
new file mode 100644
index 0000000000..dc48b59945
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/Room/Location/location_map_error.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "location_map_error.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "template-rendering-intent" : "original"
+ }
+}
diff --git a/Riot/Assets/Images.xcassets/Room/Location/location_map_error.imageset/location_map_error.svg b/Riot/Assets/Images.xcassets/Room/Location/location_map_error.imageset/location_map_error.svg
new file mode 100644
index 0000000000..56323f1463
--- /dev/null
+++ b/Riot/Assets/Images.xcassets/Room/Location/location_map_error.imageset/location_map_error.svg
@@ -0,0 +1,3 @@
+
diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings
index 4ffe267aee..b3e4a2048b 100644
--- a/Riot/Assets/de.lproj/Vector.strings
+++ b/Riot/Assets/de.lproj/Vector.strings
@@ -234,7 +234,7 @@
"settings_term_conditions" = "Geschäftsbedingungen";
"settings_privacy_policy" = "Datenschutzerklärung";
"settings_send_crash_report" = "Sende anonyme Absturz- und Nutzungsdaten";
-"settings_change_password" = "Passwort deines Matrix-Kontos ändern";
+"settings_change_password" = "Passwort ändern";
"settings_old_password" = "altes Passwort";
"settings_new_password" = "neues Passwort";
"settings_confirm_password" = "bestätige Passwort";
@@ -289,8 +289,8 @@
"room_creation_invite_another_user" = "Benutzer-ID, Name oder E-Mail";
"room_recents_join_room_prompt" = "Gib eine Raum-ID oder einem Raum-Alias an";
"directory_cell_description" = "%tu Räume";
-"directory_search_results" = "%tu Treffer gefunden für %@";
-"directory_search_results_more_than" = ">%tu Treffer gefunden für %@";
+"directory_search_results" = "%1$tu Treffer gefunden für %2$@";
+"directory_search_results_more_than" = ">%1$tu Treffer gefunden für %2$@";
"contacts_address_book_permission_denied" = "%@ wurde nicht erlaubt, auf lokale Kontakte zuzugreifen";
"room_participants_remove_third_party_invite_msg" = "Entfernen der Einladung von Dritten ist noch nicht unterstützt";
"room_participants_invite_another_user" = "Suchen/Einladen mittels Benutzer-ID, Name oder E-Mail-Adresse";
@@ -1181,7 +1181,7 @@
"create_room_section_header_name" = "Raumname";
"create_room_placeholder_name" = "Name";
"create_room_section_header_topic" = "Raumthema (optional)";
-"create_room_placeholder_topic" = "Thema";
+"create_room_placeholder_topic" = "Um was geht es in diesem Raum?";
"create_room_section_header_encryption" = "Raumverschlüsselung";
"create_room_enable_encryption" = "Verschlüsselung aktivieren";
"create_room_section_footer_encryption" = "Verschlüsselung kann im Nachhinein nicht deaktiviert werden.";
@@ -2232,3 +2232,192 @@
"authentication_login_username" = "Nutzername / E-Mail-Adresse / Telefonnummer";
"authentication_login_title" = "Willkommen zurück!";
"authentication_server_selection_login_title" = "Mit Homeserver verbinden";
+"location_sharing_invalid_power_level_message" = "Du brauchst die richtigen Berechtigungen, um deinen Live-Standort in diesem Raum zu teilen.";
+"location_sharing_invalid_power_level_title" = "Du hast keine Berechtigung deinen Live-Standort zu teilen";
+"authentication_choose_password_not_verified_message" = "Überprüfe deinen Posteingang";
+"authentication_choose_password_not_verified_title" = "E-Mail Adresse nicht bestätigt";
+"message_reply_to_sender_sent_their_live_location" = "Live-Standort.";
+"location_sharing_live_lab_promotion_activation" = "Aktiviere Live-Standortfreigabe";
+"location_sharing_live_lab_promotion_text" = "Bitte beachte: Dies ist eine experimentelle Funktion. Sie benutzt eine temporäre Implementation und ermöglicht, dass andere Personen in diesem Raum den Verlauf deines geteilten Standortes permanent sehen können.";
+"location_sharing_live_lab_promotion_title" = "Live-Standort-Freigabe";
+"room_info_back_button_title" = "Raum-Info";
+"network_offline_message" = "Du bist offline, überprüfe deine Internetverbindung.";
+"network_offline_title" = "Du bist offline";
+
+// MARK: Reactions
+
+"room_event_action_reaction_more" = "%@ mehr";
+"leave_space_selection_no_rooms" = "Wähle keine Räume";
+"leave_space_selection_all_rooms" = "Wähle alle Räume";
+"leave_space_selection_title" = "RÄUME WÄHLEN";
+"leave_space_and_more_rooms" = "Verlasse Space und %@ Räume";
+"leave_space_and_one_room" = "Verlasse Space und 1 Raum";
+
+// Mark: Leave space
+
+"leave_space_action" = "Space verlassen";
+"spaces_feature_not_available" = "Diese Funktion ist hier nicht verfügbar. Derzeit kannst du es mit %@ auf deinem Computer machen.";
+"home_context_menu_mark_as_read" = "Als gelesen markieren";
+"settings_timeline" = "ZEITLINIE";
+"room_accessibility_record_voice_message_hint" = "Tippe doppelt und halte zum Aufnehmen.";
+"room_accessibility_record_voice_message" = "Sprachnachricht aufnehmen";
+"settings_ui_show_redactions_in_room_history" = "Zeige einen Platzhalter für entfernte Nachrichten";
+"location_sharing_allow_background_location_cancel_action" = "Nicht jetzt";
+"location_sharing_allow_background_location_validate_action" = "Einstellungen";
+"location_sharing_allow_background_location_title" = "Zugriff erlauben";
+"settings_labs_enable_live_location_sharing" = "Teilen des Live-Standortes - teile deinen aktuellen Standort (aktive Entwicklung, temporäre Standorte bleiben im Verlauf des Raums)";
+"location_sharing_live_stop_sharing_progress" = "Standort-Freigabe beenden";
+"location_sharing_live_stop_sharing_error" = "Teilen des Live-Standortes konnte nicht gestoppt werden";
+"location_sharing_live_no_user_locations_error_title" = "Keine Standorte verfügbar";
+"location_sharing_live_timer_selector_long" = "für 8 Stunden";
+"location_sharing_live_timer_selector_medium" = "für 1 Stunde";
+"location_sharing_live_timer_selector_short" = "für 15 Minuten";
+"location_sharing_live_timer_selector_title" = "Lege fest, wie lange dein genauer Standort für andere sichtbar ist.";
+"location_sharing_live_error" = "Live-Standort fehlgeschlagen";
+"location_sharing_live_loading" = "Lade Live-Standort...";
+"location_sharing_live_timer_incoming" = "Live bis %@";
+"live_location_sharing_ended" = "Live-Standort beendet";
+"location_sharing_live_list_item_stop_sharing_action" = "Stop";
+"location_sharing_live_list_item_current_user_display_name" = "Du";
+"location_sharing_live_list_item_last_update_invalid" = "Letzter Standort unbekannt";
+"location_sharing_live_list_item_last_update" = "Vor %@ aktualisiert";
+"location_sharing_live_list_item_sharing_expired" = "Freigabe abgelaufen";
+"location_sharing_live_list_item_time_left" = "%@ hat verlassen";
+"location_sharing_live_viewer_title" = "Standort";
+"location_sharing_live_map_callout_title" = "Standort teilen";
+"settings_presence_offline_mode_description" = "Wenn diese Option aktiviert ist, wirst Du anderen Nutzer:innen immer als offline angezeigt, auch wenn Du die Anwendung verwendest.";
+"settings_presence_offline_mode" = "Offline-Modus";
+"settings_presence" = "Präsenz";
+"threads_discourage_information_2" = "\n\nWillst du Threads trotzdem aktivieren?";
+"threads_beta_cancel" = "Nicht jetzt";
+"threads_beta_enable" = "Probiere es aus";
+"threads_beta_information_link" = "Mehr Informationen";
+"threads_beta_information" = "Organisiere Diskussionen mit Threads.\n\nThreads helfen, Konversationen zu folgen und beim Thema zu bleiben. ";
+"threads_beta_title" = "Threads";
+"ignore_user" = "Nutzer:in ignorieren";
+"location_sharing_pin_drop_share_title" = "Teile diesen Standort";
+"location_sharing_static_share_title" = "Meinen aktuellen Standort schicken";
+"live_location_sharing_banner_stop" = "Stop";
+"live_location_sharing_banner_title" = "Live-Standort aktiviert";
+
+// MARK: Live location sharing
+
+"location_sharing_live_share_title" = "Teile Live-Standort";
+"side_menu_coach_message" = "Wische nach rechts oder tippe, um alle Räume zu sehen.";
+"spaces_add_room_missing_permission_message" = "Du hast keine Berechtigung, Räume zu diesem Space hinzuzufügen.";
+"spaces_creation_in_one_space" = "in 1 Space";
+"spaces_creation_in_many_spaces" = "in %@ Spaces";
+"spaces_creation_in_spacename_plus_many" = "in %@ + %@ Spaces";
+"spaces_creation_in_spacename_plus_one" = "in %@ + 1 Space";
+"spaces_creation_in_spacename" = "in %@";
+"spaces_creation_post_process_inviting_users" = "Lade %@ Nutzer:innen ein";
+"spaces_creation_post_process_adding_rooms" = "Füge %@ Räume hinzu";
+"spaces_creation_post_process_creating_room" = "Erstelle %@";
+"spaces_creation_post_process_uploading_avatar" = "Lade Profilbild hoch";
+"spaces_creation_post_process_creating_space_task" = "Erstelle %@";
+"spaces_creation_post_process_creating_space" = "Erstelle Space";
+"spaces_creation_invite_by_username_message" = "Du kannst sie auch später einladen.";
+"spaces_creation_invite_by_username_title" = "Lade dein Team ein";
+"spaces_creation_invite_by_username" = "Per Benutzername einladen";
+"spaces_creation_add_rooms_message" = "Da dieser Space nur für dich ist, wird niemand benachrichtigt. Du kannst später mehrere Personen hinzufügen.";
+"spaces_creation_add_rooms_title" = "Was willst du hinzufügen?";
+"spaces_creation_sharing_type_me_and_teammates_detail" = "Ein privater Space für dich & deine Teamkollegen";
+"spaces_creation_sharing_type_me_and_teammates_title" = "Teamkollegen und ich";
+"spaces_creation_sharing_type_just_me_detail" = "Ein privater Space zum Organisieren deiner Räume";
+"spaces_creation_sharing_type_just_me_title" = "Nur ich";
+"spaces_creation_sharing_type_message" = "Stelle sicher, dass die richtigen Personen Zugriff haben %@. Du kannst dies später ändern.";
+"spaces_creation_sharing_type_title" = "Mit wem arbeitest du zusammen?";
+"spaces_creation_email_invites_email_title" = "E-Mail";
+"spaces_creation_email_invites_message" = "Du kannst sie auch später einladen.";
+"spaces_creation_email_invites_title" = "Lade dein Team ein";
+"spaces_creation_new_rooms_support" = "Support";
+"spaces_creation_new_rooms_random" = "Zufällig";
+"spaces_creation_new_rooms_general" = "Allgemein";
+"spaces_creation_new_rooms_room_name_title" = "Raumname";
+"spaces_creation_new_rooms_title" = "Worüber werdet ihr reden?";
+"spaces_creation_cancel_message" = "Dein Fortschritt geht verloren.";
+"spaces_creation_cancel_title" = "Erstellen des Space abbrechen?";
+"spaces_creation_private_space_title" = "Dein privater Space";
+"spaces_creation_public_space_title" = "Dein öffentlicher Space";
+"spaces_creation_address_already_exists" = "%@\nexistiert bereits";
+"spaces_creation_address_invalid_characters" = "%@\nhat ungültige Zeichen";
+"spaces_creation_address_default_message" = "Dein Space ist sichtbar unter\n%@";
+"spaces_creation_empty_room_name_error" = "Name wird benötigt";
+"spaces_creation_address" = "Adresse";
+"spaces_creation_settings_message" = "Füge ein paar Details hinzu, um die Auffälligkeit zu steigern. Diese Einstellungen können jederzeit geändert werden.";
+"spaces_creation_footer" = "Du kannst dies später ändern";
+"spaces_creation_visibility_message" = "Du benötigst eine Einladung, um einem existierenden Space beizutreten.";
+"spaces_creation_visibility_title" = "Welche Art von Space möchtest du erstellen?";
+
+// Mark: - Space Creation
+
+"spaces_creation_hint" = "Spaces sind eine neue Art, Räume und Personen zu gruppieren.";
+"space_settings_current_address_message" = "Dein Space ist sichtbar unter\n%@";
+"space_settings_update_failed_message" = "Aktualisieren der Space-Einstellungen fehlgeschlagen. Erneut versuchen?";
+"space_settings_access_section" = "Wer hat Zugriff auf diesen Space?";
+"space_topic" = "Beschreibung";
+"space_public_join_rule_detail" = "Offen für alle, am Besten für Communities";
+"spaces_add_space" = "Space hinzufügen";
+"spaces_add_room" = "Raum hinzufügen";
+"spaces_invite_people" = "Personen einladen";
+"space_private_join_rule_detail" = "Beschränkt durch Einladung, am Besten für dich selbst oder für Teams";
+"spaces_explore_rooms_one_room" = "1 Raum";
+"spaces_explore_rooms_room_number" = "%@ Räume";
+"spaces_create_space_title" = "Einen Space erstellen";
+"spaces_add_space_title" = "Space erstellen";
+"space_invite_not_enough_permission" = "Du hast keine Berechtigung, Personen zu diesem Space einzuladen";
+"room_invite_not_enough_permission" = "Du hast keine Berechtigung, Personen zu diesem Raum einzuladen";
+"room_invite_to_room_option_detail" = "Sie werden kein Teil von %@ sein.";
+"room_invite_to_room_option_title" = "Nur zu diesem Raum";
+"room_invite_to_space_option_detail" = "Sie können %@ erkunden, werden aber kein Mitglied von %@ sein.";
+
+// Mark: - Room invite
+
+"room_invite_to_space_option_title" = "Zu %@";
+"share_invite_link_space_text" = "Hey, tritt diesem Raum auf %@ bei.";
+"share_invite_link_room_text" = "Hey, tritt diesem Raum auf %@ bei.";
+
+// MARK: - Share invite link
+
+"share_invite_link_action" = "Einladungslink teilen";
+"create_room_processing" = "Erstelle Raum";
+"create_room_suggest_room_footer" = "Vorgeschlagene Räume werden Space-Mitgliedern empfohlen.";
+"create_room_suggest_room" = "Space-Mitgliedern vorschlagen";
+"create_room_show_in_directory_footer" = "Dadurch sind Sichtbarkeit und Zugang vereinfacht.";
+"create_room_promotion_header" = "BEFÖRDERUNG";
+"create_room_section_footer_type_restricted" = "Sichtbar und betretbar für jeden im Space.";
+"create_room_section_footer_type_private" = "Nur sichtbar und betretbar für eingeladene Personen.";
+"create_room_type_restricted" = "Space-Mitglieder";
+"call_jitsi_unable_to_start" = "Starten der Telefonkonferenz nicht möglich";
+"room_suggestion_settings_screen_message" = "Vorgeschlagene Räume werden Space-Mitgliedern empfohlen.";
+"room_suggestion_settings_screen_title" = "Empfehle einen Raum in einem Space";
+
+// Room suggestion Settings
+"room_suggestion_settings_screen_nav_title" = "Raum vorschlagen";
+"room_access_space_chooser_other_spaces_section_info" = "Diese sind vermutlich Dinge, zu denen andere Admins von %@ gehören.";
+"room_access_space_chooser_other_spaces_section" = "Andere Spaces oder Räume";
+"room_access_settings_screen_setting_room_access" = "Lege Raumzugriff fest";
+"room_access_settings_screen_upgrade_alert_upgrading" = "Raum upgraden";
+"room_access_settings_screen_upgrade_alert_upgrade_button" = "Upgrade";
+"room_access_settings_screen_upgrade_alert_auto_invite_switch" = "Mitglieder automatisch zu neuem Raum einladen";
+"room_access_settings_screen_upgrade_alert_message" = "Jeder in %@ kann diesen Raum finden und ihm beitreten - jeden manuell einzuladen ist nicht nötig. Du kannst diese Einstellung jederzeit ändern.";
+"room_access_settings_screen_upgrade_alert_title" = "Raum upgraden";
+"room_access_settings_screen_edit_spaces" = "Spaces bearbeiten";
+"room_access_settings_screen_upgrade_required" = "Upgrade erforderlich";
+"room_access_settings_screen_message" = "Lege fest, wer %@ finden und beitreten kann.";
+"room_access_settings_screen_title" = "Wer kann auf diesen Raum zugreifen?";
+
+// Room Access Settings
+"room_access_settings_screen_nav_title" = "Raumzugang";
+"room_details_promote_room_suggest_title" = "Space-Mitgliedern vorschlagen";
+"room_details_promote_room_title" = "Raum bewerben";
+"room_details_access_row_title" = "Zugriff";
+"settings_labs_enable_auto_report_decryption_errors" = "Entschlüsselungsfehler automatisch melden";
+"room_preview_decline_invitation_options" = "Willst du die Einladung ablehnen oder den Nutzer ignorieren?";
+"threads_notice_done" = "Verstanden";
+"threads_notice_information" = "Alle Threads, die während der experimentellen Phase erstellt wurden, werden nun als reguläre Antworten angezeigt.
Dies ist eine einmalige Änderung, da Threads nun Teil der Matrix-Spezifikation sind.";
+"threads_notice_title" = "Threads sind nicht länger experimentell. 🎉";
+"room_participants_invite_prompt_to_msg" = "Bist du sicher, dass du %@ zu %@ einladen möchtest?";
+"room_displayname_more_than_two_members" = "%@ und %@ andere";
+"settings_key_backup_info_algorithm" = "Algorithmus: %@";
+"joining" = "Trete bei";
diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings
index f58e68824b..7ff7f0697a 100644
--- a/Riot/Assets/en.lproj/Vector.strings
+++ b/Riot/Assets/en.lproj/Vector.strings
@@ -1996,7 +1996,9 @@ Tap the + to start adding people.";
"spaces_home_space_title" = "Home";
"spaces_add_space_title" = "Create space";
+"spaces_add_subspace_title" = "Create space within %@";
"spaces_create_space_title" = "Create a space";
+"spaces_create_subspace_title" = "Create a subspace";
"spaces_left_panel_title" = "Spaces";
"leave_space_title" = "Leave %@";
"leave_space_message" = "Are you sure you want to leave %@? Do you also want to leave all rooms and spaces of this space?";
@@ -2042,6 +2044,8 @@ Tap the + to start adding people.";
"spaces_creation_hint" = "Spaces are a new way to group rooms and people.";
"spaces_creation_visibility_title" = "What type of space do you want to create?";
"spaces_creation_visibility_message" = "To join an existing space, you need an invite.";
+"spaces_subspace_creation_visibility_title" = "What type of subspace do you want to create?";
+"spaces_subspace_creation_visibility_message" = "The created space will be added to %@.";
"spaces_creation_footer" = "You can change this later";
"spaces_creation_settings_message" = "Add some details to help it stand out. You can change these at any point.";
"spaces_creation_address" = "Address";
@@ -2153,6 +2157,37 @@ Tap the + to start adding people.";
"version_check_modal_subtitle_deprecated" = "We've been working on enhancing %@ for a faster and more polished experience. Unfortunately your current version of iOS is not compatible with some of those fixes and is no longer supported.\nWe're advising you to upgrade your operating system to use %@ to its full potential.";
"version_check_modal_action_title_deprecated" = "Find out how";
+// Mark: - All Chats
+
+"all_chats_title" = "All chats";
+"all_chats_section_title" = "Chats";
+"all_chats_edit_layout" = "Layout preferences";
+"all_chats_edit_layout_recents" = "Recents";
+"all_chats_edit_layout_unreads" = "Unreads";
+"all_chats_edit_layout_add_section_title" = "Add section to home";
+"all_chats_edit_layout_add_section_message" = "Pin sections to home for easy access";
+"all_chats_edit_layout_add_filters_title" = "Filter your messages";
+"all_chats_edit_layout_add_filters_message" = "Automatically filter your messages into the categories of your choice";
+"all_chats_edit_layout_pin_spaces_title" = "Pin your spaces";
+"all_chats_edit_layout_sorting_options_title" = "Sort messages by";
+
+"all_chats_edit_layout_show_recents" = "Show recents";
+"all_chats_edit_layout_show_filters" = "Show filters";
+"all_chats_edit_layout_activity_order" = "Sort by activity";
+"all_chats_edit_layout_alphabetical_order" = "Sort A-Z";
+"all_chats_all_filter" = "All";
+
+"room_recents_recently_viewed_section" = "Recently viewed";
+
+"all_chats_user_menu_settings" = "User settings";
+
+"all_chats_edit_menu_leave_space" = "Leave %@";
+"all_chats_edit_menu_space_settings" = "Space settings";
+
+// Mark: - Space Selector
+
+"space_selector_title" = "My spaces";
+
// Mark: - Polls
"poll_edit_form_create_poll" = "Create poll";
@@ -2252,6 +2287,7 @@ To enable access, tap Settings> Location and select Always";
"location_sharing_allow_background_location_validate_action" = "Settings";
"location_sharing_allow_background_location_cancel_action" = "Not now";
"location_sharing_map_credits_title" = "© Copyright";
+"location_sharing_map_loading_error" = "Unable to load map\nThis homeserver is not configured to display maps";
// MARK: Live location sharing
diff --git a/Riot/Assets/es.lproj/Vector.strings b/Riot/Assets/es.lproj/Vector.strings
index 28b38dd38e..34dc438b10 100644
--- a/Riot/Assets/es.lproj/Vector.strings
+++ b/Riot/Assets/es.lproj/Vector.strings
@@ -358,7 +358,7 @@
"settings_crypto_device_key" = "\nClave de la sesión:\n";
"settings_crypto_export" = "Exportar claves";
"settings_crypto_blacklist_unverified_devices" = "Cifrar solo a sesiones verificadas";
-"settings_deactivate_my_account" = "Desactivar mi cuenta";
+"settings_deactivate_my_account" = "Desactivar cuenta permanentemente";
// Room Details
"room_details_title" = "Detalles de Sala";
"room_details_people" = "Miembros";
@@ -1083,13 +1083,13 @@
"room_recents_suggested_rooms_section" = "SALAS SUGERIDAS";
"onboarding_use_case_existing_server_button" = "Conectar a un servidor";
"onboarding_use_case_existing_server_message" = "¿Te quieres unir a un servidor que ya existe?";
-"onboarding_use_case_skip_button" = "saltar esta pregunta";
+"onboarding_use_case_skip_button" = "Saltar esta pregunta";
/* The placeholder string contains onboarding_use_case_skip_button as a tappable action */
"onboarding_use_case_not_sure_yet" = "¿Todavía no lo sabes? Puedes %@";
"onboarding_use_case_community_messaging" = "Comunidades";
"onboarding_use_case_work_messaging" = "Equipos";
"onboarding_use_case_personal_messaging" = "Familia y amigos";
-"onboarding_use_case_message" = "Te vamos a ayudar a conectarte.";
+"onboarding_use_case_message" = "Te vamos a ayudar a conectarte";
"onboarding_use_case_title" = "¿Con quién vas a hablar más?";
"onboarding_splash_page_4_message" = "Element también funciona genial en el trabajo. Usado por algunas de las organizaciones más seguras.";
"onboarding_splash_page_4_title_no_pun" = "Mensajería para tu equipo.";
@@ -2372,7 +2372,7 @@
"threads_notice_done" = "Vale";
"onboarding_celebration_button" = "Continuar";
"onboarding_celebration_message" = "Ve a ajustes cuando quieras para actualizar tu perfil";
-"onboarding_celebration_title" = "¡Ya estás!";
+"onboarding_celebration_title" = "¡Ya está!";
"onboarding_avatar_accessibility_label" = "Imagen de perfil";
"onboarding_display_name_max_length" = "Tu nombre público debe tener menos de 256 caracteres";
"onboarding_display_name_hint" = "Puedes cambiarlo más adelante";
@@ -2483,3 +2483,14 @@
// MARK: Authentication
"authentication_registration_title" = "Crea una cuenta";
+"message_reply_to_sender_sent_their_live_location" = "Ubicación en tiempo real.";
+"authentication_recaptcha_title" = "¿Eres una persona?";
+/* The placeholder will show the homeserver's domain */
+"authentication_terms_message" = "Por favor, lee las condiciones de uso de %@";
+"authentication_terms_title" = "Políticas del servidor";
+"authentication_verify_msisdn_waiting_button" = "Volver a enviar código";
+"authentication_verify_msisdn_otp_text_field_placeholder" = "Código de confirmación";
+"authentication_verify_msisdn_text_field_placeholder" = "Número de teléfono";
+"authentication_choose_password_not_verified_message" = "Comprueba tu bandeja de entrada";
+"authentication_choose_password_text_field_placeholder" = "Nueva contraseña";
+"authentication_forgot_password_waiting_button" = "Volver a enviar correo";
diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings
index 13ab005543..1d7221745b 100644
--- a/Riot/Assets/et.lproj/Vector.strings
+++ b/Riot/Assets/et.lproj/Vector.strings
@@ -2318,3 +2318,56 @@
// MARK: Authentication
"authentication_registration_title" = "Loo endale konto";
"authentication_server_info_title_login" = "Kuidas sinu vestlusi hallatakse";
+"message_reply_to_sender_sent_their_live_location" = "Asukoht reaalajas.";
+"location_sharing_invalid_power_level_message" = "Selles jututoas asukoha jagamiseks peavad sul olema vastavad õigused.";
+"location_sharing_invalid_power_level_title" = "Sul pole vajalikke õigusi asukoha jagamiseks reaalajas";
+"password_validation_error_contain_symbol" = "Peab sisaldama sümbolit.";
+"password_validation_error_contain_number" = "Peab sisaldama numbrit.";
+"password_validation_error_contain_uppercase_letter" = "Peab sisaldama suurtähte.";
+"password_validation_error_contain_lowercase_letter" = "Peab sisaldama väiketähte.";
+/* The placeholder will show a number */
+"password_validation_error_max_length" = "Mitte enam kui %d tähemärki.";
+/* The placeholder will show a number */
+"password_validation_error_min_length" = "Vähemalt %d tähemärki.";
+"password_validation_error_header" = "Antud salasõna ei vasta järgnevatele tingimustele:";
+
+// MARK: Password Validation
+"password_validation_info_header" = "Sinu salasõna peaks vastama järgnevatele tingimustele:";
+"authentication_recaptcha_title" = "Kas sa ikka oled inimene?";
+"authentication_terms_policy_url_error" = "Serveri reeglite või kasutustingimuste aadressi ei õnnestu avada. Palun proovi hiljem uuesti.";
+/* The placeholder will show the homeserver's domain */
+"authentication_terms_message" = "Palun loe %@ serveri reegleid ja kasutustingimusi";
+"authentication_terms_title" = "Serveri reeglid";
+"authentication_verify_msisdn_invalid_phone_number" = "Vigane telefoninumber";
+"authentication_verify_msisdn_waiting_button" = "Saada kinnituskood uuesti";
+/* The placeholder will show the phone number that was entered. */
+"authentication_verify_msisdn_waiting_message" = "Kinnituskoodi saatsime telefoninumbrile %@";
+"authentication_verify_msisdn_waiting_title" = "Kinnita oma telefoninumber";
+"authentication_verify_msisdn_otp_text_field_placeholder" = "Kinnituskood";
+"authentication_verify_msisdn_text_field_placeholder" = "Telefoninumber";
+/* The placeholder will show the homeserver's domain */
+"authentication_verify_msisdn_input_message" = "%@ soovib sinu kasutajakonto verifitseerimist";
+"authentication_verify_msisdn_input_title" = "Sisesta oma telefoninumber";
+"authentication_choose_password_not_verified_message" = "Vaata oma saabuvate e-kirjade postkasti";
+"authentication_choose_password_not_verified_title" = "E-posti aadress on verifitseerimata";
+"authentication_choose_password_submit_button" = "Lähtesta salasõna";
+"authentication_choose_password_signout_all_devices" = "Logi kõik oma seadmed võrgust välja";
+"authentication_choose_password_text_field_placeholder" = "Uus salasõna";
+"authentication_choose_password_input_message" = "Palun kasuta vähemalt 8-tähelist salasõna";
+"authentication_choose_password_input_title" = "Vali uus salasõna";
+"authentication_forgot_password_waiting_button" = "Saada e-kiri uuesti";
+/* The placeholder will show the email address that was entered. */
+"authentication_forgot_password_waiting_message" = "Palun järgi juhtnööre, mille saatsime %@ aadressile";
+"authentication_forgot_password_waiting_title" = "Vaata oma e-kirju.";
+"authentication_forgot_password_text_field_placeholder" = "E-posti aadress";
+/* The placeholder will show the homeserver's domain */
+"authentication_forgot_password_input_message" = "%@ saadab sulle verifitseerimiseks lingi";
+"authentication_forgot_password_input_title" = "Sisesta oma e-posti aadress";
+"authentication_verify_email_waiting_button" = "Saada e-kiri uuesti";
+"authentication_verify_email_waiting_hint" = "Sa ei saanud e-kirja kätte?";
+/* The placeholder will show the email address that was entered. */
+"authentication_verify_email_waiting_message" = "Palun järgi juhtnööre, mille saatsime %@ aadressile";
+"authentication_verify_email_waiting_title" = "Verifitseeri oma e-posti aadress.";
+"authentication_verify_email_text_field_placeholder" = "E-posti aadress";
+/* The placeholder will show the homeserver's domain */
+"authentication_verify_email_input_message" = "%@ soovib sinu kasutajakonto verifitseerimist";
diff --git a/Riot/Assets/fr.lproj/Vector.strings b/Riot/Assets/fr.lproj/Vector.strings
index dc6da6d0b4..e7a16a51a9 100644
--- a/Riot/Assets/fr.lproj/Vector.strings
+++ b/Riot/Assets/fr.lproj/Vector.strings
@@ -2427,3 +2427,16 @@
"room_access_settings_screen_upgrade_alert_upgrading" = "Mise à niveau du salon";
"room_access_settings_screen_upgrade_alert_upgrade_button" = "Mettre à niveau";
"room_access_settings_screen_upgrade_alert_note" = "Veuillez noter que la mise à niveau va créer une nouvelle version de ce salon. Tous les messages actuels vont rester dans ce salon archivé.";
+"joining" = "En train de rejoindre";
+"create_room_section_footer_type_public" = "Seules les personnes invitées peuvent trouver et rejoindre, pas uniquement les personnes dans le nom de l’espace.";
+"location_sharing_invalid_power_level_message" = "Vous devez avoir les bonnes permissions avant de pouvoir partager votre localisation en direct dans ce salon.";
+"location_sharing_invalid_power_level_title" = "Vous n’avez pas les permissions pour partager votre localisation en direct";
+"room_invite_to_room_option_title" = "Juste pour ce salon";
+
+// Mark: - Room invite
+
+"room_invite_to_space_option_title" = "Pour %@";
+"create_room_promotion_header" = "PROMOTION";
+"room_access_space_chooser_other_spaces_section_info" = "Ce sont probablement des choses auxquelles les autres admins de %@ participent.";
+"authentication_choose_password_not_verified_message" = "Vérifiez votre boîte de réception";
+"authentication_choose_password_not_verified_title" = "Email non vérifié";
diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings
index 6721200ac0..de1e77de8b 100644
--- a/Riot/Assets/hu.lproj/Vector.strings
+++ b/Riot/Assets/hu.lproj/Vector.strings
@@ -1595,15 +1595,15 @@
"location_sharing_title" = "Földrajzi helyzet";
"ok" = "OK";
-"onboarding_splash_page_4_message" = "Element megállja a helyét a munkahelyen is. A világ legbiztonságosabb szervezetei bíznak meg benne.";
-"onboarding_splash_page_3_message" = "Telefonszám nélkül végpontok között titkosított. Reklámok és adatbányászat nélkül.";
-"onboarding_splash_page_2_message" = "Válaszd meg hol legyenek a beszélgetéseid tárolva, visszaadja az irányítást és függetlenné tesz. Csatlakozva a Matrixhoz.";
-"onboarding_splash_page_1_message" = "Biztonságos és független kommunikáció ami olyan biztonságos mintha valakivel négyszemközt beszélgetnél a házadban.";
+"onboarding_splash_page_4_message" = "Az Element megállja a helyét a munkahelyi kommunikációban is. A világ legbiztonságosabb szervezetei bíznak meg benne.";
+"onboarding_splash_page_3_message" = "Végponti titkosítással védett, és nem kell telefonszám a regiszrációhoz. Reklámok és adatbányászat nélkül.";
+"onboarding_splash_page_2_message" = "Kiválaszthatod, hogy hol legyenek a beszélgetéseid tárolva, így visszaadva neked az irányítást és a függetlenséget. Csatlakozz a Matrixhoz.";
+"onboarding_splash_page_1_message" = "Biztonságos és független kommunikáció, ami olyan biztonságos mintha valakivel négyszemközt beszélgetnél a házadban.";
"settings_enable_room_message_bubbles" = "Üzenet buborékok";
"onboarding_splash_page_4_title_no_pun" = "Üzenetküldés a csoportodnak.";
"onboarding_splash_page_3_title" = "Biztonságos üzenetküldés.";
-"onboarding_splash_page_2_title" = "Te irányítasz.";
-"onboarding_splash_page_1_title" = "Az ön beszélgetései csak az öné.";
+"onboarding_splash_page_2_title" = "Tiéd az irányítás.";
+"onboarding_splash_page_1_title" = "Vedd birtokba a beszélgetéseid!";
"onboarding_splash_login_button_title" = "Már van fiókom";
// Onboarding
@@ -1651,14 +1651,14 @@
"search_filter_placeholder" = "Szűrés";
"onboarding_use_case_existing_server_button" = "Szerverhez csatlakozás";
"onboarding_use_case_existing_server_message" = "Csatlakoznál egy már meglévő szerverhez?";
-"onboarding_use_case_skip_button" = "Kérdés kihagyása";
+"onboarding_use_case_skip_button" = "Kihagyhatod ezt a kérdést.";
/* The placeholder string contains onboarding_use_case_skip_button as a tappable action */
-"onboarding_use_case_not_sure_yet" = "Még nem vagy biztos? %@";
+"onboarding_use_case_not_sure_yet" = "Még nem tudod? %@";
"onboarding_use_case_community_messaging" = "Közösségek";
-"onboarding_use_case_work_messaging" = "Csoportok";
+"onboarding_use_case_work_messaging" = "Munkahelyi csoportok";
"onboarding_use_case_personal_messaging" = "Barátok és család";
"onboarding_use_case_message" = "Segítünk a kapcsolatteremétésben";
-"onboarding_use_case_title" = "Kivel beszélgetnék leginkább?";
+"onboarding_use_case_title" = "Kikkel fogsz legtöbbet beszélgetni?";
// MARK: - MatrixKit
@@ -2169,22 +2169,22 @@
"threads_notice_title" = "Az üzenetszálak többé már nem kísérleti funkció! 🎉";
"room_participants_invite_prompt_to_msg" = "Biztos, hogy meg akarod hívni őt: %@ ide: %@?";
"onboarding_celebration_button" = "Gyerünk";
-"onboarding_celebration_message" = "A beállításokban bármikor megváltoztatható a profilod";
+"onboarding_celebration_message" = "A beállításokban bármikor megváltoztathatod ezeket";
"onboarding_celebration_title" = "Jól néz ki!";
"onboarding_avatar_accessibility_label" = "Profilkép";
-"onboarding_avatar_message" = "Ideje képet adni a névhez";
+"onboarding_avatar_message" = "Ideje képet adni a profilhoz";
"onboarding_avatar_title" = "Profilkép hozzáadása";
-"onboarding_display_name_max_length" = "A megjelenítendő név 256 karakternél rövidebb legyen";
+"onboarding_display_name_max_length" = "A megjelenítendő név 256 karakternél rövidebb kell legyen";
"onboarding_display_name_hint" = "Ezt később meg lehet változtatni";
"onboarding_display_name_placeholder" = "Megjelenítendő név";
"onboarding_display_name_message" = "Ez fog megjelenni amikor üzenetet küldesz.";
-"onboarding_display_name_title" = "Válassz egy megjelenítési nevet";
+"onboarding_display_name_title" = "Válassz egy megjelenített nevet";
"onboarding_personalization_skip" = "Lépés kihagyása";
-"onboarding_personalization_save" = "Mentés és tovább";
-"onboarding_congratulations_home_button" = "Vigyél haza";
+"onboarding_personalization_save" = "Mentés és folytatás";
+"onboarding_congratulations_home_button" = "A kezdőlapra";
"onboarding_congratulations_personalize_button" = "Profil személyre szabása";
/* The placeholder string contains the user's matrix ID */
-"onboarding_congratulations_message" = "A fiókod elkészült: %@";
+"onboarding_congratulations_message" = "A fiókod elkészült. A Matrix címed: %@";
"onboarding_congratulations_title" = "Gratulálunk!";
"saving" = "Mentés";
@@ -2395,14 +2395,14 @@
"authentication_verify_email_text_field_placeholder" = "E-mail";
"authentication_verify_email_input_message" = "%@ ellenőrizni kell a fiókodat";
"authentication_verify_email_input_title" = "Add meg az e-mail címed";
-"authentication_cancel_flow_confirmation_message" = "A felhasználói fiókod még nincs kész. Megállítód a regisztrációt?";
-"authentication_server_selection_generic_error" = "Ezen a címen nem található szerver, ellenőrizd, hogy helyesen adtad meg.";
-"authentication_server_selection_server_url" = "Matrixszerver URL";
+"authentication_cancel_flow_confirmation_message" = "A felhasználói fiókod még nincs kész. Félbehagyod a regisztrációt?";
+"authentication_server_selection_generic_error" = "Ezen a címen nem található szerver, kérlek ellenőrizd, hogy helyesen adtad-e meg.";
+"authentication_server_selection_server_url" = "Matrix szerver URL";
"authentication_server_selection_register_message" = "Mi a szervered címe? Olyan mint az adataid otthona";
"authentication_server_selection_register_title" = "Válaszd ki a matrix szerveredet";
"authentication_server_selection_login_message" = "Mi a szervered címe?";
"authentication_server_selection_login_title" = "Matrix szerverhez csatlakozás";
-"authentication_server_info_title" = "Ahol a beszélgetéseid lesznek";
+"authentication_server_info_title" = "Itt lesznek tárolva a beszélgetéseid";
"authentication_login_forgot_password" = "Elfelejtetted a jelszót?";
"authentication_login_username" = "Felhasználónév / E-mail / Telefonszám";
"authentication_login_title" = "Üdv újra!";
@@ -2413,5 +2413,5 @@
"authentication_registration_username" = "Felhasználónév";
// MARK: Authentication
-"authentication_registration_title" = "Felhasználói fiók létrehozása";
+"authentication_registration_title" = "Fiók létrehozása";
"authentication_server_info_title_login" = "Ahol a beszélgetéseid lesznek";
diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings
index 0a730cdc52..87df61cb1f 100644
--- a/Riot/Assets/id.lproj/Vector.strings
+++ b/Riot/Assets/id.lproj/Vector.strings
@@ -2622,3 +2622,7 @@
// MARK: Authentication
"authentication_registration_title" = "Buat akun Anda";
"authentication_server_info_title_login" = "Di mana percakapan Anda tinggal";
+"location_sharing_invalid_power_level_message" = "Anda harus mempunyai izin yang diperlukan untuk membagikan lokasi di ruangan ini.";
+"location_sharing_invalid_power_level_title" = "Anda tidak memiliki izin untuk membagikan lokasi";
+"authentication_choose_password_not_verified_message" = "Periksa kotak masuk Anda";
+"authentication_choose_password_not_verified_title" = "Email belum diverifikasi";
diff --git a/Riot/Assets/it.lproj/Vector.strings b/Riot/Assets/it.lproj/Vector.strings
index cfba7ec488..9f042fdd0f 100644
--- a/Riot/Assets/it.lproj/Vector.strings
+++ b/Riot/Assets/it.lproj/Vector.strings
@@ -2395,3 +2395,7 @@
// MARK: Authentication
"authentication_registration_title" = "Crea il tuo account";
"authentication_server_info_title_login" = "Dove vivono le tue conversazioni";
+"location_sharing_invalid_power_level_message" = "Devi avere le giuste autorizzazioni per potere condividere la posizione in tempo reale in questa stanza.";
+"location_sharing_invalid_power_level_title" = "Non hai l'autorizzazione di condividere la posizione in tempo reale";
+"authentication_choose_password_not_verified_message" = "Controlla la posta in arrivo";
+"authentication_choose_password_not_verified_title" = "Email non verificata";
diff --git a/Riot/Assets/nl.lproj/Vector.strings b/Riot/Assets/nl.lproj/Vector.strings
index a0aeb96bac..91c2fd2dd5 100644
--- a/Riot/Assets/nl.lproj/Vector.strings
+++ b/Riot/Assets/nl.lproj/Vector.strings
@@ -2582,3 +2582,7 @@
// MARK: Authentication
"authentication_registration_title" = "Maak een account aan";
"authentication_server_info_title_login" = "Waar uw gesprekken leven";
+"location_sharing_invalid_power_level_message" = "U moet de juiste rechten hebben om de live locatie in deze kamer te delen.";
+"location_sharing_invalid_power_level_title" = "U heeft geen toestemming om de live locatie te delen";
+"authentication_choose_password_not_verified_message" = "Controleer uw inbox";
+"authentication_choose_password_not_verified_title" = "E-mailadres niet geverifieerd";
diff --git a/Riot/Assets/pl.lproj/Vector.strings b/Riot/Assets/pl.lproj/Vector.strings
index 1f60fbe151..a76b615737 100644
--- a/Riot/Assets/pl.lproj/Vector.strings
+++ b/Riot/Assets/pl.lproj/Vector.strings
@@ -256,7 +256,7 @@
"settings_crypto_device_id" = "\nID Sesji: ";
"settings_crypto_device_key" = "\nKlucz Sesji:\n";
"settings_crypto_blacklist_unverified_devices" = "Szyfruj wiadomości tylko do zaufanych sesji";
-"settings_deactivate_my_account" = "Dezaktywuj moje konto";
+"settings_deactivate_my_account" = "Dezaktywuj konto na stałe";
// Room Details
"room_details_title" = "Szczegóły pokoju";
"room_details_files" = "Pliki";
@@ -2075,7 +2075,7 @@
"room_displayname_all_other_members_left" = "%@ (Opuścił-a)";
"call_jitsi_unable_to_start" = "Nie można rozpocząć połączenia konferencyjnego";
"spaces_creation_invite_by_username_title" = "Zaproś swój zespół";
-"message_reply_to_sender_sent_their_live_location" = "udostępnił swoją lokalizację na żywo.";
+"message_reply_to_sender_sent_their_live_location" = "Lokalizacja na żywo.";
"notice_error_unformattable_event" = "** Nie można wyrenderować wiadomości. Proszę zgłosić błąd";
"ignore_user" = "Ignoruj użytkownika";
"location_sharing_live_lab_promotion_activation" = "Włącz udostępnianie lokalizacji na żywo";
@@ -2439,8 +2439,8 @@
"authentication_verify_email_waiting_button" = "Wyślij ponownie wiadomość e-mail";
"authentication_verify_email_waiting_hint" = "Nie otrzymałeś e-maila?";
/* The placeholder will show the email address that was entered. */
-"authentication_verify_email_waiting_message" = "Aby potwierdzić swój adres e-mail, dotknij przycisku w e-mailu, który właśnie wysłaliśmy do %@";
-"authentication_verify_email_waiting_title" = "Sprawdź swój adres e-mail, aby zweryfikować.";
+"authentication_verify_email_waiting_message" = "Postępuj zgodnie z instrukcjami wysłanymi do %@";
+"authentication_verify_email_waiting_title" = "Zweryfikuj swój adres email.";
"authentication_verify_email_text_field_placeholder" = "Email";
"authentication_verify_email_input_message" = "%@ musi zweryfikować Twoje konto";
"authentication_verify_email_input_title" = "Wprowadź swój email";
@@ -2464,7 +2464,7 @@
// MARK: Authentication
"authentication_registration_title" = "Utwórz swoje konto";
"onboarding_celebration_button" = "Ruszajmy dalej";
-"onboarding_celebration_message" = "Przejdź do ustawień w dowolnym momencie, aby zaktualizować swój profil.";
+"onboarding_celebration_message" = "Przejdź do ustawień w dowolnym momencie, aby zaktualizować swój profil";
"onboarding_celebration_title" = "Wygląda dobrze!";
"onboarding_avatar_accessibility_label" = "Obraz profilowy";
"onboarding_avatar_message" = "Ustaw avatar";
@@ -2479,7 +2479,7 @@
"onboarding_congratulations_home_button" = "Wróć do ekranu głównego";
"onboarding_congratulations_personalize_button" = "Spersonalizuj profil";
/* The placeholder string contains the user's matrix ID */
-"onboarding_congratulations_message" = "Twoje konto %@ zostało utworzone.";
+"onboarding_congratulations_message" = "Twoje konto %@ zostało utworzone";
"onboarding_congratulations_title" = "Gratulacje!";
"onboarding_use_case_existing_server_button" = "Połącz się z serwerem";
"onboarding_use_case_existing_server_message" = "Chcesz dołączyć do istniejącego serwera?";
@@ -2510,3 +2510,8 @@
"new_word" = "Nowy";
"stop" = "Stop";
"joining" = "Dołączanie";
+"location_sharing_invalid_power_level_message" = "Aby udostępniać lokalizację na żywo w tym pokoju, musisz mieć odpowiednie uprawnienia.";
+"location_sharing_invalid_power_level_title" = "Nie masz uprawnień do udostępniania lokalizacji na żywo";
+"authentication_choose_password_not_verified_message" = "Sprawdź swoją skrzynkę odbiorczą";
+"authentication_choose_password_not_verified_title" = "E-mail niezweryfikowany";
+"authentication_server_info_title_login" = "Miejsce twoich konwersacji";
diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings
index 82541229ce..d450441348 100644
--- a/Riot/Assets/pt_BR.lproj/Vector.strings
+++ b/Riot/Assets/pt_BR.lproj/Vector.strings
@@ -2396,3 +2396,7 @@
// MARK: Authentication
"authentication_registration_title" = "Criar sua conta";
+"location_sharing_invalid_power_level_message" = "Você precisa ter as permissões certas a fim de compartilhar localização ao vivo nesta sala.";
+"location_sharing_invalid_power_level_title" = "Você não tem permissão para compartilhar localização ao vivo";
+"authentication_choose_password_not_verified_message" = "Cheque sua inbox";
+"authentication_choose_password_not_verified_title" = "Email não verificado";
diff --git a/Riot/Assets/ru.lproj/Vector.strings b/Riot/Assets/ru.lproj/Vector.strings
index a1de069974..fd018bde0b 100644
--- a/Riot/Assets/ru.lproj/Vector.strings
+++ b/Riot/Assets/ru.lproj/Vector.strings
@@ -111,8 +111,8 @@
"room_recents_join_room_prompt" = "Введите идентификатор или псевдоним комнаты";
// People tab
"people_invites_section" = "ПРИГЛАШЕНИЯ";
-"people_conversation_section" = "БЕСЕДЫ";
-"people_no_conversation" = "Нет бесед";
+"people_conversation_section" = "ДИАЛОГИ";
+"people_no_conversation" = "Нет диалогов";
// Rooms tab
"room_directory_no_public_room" = "Общедоступных комнат нет";
// Search
@@ -1995,3 +1995,161 @@
// MARK: Authentication
"authentication_registration_title" = "Создать аккаунт";
+"settings_presence_offline_mode" = "Режим офлайн";
+"settings_analytics_and_crash_data" = "Отправлять данные о сбоях и аналитике";
+"settings_labs_enable_live_location_sharing" = "Трансляция геопозиции - делиться текущей геопозицией (активная разработка и, временно, сохраняющиеся в истории комнаты локации)";
+"settings_labs_use_only_latest_user_avatar_and_name" = "Показывать последний аватар и имя пользователей в истории сообщений";
+"settings_labs_enable_threads" = "Потоковый обмен сообщениями";
+"settings_labs_enabled_polls" = "Опросы";
+"settings_ui_show_redactions_in_room_history" = "Показать место хранения удалённых сообщений";
+"settings_about" = "О";
+"room_preview_decline_invitation_options" = "Вы хотите отклонить приглашение или проигнорировать пользователя?";
+"threads_discourage_information_2" = "\n\nХотите всё равно включить потоки?";
+"threads_discourage_information_1" = "Ваш домашний сервер в настоящее время не поддерживает потоки, поэтому эта функция может быть ненадежной. Некоторые потоковые сообщения могут быть недоступны. ";
+"threads_beta_cancel" = "Не сейчас";
+"threads_beta_enable" = "Попробуйте";
+"threads_beta_information_link" = "Больше информации";
+"threads_beta_title" = "Потоки";
+"message_from_a_thread" = "Из потока";
+"threads_empty_show_all_threads" = "Показать все потоки";
+"threads_action_my_threads" = "Мои потоки";
+"threads_action_all_threads" = "Все потоки";
+"threads_title" = "Потоки";
+"thread_copy_link_to_thread" = "Скопировать ссылку потока";
+
+// MARK: Threads
+"room_thread_title" = "Поток";
+"room_accessibility_threads" = "Потоки";
+"message_reply_to_sender_sent_their_live_location" = "Трансляция геопозиции в реальном времени.";
+
+// Mark: - Space Creation
+
+"spaces_creation_hint" = "Пространства - это новый способ организации комнат и людей.";
+"spaces_feature_not_available" = "Эта функция тут недоступна. На данный момент, вы можете сделать это с помощью %@ на своём компьютере.";
+"space_topic" = "Описание";
+"space_public_join_rule_detail" = "Открыто для всех, лучше всего для сообществ";
+"spaces_add_room" = "Добавить комнату";
+"spaces_invite_people" = "Пригласить людей";
+"space_private_join_rule_detail" = "Только по приглашению, лучшее для себя или команд";
+"spaces_explore_rooms_one_room" = "1 комната";
+"spaces_explore_rooms_room_number" = "%@ комнаты";
+"room_invite_not_enough_permission" = "У вас нет возможности приглашать людей в эту комнату";
+"room_invite_to_room_option_detail" = "Они не будут состоять в %@.";
+"room_invite_to_room_option_title" = "Только в эту комнату";
+"room_invite_to_space_option_detail" = "Они могут исследовать %@, но не будут членами %@.";
+"share_invite_link_room_text" = "Привет, присоединяйся к этой комнате %@";
+
+// MARK: - Share invite link
+
+"share_invite_link_action" = "Поделиться ссылкой для приглашения";
+"home_syncing" = "Синхронизация";
+"home_context_menu_mark_as_read" = "Пометить как прочитанное";
+"home_context_menu_leave" = "Покинуть";
+"notice_room_third_party_registered_invite_by_you" = "Вы приняли приглашение в %@";
+"threads_notice_done" = "Понятно";
+"room_accessibility_record_voice_message_hint" = "Для записи нажмите 2 раза и задержите.";
+"room_accessibility_record_voice_message" = "Записать голосовое сообщение";
+"room_accessibility_thread_more" = "Больше";
+"room_event_copy_link_info" = "Ссылка скопирована в буфер обмена.";
+"room_event_action_reply_in_thread" = "Нить";
+"room_event_action_view_in_room" = "Посмотреть в комнате";
+"room_event_action_end_poll" = "Закончить опрос";
+"room_event_action_remove_poll" = "Удалить опрос";
+"room_participants_invite_prompt_to_msg" = "Вы уверены что хотите пригласить %@ в %@?";
+"room_participants_leave_success" = "Левая комната";
+"search_filter_placeholder" = "Фильтр";
+"password_validation_error_contain_symbol" = "Содержать символ.";
+"password_validation_error_contain_number" = "Содержать число.";
+"password_validation_error_contain_uppercase_letter" = "Содержать заглавную букву.";
+"password_validation_error_contain_lowercase_letter" = "Содержать не заглавную букву.";
+/* The placeholder will show a number */
+"password_validation_error_max_length" = "Не более %d символов.";
+/* The placeholder will show a number */
+"password_validation_error_min_length" = "Как минимум %d символов.";
+"password_validation_error_header" = "Данный пароль не соответствует критериям ниже:";
+
+// MARK: Password Validation
+"password_validation_info_header" = "Ваш пароль должен соответствовать критериям ниже:";
+"authentication_choose_password_not_verified_title" = "Электронная почта не подтверждена";
+"authentication_choose_password_submit_button" = "Сбросить пароль";
+"authentication_choose_password_signout_all_devices" = "Выйти из аккаунта на всех девайсах";
+"authentication_choose_password_text_field_placeholder" = "Новый пароль";
+"authentication_forgot_password_waiting_button" = "Отправить письмо повторно";
+/* The placeholder will show the email address that was entered. */
+"authentication_forgot_password_waiting_message" = "Следуйте инструкциям, отправленным %@";
+"authentication_forgot_password_waiting_title" = "Проверьте свою электронную почту.";
+"authentication_forgot_password_text_field_placeholder" = "Электронная почта";
+/* The placeholder will show the homeserver's domain */
+"authentication_forgot_password_input_message" = "%@ отправит вам ссылку для верификации";
+"authentication_forgot_password_input_title" = "Введите свою электронную почту";
+"authentication_verify_email_waiting_button" = "Отправить письмо повторно";
+"authentication_verify_email_waiting_hint" = "Не получили письмо на электронную почту?";
+/* The placeholder will show the email address that was entered. */
+"authentication_verify_email_waiting_message" = "Следуйте инструкциям, отправленным %@";
+/* The placeholder will show the homeserver's domain */
+"authentication_verify_email_input_message" = "%@ нужно проверить ваш аккаунт";
+"authentication_server_info_title_login" = "Где живут ваши разговоры";
+"authentication_server_info_title" = "Где будут жить ваши диалоги";
+/* The placeholder will show the full Matrix ID that has been entered. */
+"authentication_registration_username_footer_available" = "Другие могут обнаружить вас %@";
+"onboarding_celebration_button" = "Поехали";
+"onboarding_celebration_message" = "Зайдите в настройки в любое время, чтобы обновить свой профиль";
+"onboarding_avatar_title" = "Добавить фото профиля";
+"onboarding_display_name_max_length" = "Ваше отображаемое имя должно состоять из не более чем 256 символов";
+"onboarding_display_name_hint" = "Вы сможете изменить его позже";
+"onboarding_display_name_placeholder" = "Отображаемое имя";
+"onboarding_display_name_message" = "Его будет видно, когда вы будете отправляете сообщения.";
+"onboarding_display_name_title" = "Выберите отображаемое имя";
+"onboarding_personalization_skip" = "Пропустить этот шаг";
+"onboarding_personalization_save" = "Сохранить и продолжить";
+"onboarding_congratulations_personalize_button" = "Персонализировать профиль";
+/* The placeholder string contains the user's matrix ID */
+"onboarding_congratulations_message" = "Ваш аккаунт %@ был создан";
+"onboarding_congratulations_title" = "Поздравляем!";
+"onboarding_use_case_message" = "Мы поможем вам подключиться";
+"onboarding_use_case_title" = "С кем вы будете переписываться больше всего?";
+"onboarding_splash_page_4_message" = "Element также отлично подходит для работы. Ему доверяют самые безопасные организации мира.";
+"onboarding_splash_page_4_title_no_pun" = "Обмен сообщениями для вашей команды.";
+"onboarding_splash_page_3_message" = "Полностью зашифровано и не требует номера телефона. Без рекламы и сбора данных.";
+"onboarding_splash_page_3_title" = "Безопасный обмен сообщениями.";
+"onboarding_splash_page_2_message" = "Выберите, где будут храниться ваши диалоги, давая вам контроль и независимость. Подключен через Matrix.";
+"onboarding_splash_page_2_title" = "У вас всё под контролем.";
+"onboarding_splash_page_1_message" = "Безопасное и независимое общение, обеспечивающее такой же уровень конфиденциальности, как и при личном разговоре у вас дома.";
+"onboarding_splash_page_1_title" = "Будьте хозяином своих переписок.";
+"onboarding_splash_login_button_title" = "У меня уже есть аккаунт";
+"confirm" = "Подтвердить";
+"onboarding_celebration_title" = "Выглядит хорошо!";
+"onboarding_avatar_accessibility_label" = "Фото профиля";
+"onboarding_use_case_existing_server_button" = "Подключиться к серверу";
+"onboarding_use_case_existing_server_message" = "Хотите присоединиться к существующему серверу?";
+"onboarding_use_case_skip_button" = "Пропустить вопрос";
+/* The placeholder string contains onboarding_use_case_skip_button as a tappable action */
+"onboarding_use_case_not_sure_yet" = "Ещё не уверенны? %@";
+"onboarding_use_case_community_messaging" = "Сообщества";
+"onboarding_use_case_work_messaging" = "Команды";
+"onboarding_use_case_personal_messaging" = "Друзья и семья";
+"authentication_recaptcha_title" = "Вы человек?";
+/* The placeholder will show the homeserver's domain */
+"authentication_terms_message" = "Пожалуйста прочитайте условия и политику %@";
+"authentication_terms_title" = "Политика сервера";
+"authentication_verify_msisdn_invalid_phone_number" = "Недействительный номер телефона";
+"authentication_verify_msisdn_waiting_button" = "Отправить код повторно";
+/* The placeholder will show the phone number that was entered. */
+"authentication_verify_msisdn_waiting_message" = "Код был отправлен на %@";
+"authentication_verify_msisdn_waiting_title" = "Подтвердите свой номер телефона";
+"authentication_verify_msisdn_otp_text_field_placeholder" = "Код подтверждения";
+"authentication_verify_msisdn_text_field_placeholder" = "Номер телефона";
+/* The placeholder will show the homeserver's domain */
+"authentication_verify_msisdn_input_message" = "%@ нужно проверить ваш аккаунт";
+"authentication_verify_msisdn_input_title" = "Введите свой номер телефона";
+"authentication_choose_password_not_verified_message" = "Проверьте входящие сообщения";
+"authentication_choose_password_input_title" = "Выберите новый пароль";
+"authentication_choose_password_input_message" = "Убедитесь, что он состоит из не менее чем 8 символов";
+"authentication_server_selection_generic_error" = "Не получилось найти сервер по этому URL, проверьте, пожалуйста, всё ли правильно введено.";
+"authentication_server_selection_server_url" = "URL домашнего сервера";
+"authentication_server_selection_register_message" = "Какой адрес у вашего сервера? Это что-то вроде дома для всех ваших данных";
+"authentication_server_selection_register_title" = "Выберите ваш домашний сервер";
+"authentication_server_selection_login_message" = "Какой адрес у вашего сервера?";
+"authentication_server_selection_login_title" = "Подключиться к домашнему серверу";
+"authentication_cancel_flow_confirmation_message" = "Ваш аккаунт ещё не создан. Остановить процесс регистрации?";
+"settings_timeline" = "Лента сообщений";
diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings
index d96eaf66b3..7b0a3f06eb 100644
--- a/Riot/Assets/sk.lproj/Vector.strings
+++ b/Riot/Assets/sk.lproj/Vector.strings
@@ -2618,3 +2618,7 @@
// MARK: Authentication
"authentication_registration_title" = "Vytvorte si účet";
"authentication_server_info_title_login" = "Kde vaše rozhovory žijú";
+"location_sharing_invalid_power_level_message" = "Musíte mať príslušné oprávnenia na zdieľanie polôh v reálnom čase v tejto miestnosti.";
+"location_sharing_invalid_power_level_title" = "Nemáte oprávnenie na zdieľanie polohy v reálnom čase";
+"authentication_choose_password_not_verified_message" = "Skontrolujte si doručenú poštu";
+"authentication_choose_password_not_verified_title" = "E-mail nie je overený";
diff --git a/Riot/Assets/sq.lproj/Vector.strings b/Riot/Assets/sq.lproj/Vector.strings
index bcb5d1a490..280ad600cf 100644
--- a/Riot/Assets/sq.lproj/Vector.strings
+++ b/Riot/Assets/sq.lproj/Vector.strings
@@ -427,7 +427,7 @@
"settings_pin_rooms_with_unread" = "Fikso dhomat me mesazhe të palexuar";
"settings_labs_create_conference_with_jitsi" = "Krijoni thirrje konferencë me Jitsi-n";
"settings_fail_to_update_password" = "S’u arrit të përditësohet fjalëkalimi i llogarisë Matrix";
-"settings_deactivate_my_account" = "Çaktivizoje llogarinë time";
+"settings_deactivate_my_account" = "Çaktivizoje llogarinë përgjithmonë";
"room_details_mute_notifs" = "Heshtoji njoftimet";
"room_details_access_section_no_address_warning" = "Që të lidhni një dhomë, ajo duhet të ketë një adresë";
"room_details_new_address_placeholder" = "Shtoni adresë të re (p.sh. #foo%@)";
@@ -1643,13 +1643,13 @@
"search_filter_placeholder" = "Filtër";
"onboarding_use_case_existing_server_button" = "Lidhu me shërbyesin";
"onboarding_use_case_existing_server_message" = "Po shihni për t’u lidhur me një shërbyes ekzistues?";
-"onboarding_use_case_skip_button" = "anashkaloni këtë pyetje";
+"onboarding_use_case_skip_button" = "Anashkaloni këtë pyetje";
/* The placeholder string contains onboarding_use_case_skip_button as a tappable action */
-"onboarding_use_case_not_sure_yet" = "Ende jo i sigurt? Mundeni të %@";
+"onboarding_use_case_not_sure_yet" = "Ende jo i sigurt? %@";
"onboarding_use_case_community_messaging" = "Bashkësi";
"onboarding_use_case_work_messaging" = "Ekipe";
"onboarding_use_case_personal_messaging" = "Shokë dhe familje";
-"onboarding_use_case_message" = "Do t’ju ndihmojmë të lidheni.";
+"onboarding_use_case_message" = "Do t’ju ndihmojmë të lidheni";
"onboarding_use_case_title" = "Me kë do të bisedoni më të shumtën?";
@@ -1740,7 +1740,7 @@
"room_displayname_more_than_two_members" = "%@ dhe %@ të tjerë";
// Settings
"settings" = "Rregullime";
-"settings_enable_inapp_notifications" = "Aktivizoni njoftime Aplikacioni";
+"settings_enable_inapp_notifications" = "Aktivizoni njoftime të aplikacionit";
"settings_enable_push_notifications" = "Aktivizoni njoftime push";
"settings_enter_validation_token_for" = "Jepni token vleftësimi për %@:";
"notification_settings_room_rule_title" = "Dhomë: '%@'";
@@ -2254,10 +2254,10 @@
"threads_notice_title" = "Rrjedhat s’janë më eksperimentale 🎉";
"room_participants_invite_prompt_to_msg" = "Jeni i sigurt se doni të ftohet %@ te %@?";
"onboarding_celebration_button" = "Shkojmë";
-"onboarding_celebration_message" = "Parapëlqimet tuaja u ruajtën.";
-"onboarding_celebration_title" = "Kaq qe!";
+"onboarding_celebration_message" = "Që të përditësoni profilin tuaj, shkoni kur të doni te rregullimet";
+"onboarding_celebration_title" = "Bukur duket!";
"onboarding_avatar_accessibility_label" = "Foto profili";
-"onboarding_avatar_message" = "Këtë mund ta ndryshoni në çfarëdo kohe..";
+"onboarding_avatar_message" = "Koha për t’i dhënë pamje emrit";
"onboarding_avatar_title" = "Shtoni një foto profili";
"onboarding_display_name_max_length" = "Emri juaj për në ekran duhet të jetë më pak se 256 shenja";
"onboarding_display_name_hint" = "Këtë mund ta ndryshoni më vonë";
@@ -2269,7 +2269,7 @@
"onboarding_congratulations_home_button" = "Shpjemëni në shtëpi";
"onboarding_congratulations_personalize_button" = "Personalizoni profilin";
/* The placeholder string contains the user's matrix ID */
-"onboarding_congratulations_message" = "Llogaria juaj %@ u krijua.";
+"onboarding_congratulations_message" = "Llogaria juaj %@ u krijua";
"onboarding_congratulations_title" = "Përgëzime!";
"saving" = "Ruajtje";
@@ -2312,3 +2312,108 @@
"threads_discourage_information_2" = "\n\nDoni të aktivizohen rrjedha, sido qoftë?";
"threads_discourage_information_1" = "Shërbyesi juaj Home aktualisht s’mbulon rrjedha, ndaj kjo veçori mund të jetë e paqëndrueshme. Disa mesazhe rrjedhash mund të mos jenë të përdorshëm. ";
"confirm" = "Ripohojeni";
+"message_reply_to_sender_sent_their_live_location" = "Vendndodhje drejtpërsëdrejti.";
+"location_sharing_live_lab_promotion_activation" = "Aktivizo tregim vendndodhjeje “live”";
+"location_sharing_live_lab_promotion_text" = "Ju lutemi, kini parasysh: kjo është një veçori në zhvillim, që përdor një sendërtim të përkohshëm i cili lejon që historiku i vendndodhjeve tuaja të dhëna për të tjerët të jenë përherë të dukshme për persona të tjerë te dhoma.";
+"location_sharing_live_lab_promotion_title" = "Tregim “live” vendndodhjeje";
+"location_sharing_live_loading" = "Po ngarkohet Vendndodhje “Live”…";
+"location_sharing_live_timer_incoming" = "“Live” deri më %@";
+"location_sharing_live_list_item_sharing_expired" = "Dhënia ka skaduar";
+"location_sharing_live_list_item_time_left" = "Edhe %@";
+"location_sharing_map_credits_title" = "© Të drejta kopjimi";
+"location_sharing_allow_background_location_message" = "Nëse do të donit të tregonit Vendndodhjen tuaj Drejtpërsëdrejti, Element-it i duhet hyrje te vendndodhja, kur aplikacioni është në prapaskenë.Që të aktivizoni hyrje, prekni Rregullime> Vendndodhje dhe përzgjidhni Përherë";
+"location_sharing_invalid_power_level_message" = "Që të mund të ndani me të tjerë në këtë dhomë vendndodhje, lypset të keni lejet e duhura.";
+"location_sharing_invalid_power_level_title" = "S’keni leje të tregoni vendndodhje drejtpërsëdrejti";
+
+// MARK: Reactions
+
+"room_event_action_reaction_more" = "%@ më tepër";
+"leave_space_selection_no_rooms" = "Mos përzgjidh dhoma";
+"leave_space_selection_all_rooms" = "Përzgjidhni krejt dhomat";
+"leave_space_selection_title" = "PËRZGJIDHNI DHOMA";
+"leave_space_and_more_rooms" = "Braktisni hapësirën dhe %@dhoma";
+"leave_space_and_one_room" = "Braktisni hapësirën dhe 1 dhomë";
+
+// Mark: Leave space
+
+"leave_space_action" = "Braktiseni hapësirën";
+"spaces_feature_not_available" = "Kjo veçori s’është e passhme këtu. Tani për tani, këtë mund ta bëni me %@ në kompjuterin tuaj.";
+"home_context_menu_mark_as_read" = "Vëri shenjë si të lexuar";
+"room_info_back_button_title" = "Hollësi Dhome";
+"network_offline_message" = "S’jeni në linjë, kontrolloni lidhjen tuaj në internet.";
+"network_offline_title" = "S’jeni në linjë";
+"settings_labs_enable_live_location_sharing" = "Tregim vendndodhjeje drejtpërsëdrejti - tregoju vendndodhjen e tanishme (në zhvillim aktiv dhe përkohësisht, vendndodhjet mbeten në historikun e dhomës)";
+"settings_timeline" = "RRJEDHË KOHORE";
+"room_accessibility_record_voice_message_hint" = "Për regjistrim, prekeni dyfish dhe mbajeni të prekur.";
+"room_accessibility_record_voice_message" = "Incizoni Mesazh Zanor";
+"password_validation_error_contain_symbol" = "Përmban një simbol.";
+"password_validation_error_contain_number" = "Përmban një numër.";
+"password_validation_error_contain_uppercase_letter" = "Përmban shkronjë të madhe.";
+"password_validation_error_contain_lowercase_letter" = "Përmban shkronjë të vogël.";
+/* The placeholder will show a number */
+"password_validation_error_max_length" = "S’tejkalon %d shenja.";
+/* The placeholder will show a number */
+"password_validation_error_min_length" = "E pakta %d shenja.";
+"password_validation_error_header" = "Fjalëkalimi i dhënë nuk plotëson kriteret më poshtë:";
+
+// MARK: Password Validation
+"password_validation_info_header" = "Fjalëkalimi juaj duhet të plotësojë kriteret më poshtë:";
+"authentication_recaptcha_title" = "Jeni qenie njerëzore?";
+"authentication_terms_policy_url_error" = "S’arrihet të gjendet rregulli i përzgjedhur. Ju lutemi, riprovoni.";
+/* The placeholder will show the homeserver's domain */
+"authentication_terms_message" = "Ju lutemi, lexoni kushte dhe rregulla të %@";
+"authentication_terms_title" = "Rregulla shërbyesi";
+"authentication_verify_msisdn_invalid_phone_number" = "Numër telefoni i pavlefshëm";
+"authentication_verify_msisdn_waiting_button" = "Ridërgomëni kodin";
+/* The placeholder will show the phone number that was entered. */
+"authentication_verify_msisdn_waiting_message" = "Te %@ u dërgua një kod";
+"authentication_verify_msisdn_waiting_title" = "Verifikoni numrin tuaj të telefonit";
+"authentication_verify_msisdn_otp_text_field_placeholder" = "Kod Ripohimi";
+"authentication_verify_msisdn_text_field_placeholder" = "Numër Telefoni";
+/* The placeholder will show the homeserver's domain */
+"authentication_verify_msisdn_input_message" = "%@ lyp verifikimin e llogarisë tuaj";
+"authentication_verify_msisdn_input_title" = "Jepni numrin e telefonit tuaj";
+"authentication_choose_password_not_verified_message" = "Kontrolloni te mesazhet tuaj të marrë";
+"authentication_choose_password_not_verified_title" = "Email i paverifikuar";
+"authentication_choose_password_submit_button" = "Ricaktoni Fjalëkalimin";
+"authentication_choose_password_signout_all_devices" = "Dil nga krejt pajisjet";
+"authentication_choose_password_text_field_placeholder" = "Fjalëkalim i Ri";
+"authentication_choose_password_input_message" = "Sigurohuni të jetë 8 ose më shumë shenja";
+"authentication_choose_password_input_title" = "Zgjidhni një fjalëkalim të ri";
+"authentication_forgot_password_waiting_button" = "Ridërgo email";
+/* The placeholder will show the email address that was entered. */
+"authentication_forgot_password_waiting_message" = "Ndiqni udhëzimet e dërguara te %@";
+"authentication_forgot_password_waiting_title" = "Kontrolloni email-et tuaj.";
+"authentication_forgot_password_text_field_placeholder" = "Email";
+/* The placeholder will show the homeserver's domain */
+"authentication_forgot_password_input_message" = "%@ do t’ju dërgojë një lidhje verifikimi";
+"authentication_forgot_password_input_title" = "Jepni email-in tuaj";
+"authentication_verify_email_waiting_button" = "Ridërgo email";
+"authentication_verify_email_waiting_hint" = "S’u mor email?";
+/* The placeholder will show the email address that was entered. */
+"authentication_verify_email_waiting_message" = "Ndiqni udhëzimet e dërguara te %@";
+"authentication_verify_email_waiting_title" = "Verifikoni email-in tuaj.";
+"authentication_verify_email_text_field_placeholder" = "Email";
+/* The placeholder will show the homeserver's domain */
+"authentication_verify_email_input_message" = "%@ lyp verifikimin e llogarisë tuaj";
+"authentication_verify_email_input_title" = "Jepni email-in tuaj";
+"authentication_cancel_flow_confirmation_message" = "Llogaria juaj s’është krijuar ende. Të ndalet procesi i regjistrimit?";
+"authentication_server_selection_generic_error" = "S’gjendet dot shërbyes në këtë URL, ju lutemi, shihni nëse është e saktë.";
+"authentication_server_selection_server_url" = "URL shërbyesi Home";
+"authentication_server_selection_register_message" = "Cila është adresa e shërbyesit tuaj? Kjo është si shtëpi për krejt të dhënat tuaja";
+"authentication_server_selection_register_title" = "Përzgjidhni shërbyesin tuaj Home";
+"authentication_server_selection_login_message" = "Cila është adresa e shërbyesit tuaj?";
+"authentication_server_selection_login_title" = "Lidhu me shërbyesin Home";
+"authentication_server_info_title_login" = "Ku gjenden bisedat tuaja";
+"authentication_login_forgot_password" = "Harruat fjalëkalimin";
+"authentication_login_username" = "Emër përdoruesi / Email / Telefon";
+"authentication_login_title" = "Mirë se u kthyet!";
+"authentication_server_info_title" = "Ku do të gjenden bisedat tuaja";
+"authentication_registration_password_footer" = "Duhet të jetë 8 ose më shumë shenja";
+/* The placeholder will show the full Matrix ID that has been entered. */
+"authentication_registration_username_footer_available" = "Të tjerët mund t’ju zbulojnë %@";
+"authentication_registration_username_footer" = "Këtë s’mund ta ndryshoni më vonë";
+"authentication_registration_username" = "Emër përdoruesi";
+
+// MARK: Authentication
+"authentication_registration_title" = "Krijoni llogarinë tuaj";
diff --git a/Riot/Assets/zh_Hans.lproj/Localizable.strings b/Riot/Assets/zh_Hans.lproj/Localizable.strings
index b64a42a87f..1e13dc6f68 100644
--- a/Riot/Assets/zh_Hans.lproj/Localizable.strings
+++ b/Riot/Assets/zh_Hans.lproj/Localizable.strings
@@ -88,12 +88,12 @@
"USER_UPDATED_DISPLAYNAME" = "%@ 将名称更改为 %@";
/* A user has reacted to a message, but the reaction content is unknown */
-"GENERIC_REACTION_FROM_USER" = "%@ 发送了一则回应";
+"GENERIC_REACTION_FROM_USER" = "%@发送了一个反应";
/** Reactions **/
/* A user has reacted to a message, including the reaction e.g. "Alice reacted 👍". */
-"REACTION_FROM_USER" = "%@ 以 %@ 回应";
+"REACTION_FROM_USER" = "%@以%@作为反应";
/* New file message from a specific person, not referencing a room. */
"FILE_FROM_USER" = "%@ 发了个文件 %@";
diff --git a/Riot/Assets/zh_Hans.lproj/Vector.strings b/Riot/Assets/zh_Hans.lproj/Vector.strings
index 77377ec0ec..f8b24462b3 100644
--- a/Riot/Assets/zh_Hans.lproj/Vector.strings
+++ b/Riot/Assets/zh_Hans.lproj/Vector.strings
@@ -470,7 +470,7 @@
"widget_integration_unable_to_create" = "无法创建挂件。";
"widget_integration_failed_to_send_request" = "发送请求失败。";
"widget_integration_room_not_recognised" = "无法识别此房间。";
-"widget_integration_positive_power_level" = "权限级别必须是整数。";
+"widget_integration_positive_power_level" = "权力级别必须是正整数。";
"widget_integration_must_be_in_room" = "您不在此房间中。";
"e2e_room_key_request_start_verification" = "开始验证…";
"e2e_room_key_request_share_without_verifying" = "在不验证的情况下分享";
@@ -720,7 +720,7 @@
"settings_calls_stun_server_fallback_button" = "允许使用通话辅助服务器作为备用手段";
"settings_calls_stun_server_fallback_description" = "允许在你的主服务器不能提供时使用通话辅助服务器 %@ 作为备用手段(你的IP地址在通话时会被分享)。";
"settings_integrations_allow_button" = "管理集成";
-"settings_integrations_allow_description" = "使用集成管理器(%@)来管理机器人,桥接,小插件和贴图包。\n\n集成管理器会收到设置数据,而且能修改小插件,发送房间邀请以及代表你设置权限级别。";
+"settings_integrations_allow_description" = "使用集成管理器(%@)来管理机器人,桥接,小插件和贴图包。\n\n集成管理器会收到设置数据,而且能修改小插件,发送房间邀请以及代表你设置权力级别。";
"settings_labs_message_reaction" = "用emoji表情回应消息";
"settings_labs_enable_cross_signing" = "开启交叉签名按用户验证而不是按设备验证(开发中)";
"settings_add_3pid_password_title_email" = "添加邮箱地址";
@@ -926,7 +926,7 @@
"file_upload_error_title" = "文件上传";
"file_upload_error_unsupported_file_type_message" = "不支持的文件类型。";
// MARK: Emoji picker
-"emoji_picker_title" = "回应";
+"emoji_picker_title" = "反应";
"emoji_picker_people_category" = "表情和人物";
"emoji_picker_nature_category" = "动物和自热";
"emoji_picker_foods_category" = "食物和饮料";
@@ -936,7 +936,7 @@
"emoji_picker_symbols_category" = "符号";
"emoji_picker_flags_category" = "旗帜";
// MARK: Reaction history
-"reaction_history_title" = "回应";
+"reaction_history_title" = "反应";
// Generic errors
"error_invite_3pid_with_no_identity_server" = "在你的设置里添加身份认证服务器以便用邮箱邀请。";
"error_not_supported_on_mobile" = "你不能从移动版%@中进行此操作。";
@@ -978,15 +978,15 @@
"user_verification_session_details_verify_action_other_user" = "手动验证";
"room_participants_action_security_status_complete_security" = "完整安全性";
"room_participants_action_security_status_loading" = "正在加载…";
-"room_member_power_level_admin_in" = "管理员(%@)";
+"room_member_power_level_admin_in" = "%@里的管理员";
"room_member_power_level_moderator_in" = "%@里的协管员";
-"room_member_power_level_short_admin" = "管理";
+"room_member_power_level_short_admin" = "管理员";
"room_member_power_level_short_moderator" = "协管员";
"security_settings_crosssigning" = "交叉签名";
"security_settings_crosssigning_info_not_bootstrapped" = "交叉签名还没有被设置。";
"security_settings_crosssigning_info_exists" = "您的帐户有一个交叉签名身份,但是还没有被这个会话信任。完全安全的会话。";
"skip" = "跳过";
-"room_member_power_level_custom_in" = "自定义(%@)(%@)";
+"room_member_power_level_custom_in" = "%@里的自定义(%@)";
"room_member_power_level_short_custom" = "自定义";
"security_settings_crosssigning_info_trusted" = "已启用交叉签名。您可以基于交叉签名信任其他用户和其他会话,但不能从此会话交叉签名,因为它没有交叉签名私钥。此会话完全安全。";
"security_settings_crosssigning_info_ok" = "交叉登录已准备就绪。";
@@ -1645,7 +1645,7 @@
"sign_up" = "注册";
"submit" = "提交";
"submit_code" = "提交码";
-"set_default_power_level" = "重置权限级别";
+"set_default_power_level" = "重置权力级别";
"set_moderator" = "设置协管员";
"set_admin" = "设置管理员";
"start_chat" = "启动聊天";
@@ -1677,9 +1677,9 @@
"notice_profile_change_redacted" = "%@ 已经更新了他的个人档案 %@";
"notice_room_created" = "%@ 创建并配置了此房间。";
"notice_room_join_rule" = "加入规则是:%@";
-"notice_room_power_level_intro" = "此房间成员的权限级别是:";
-"notice_room_power_level_acting_requirement" = "要进行此操作,用户必须具备的最低权限级别是 :";
-"notice_room_power_level_event_requirement" = "事件所需的最小权限级别:";
+"notice_room_power_level_intro" = "此房间成员的权力级别是:";
+"notice_room_power_level_acting_requirement" = "要进行此操作,用户必须具备的最低权力级别是 :";
+"notice_room_power_level_event_requirement" = "事件所需的最小权力级别:";
"notice_room_aliases" = "此房间的别名是:%@";
"notice_encrypted_message" = "已加密消息";
"notice_image_attachment" = "图片附件";
@@ -1787,7 +1787,7 @@
"default" = "默认";
"private" = "私人";
"public" = "公开";
-"power_level" = "权限级别";
+"power_level" = "权力级别";
"network_error_not_reachable" = "请检查你的网络连接";
"user_id_placeholder" = "例如:@bob:homeserver";
"ssl_homeserver_url" = "主服务器网址:%@";
@@ -1819,7 +1819,7 @@
"resend" = "重新发送";
"share" = "分享";
"redact" = "移除";
-"set_power_level" = "设置权限级别";
+"set_power_level" = "设置权力级别";
"delete" = "删除";
"create_room" = "创建房间";
"login" = "登录";
@@ -1927,7 +1927,7 @@
"message_reply_to_sender_sent_an_audio_file" = "发送了一个音频文件。";
"message_reply_to_sender_sent_a_file" = "发送了一个文件。";
"message_reply_to_message_to_reply_to_prefix" = "回复";
-"room_member_power_level_prompt" = "该用户将被提升至与您一样的权限级别,所以此操作将无法撤销。\n您确定吗?";
+"room_member_power_level_prompt" = "该用户将被提升至与您一样的权力级别,所以此操作将无法撤销。\n您确定吗?";
// Attachment
"attachment_size_prompt" = "发送为:";
"attachment_original" = "实际大小 (%@)";
@@ -1996,7 +1996,7 @@
"notice_room_third_party_revoked_invite_for_dm" = "%@ 撤回了对 %@ 的邀请";
"notice_room_third_party_invite_for_dm" = "%@ 邀请了 %@";
"room_left_for_dm" = "你离开了";
-"notice_room_power_level_intro_for_dm" = "成员的权限级别是:";
+"notice_room_power_level_intro_for_dm" = "成员的权力级别是:";
"notice_room_aliases_for_dm" = "别名是:%@";
"notice_room_created_for_dm" = "%@ 已加入。";
"notice_room_name_removed_for_dm" = "%@ 移除了名称";
@@ -2087,3 +2087,42 @@
/* The placeholder %1$tu will be replaced with a number and %2$@ with the user's search terms. */
"directory_search_results" = "为%2$@找到%1$tu个结果";
"onboarding_splash_page_2_title" = "一切都在你的掌控中。";
+"onboarding_congratulations_personalize_button" = "个性化用户资料";
+/* The placeholder string contains the user's matrix ID */
+"onboarding_congratulations_message" = "你的账户%@已创建";
+"onboarding_congratulations_title" = "祝贺!";
+"onboarding_use_case_existing_server_button" = "连接到服务器";
+"onboarding_use_case_existing_server_message" = "想加入一个现有得服务器?";
+"onboarding_use_case_skip_button" = "跳过此问题";
+/* The placeholder string contains onboarding_use_case_skip_button as a tappable action */
+"onboarding_use_case_not_sure_yet" = "还不确定?%@";
+"onboarding_use_case_community_messaging" = "社群";
+"onboarding_use_case_work_messaging" = "团队";
+"onboarding_use_case_title" = "你会和谁聊得最多?";
+"onboarding_splash_page_4_message" = "Element也很适合工作场所。受世界最安全的组织的信任。";
+"onboarding_splash_page_3_message" = "端到端加密且不要求电话号码。无广告或数据挖掘。";
+"onboarding_splash_page_2_message" = "选择在哪里保存你的对话,给你控制和独立。通过Matrix连接。";
+
+// MARK: Reactions
+
+"room_event_action_reaction_more" = "还有%@个";
+"location_sharing_invalid_power_level_title" = "你没有权限分享实时位置";
+/* The placeholder will show the homeserver's domain */
+"authentication_verify_msisdn_input_message" = "%@需要验证你的账户";
+"space_settings_update_failed_message" = "更新空间设置失败。要重试吗?";
+"space_settings_access_section" = "谁能访问此空间?";
+"space_topic" = "描述";
+"space_public_join_rule_detail" = "对任何人开放,最适合社群";
+"spaces_invite_people" = "邀请人";
+"space_private_join_rule_detail" = "仅邀请,最适合你自己或团队";
+"spaces_coming_soon_detail" = "此特性尚未实现,但是快了。目前可以在计算机上使用%@来体验。";
+"spaces_explore_rooms_room_number" = "%@个房间";
+"spaces_create_space_title" = "创建空间";
+"spaces_add_space_title" = "创建空间";
+"space_invite_not_enough_permission" = "你没权限邀请人来此空间";
+"room_invite_not_enough_permission" = "你没权限邀请人来此房间";
+"room_invite_to_space_option_detail" = "他们可以探索%@,但不会成为其成员%@。";
+
+// MARK: - Share invite link
+
+"share_invite_link_action" = "分享邀请链接";
diff --git a/Riot/Categories/UIViewController.swift b/Riot/Categories/UIViewController.swift
index a12db9e793..5fb780d8c2 100644
--- a/Riot/Categories/UIViewController.swift
+++ b/Riot/Categories/UIViewController.swift
@@ -125,6 +125,27 @@ extension UIViewController {
return fabImageView
}
+ /// Defines the large title display mode for the view controller
+ /// - Parameters:
+ /// - largeTitleDisplayMode: large title display mode
+ @objc func vc_setLargeTitleDisplayMode(_ largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode) {
+ switch largeTitleDisplayMode {
+ case .automatic:
+ guard let navigationController = navigationController else { break }
+ if let index = navigationController.children.firstIndex(of: self) {
+ vc_setLargeTitleDisplayMode(index == 0 ? .always : .never)
+ } else {
+ vc_setLargeTitleDisplayMode(.always)
+ }
+ case .always, .never:
+ navigationItem.largeTitleDisplayMode = largeTitleDisplayMode
+ // Even when .never, needs to be true otherwise animation will be broken on iOS11, 12, 13
+ navigationController?.navigationBar.prefersLargeTitles = true
+ @unknown default:
+ MXLog.failure("[UIViewController] setLargeTitleDisplayMode: Missing handler for \(largeTitleDisplayMode)")
+ }
+ }
+
/// Set leftBarButtonItem with split view display mode button if there is no leftBarButtonItem defined and splitViewController exists.
/// To be Used when view controller is displayed as detail controller in split view.
func vc_setupDisplayModeLeftBarButtonItemIfNeeded() {
diff --git a/Riot/Common.xcconfig b/Riot/Common.xcconfig
index b25a82689c..6ecbeae9bd 100644
--- a/Riot/Common.xcconfig
+++ b/Riot/Common.xcconfig
@@ -20,7 +20,7 @@
#include "Config/AppIdentifiers.xcconfig"
#include "Config/AppVersion.xcconfig"
-PRODUCT_NAME = Riot
+PRODUCT_NAME = Element
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER)
INFOPLIST_FILE = Riot/SupportingFiles/Info.plist
@@ -28,7 +28,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon
CODE_SIGN_ENTITLEMENTS = Riot/SupportingFiles/Riot.entitlements
-SWIFT_OBJC_BRIDGING_HEADER = $(SRCROOT)/$(PRODUCT_NAME)/SupportingFiles/Riot-Bridging-Header.h
+SWIFT_OBJC_BRIDGING_HEADER = $(SRCROOT)/Riot/SupportingFiles/Riot-Bridging-Header.h
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks
SWIFT_OBJC_INTERFACE_HEADER_NAME = GeneratedInterface-Swift.h
diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift
index 906e277189..d0373b94fa 100644
--- a/Riot/Generated/Images.swift
+++ b/Riot/Generated/Images.swift
@@ -33,6 +33,7 @@ internal class Asset: NSObject {
internal static let authenticationEmailIcon = ImageAsset(name: "authentication_email_icon")
internal static let authenticationMsisdnIcon = ImageAsset(name: "authentication_msisdn_icon")
internal static let authenticationPasswordIcon = ImageAsset(name: "authentication_password_icon")
+ internal static let authenticationRecaptchaIcon = ImageAsset(name: "authentication_recaptcha_icon")
internal static let authenticationRevealPassword = ImageAsset(name: "authentication_reveal_password")
internal static let authenticationServerSelectionIcon = ImageAsset(name: "authentication_server_selection_icon")
internal static let authenticationSsoIconApple = ImageAsset(name: "authentication_sso_icon_apple")
@@ -114,6 +115,7 @@ internal class Asset: NSObject {
internal static let roomActionPriorityLow = ImageAsset(name: "room_action_priority_low")
internal static let homeEmptyScreenArtwork = ImageAsset(name: "home_empty_screen_artwork")
internal static let homeEmptyScreenArtworkDark = ImageAsset(name: "home_empty_screen_artwork_dark")
+ internal static let homeMySpacesAction = ImageAsset(name: "home_my_spaces_action")
internal static let plusFloatingAction = ImageAsset(name: "plus_floating_action")
internal static let versionCheckCloseIcon = ImageAsset(name: "version_check_close_icon")
internal static let versionCheckInfoIcon = ImageAsset(name: "version_check_info_icon")
@@ -193,6 +195,7 @@ internal class Asset: NSObject {
internal static let locationLiveCellIcon = ImageAsset(name: "location_live_cell_icon")
internal static let locationLiveCellLoadingIcon = ImageAsset(name: "location_live_cell_loading_icon")
internal static let locationLiveIcon = ImageAsset(name: "location_live_icon")
+ internal static let locationMapError = ImageAsset(name: "location_map_error")
internal static let locationMarkerIcon = ImageAsset(name: "location_marker_icon")
internal static let locationPinIcon = ImageAsset(name: "location_pin_icon")
internal static let locationShareIcon = ImageAsset(name: "location_share_icon")
diff --git a/Riot/Generated/Storyboards.swift b/Riot/Generated/Storyboards.swift
index 84fa5c1d6a..ee1f961585 100644
--- a/Riot/Generated/Storyboards.swift
+++ b/Riot/Generated/Storyboards.swift
@@ -10,322 +10,324 @@ import UIKit
// MARK: - Storyboard Scenes
-// swiftlint:disable explicit_type_interface identifier_name line_length type_body_length type_name
+// swiftlint:disable explicit_type_interface identifier_name line_length prefer_self_in_static_references
+// swiftlint:disable type_body_length type_name
internal enum StoryboardScene {
internal enum CallTransferMainViewController: StoryboardType {
internal static let storyboardName = "CallTransferMainViewController"
- internal static let initialScene = InitialSceneType(storyboard: CallTransferMainViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: CallTransferMainViewController.self)
}
internal enum CallTransferSelectContactViewController: StoryboardType {
internal static let storyboardName = "CallTransferSelectContactViewController"
- internal static let initialScene = InitialSceneType(storyboard: CallTransferSelectContactViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: CallTransferSelectContactViewController.self)
}
internal enum DeviceVerificationIncomingViewController: StoryboardType {
internal static let storyboardName = "DeviceVerificationIncomingViewController"
- internal static let initialScene = InitialSceneType(storyboard: DeviceVerificationIncomingViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: DeviceVerificationIncomingViewController.self)
}
internal enum DeviceVerificationStartViewController: StoryboardType {
internal static let storyboardName = "DeviceVerificationStartViewController"
- internal static let initialScene = InitialSceneType(storyboard: DeviceVerificationStartViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: DeviceVerificationStartViewController.self)
}
internal enum DialpadViewController: StoryboardType {
internal static let storyboardName = "DialpadViewController"
- internal static let initialScene = InitialSceneType(storyboard: DialpadViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: DialpadViewController.self)
}
internal enum EditHistoryViewController: StoryboardType {
internal static let storyboardName = "EditHistoryViewController"
- internal static let initialScene = InitialSceneType(storyboard: EditHistoryViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: EditHistoryViewController.self)
}
internal enum EmojiPickerViewController: StoryboardType {
internal static let storyboardName = "EmojiPickerViewController"
- internal static let initialScene = InitialSceneType(storyboard: EmojiPickerViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: EmojiPickerViewController.self)
}
internal enum EnterNewRoomDetailsViewController: StoryboardType {
internal static let storyboardName = "EnterNewRoomDetailsViewController"
- internal static let initialScene = InitialSceneType(storyboard: EnterNewRoomDetailsViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: EnterNewRoomDetailsViewController.self)
}
internal enum EnterPinCodeViewController: StoryboardType {
internal static let storyboardName = "EnterPinCodeViewController"
- internal static let initialScene = InitialSceneType(storyboard: EnterPinCodeViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: EnterPinCodeViewController.self)
}
internal enum KeyBackupRecoverFromPassphraseViewController: StoryboardType {
internal static let storyboardName = "KeyBackupRecoverFromPassphraseViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverFromPassphraseViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverFromPassphraseViewController.self)
}
internal enum KeyBackupRecoverFromPrivateKeyViewController: StoryboardType {
internal static let storyboardName = "KeyBackupRecoverFromPrivateKeyViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverFromPrivateKeyViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverFromPrivateKeyViewController.self)
}
internal enum KeyBackupRecoverFromRecoveryKeyViewController: StoryboardType {
internal static let storyboardName = "KeyBackupRecoverFromRecoveryKeyViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverFromRecoveryKeyViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverFromRecoveryKeyViewController.self)
}
internal enum KeyBackupRecoverSuccessViewController: StoryboardType {
internal static let storyboardName = "KeyBackupRecoverSuccessViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverSuccessViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyBackupRecoverSuccessViewController.self)
}
internal enum KeyBackupSetupIntroViewController: StoryboardType {
internal static let storyboardName = "KeyBackupSetupIntroViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupIntroViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupIntroViewController.self)
}
internal enum KeyBackupSetupPassphraseViewController: StoryboardType {
internal static let storyboardName = "KeyBackupSetupPassphraseViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupPassphraseViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupPassphraseViewController.self)
}
internal enum KeyBackupSetupSuccessFromPassphraseViewController: StoryboardType {
internal static let storyboardName = "KeyBackupSetupSuccessFromPassphraseViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromPassphraseViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromPassphraseViewController.self)
}
internal enum KeyBackupSetupSuccessFromRecoveryKeyViewController: StoryboardType {
internal static let storyboardName = "KeyBackupSetupSuccessFromRecoveryKeyViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromRecoveryKeyViewController.self)
+ 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 static let initialScene = InitialSceneType(storyboard: KeyBackupSetupSuccessFromSecureBackupViewController.self)
}
internal enum KeyVerificationDataLoadingViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationDataLoadingViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyVerificationDataLoadingViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyVerificationDataLoadingViewController.self)
}
internal enum KeyVerificationManuallyVerifyViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationManuallyVerifyViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyVerificationManuallyVerifyViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyVerificationManuallyVerifyViewController.self)
}
internal enum KeyVerificationScanConfirmationViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationScanConfirmationViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyVerificationScanConfirmationViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyVerificationScanConfirmationViewController.self)
}
internal enum KeyVerificationSelfVerifyStartViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationSelfVerifyStartViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyVerificationSelfVerifyStartViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyVerificationSelfVerifyStartViewController.self)
}
internal enum KeyVerificationSelfVerifyWaitViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationSelfVerifyWaitViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyVerificationSelfVerifyWaitViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyVerificationSelfVerifyWaitViewController.self)
}
internal enum KeyVerificationVerifiedViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationVerifiedViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyVerificationVerifiedViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyVerificationVerifiedViewController.self)
}
internal enum KeyVerificationVerifyBySASViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationVerifyBySASViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyVerificationVerifyBySASViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyVerificationVerifyBySASViewController.self)
}
internal enum KeyVerificationVerifyByScanningViewController: StoryboardType {
internal static let storyboardName = "KeyVerificationVerifyByScanningViewController"
- internal static let initialScene = InitialSceneType(storyboard: KeyVerificationVerifyByScanningViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: KeyVerificationVerifyByScanningViewController.self)
}
internal enum MajorUpdateViewController: StoryboardType {
internal static let storyboardName = "MajorUpdateViewController"
- internal static let initialScene = InitialSceneType(storyboard: MajorUpdateViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: MajorUpdateViewController.self)
}
internal enum OptionListViewController: StoryboardType {
internal static let storyboardName = "OptionListViewController"
- internal static let initialScene = InitialSceneType(storyboard: OptionListViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: OptionListViewController.self)
}
internal enum QRCodeReaderViewController: StoryboardType {
internal static let storyboardName = "QRCodeReaderViewController"
- internal static let initialScene = InitialSceneType(storyboard: QRCodeReaderViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: QRCodeReaderViewController.self)
}
internal enum ReactionHistoryViewController: StoryboardType {
internal static let storyboardName = "ReactionHistoryViewController"
- internal static let initialScene = InitialSceneType(storyboard: ReactionHistoryViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: ReactionHistoryViewController.self)
}
internal enum RoomContextPreviewViewController: StoryboardType {
internal static let storyboardName = "RoomContextPreviewViewController"
- internal static let initialScene = InitialSceneType(storyboard: RoomContextPreviewViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: RoomContextPreviewViewController.self)
}
internal enum RoomContextualMenuViewController: StoryboardType {
internal static let storyboardName = "RoomContextualMenuViewController"
- internal static let initialScene = InitialSceneType(storyboard: RoomContextualMenuViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: RoomContextualMenuViewController.self)
}
internal enum RoomCreationEventsModalViewController: StoryboardType {
internal static let storyboardName = "RoomCreationEventsModalViewController"
- internal static let initialScene = InitialSceneType(storyboard: RoomCreationEventsModalViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: RoomCreationEventsModalViewController.self)
}
internal enum RoomInfoListViewController: StoryboardType {
internal static let storyboardName = "RoomInfoListViewController"
- internal static let initialScene = InitialSceneType(storyboard: RoomInfoListViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: RoomInfoListViewController.self)
}
internal enum RoomNotificationSettingsViewController: StoryboardType {
internal static let storyboardName = "RoomNotificationSettingsViewController"
- internal static let initialScene = InitialSceneType(storyboard: RoomNotificationSettingsViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: RoomNotificationSettingsViewController.self)
}
internal enum SecretsRecoveryWithKeyViewController: StoryboardType {
internal static let storyboardName = "SecretsRecoveryWithKeyViewController"
- internal static let initialScene = InitialSceneType(storyboard: SecretsRecoveryWithKeyViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SecretsRecoveryWithKeyViewController.self)
}
internal enum SecretsRecoveryWithPassphraseViewController: StoryboardType {
internal static let storyboardName = "SecretsRecoveryWithPassphraseViewController"
- internal static let initialScene = InitialSceneType(storyboard: SecretsRecoveryWithPassphraseViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SecretsRecoveryWithPassphraseViewController.self)
}
internal enum SecretsResetViewController: StoryboardType {
internal static let storyboardName = "SecretsResetViewController"
- internal static let initialScene = InitialSceneType(storyboard: SecretsResetViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SecretsResetViewController.self)
}
internal enum SecretsSetupRecoveryKeyViewController: StoryboardType {
internal static let storyboardName = "SecretsSetupRecoveryKeyViewController"
- internal static let initialScene = InitialSceneType(storyboard: SecretsSetupRecoveryKeyViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SecretsSetupRecoveryKeyViewController.self)
}
internal enum SecretsSetupRecoveryPassphraseViewController: StoryboardType {
internal static let storyboardName = "SecretsSetupRecoveryPassphraseViewController"
- internal static let initialScene = InitialSceneType(storyboard: SecretsSetupRecoveryPassphraseViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SecretsSetupRecoveryPassphraseViewController.self)
}
internal enum SecureBackupSetupIntroViewController: StoryboardType {
internal static let storyboardName = "SecureBackupSetupIntroViewController"
- internal static let initialScene = InitialSceneType(storyboard: SecureBackupSetupIntroViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SecureBackupSetupIntroViewController.self)
}
internal enum ServiceTermsModalScreenViewController: StoryboardType {
internal static let storyboardName = "ServiceTermsModalScreenViewController"
- internal static let initialScene = InitialSceneType(storyboard: ServiceTermsModalScreenViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: ServiceTermsModalScreenViewController.self)
}
internal enum SettingsDiscoveryThreePidDetailsViewController: StoryboardType {
internal static let storyboardName = "SettingsDiscoveryThreePidDetailsViewController"
- internal static let initialScene = InitialSceneType(storyboard: SettingsDiscoveryThreePidDetailsViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SettingsDiscoveryThreePidDetailsViewController.self)
}
internal enum SettingsIdentityServerViewController: StoryboardType {
internal static let storyboardName = "SettingsIdentityServerViewController"
- internal static let initialScene = InitialSceneType(storyboard: SettingsIdentityServerViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SettingsIdentityServerViewController.self)
}
internal enum SetupBiometricsViewController: StoryboardType {
internal static let storyboardName = "SetupBiometricsViewController"
- internal static let initialScene = InitialSceneType(storyboard: SetupBiometricsViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SetupBiometricsViewController.self)
}
internal enum ShowDirectoryViewController: StoryboardType {
internal static let storyboardName = "ShowDirectoryViewController"
- internal static let initialScene = InitialSceneType(storyboard: ShowDirectoryViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: ShowDirectoryViewController.self)
- internal static let searchableDirectoryViewController = SceneType(storyboard: ShowDirectoryViewController.self, identifier: "SearchableDirectoryViewController")
+ 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 static let initialScene = InitialSceneType(storyboard: SideMenuViewController.self)
}
internal enum SimpleScreenTemplateViewController: StoryboardType {
internal static let storyboardName = "SimpleScreenTemplateViewController"
- internal static let initialScene = InitialSceneType(storyboard: SimpleScreenTemplateViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SimpleScreenTemplateViewController.self)
}
internal enum SpaceChildRoomDetailViewController: StoryboardType {
internal static let storyboardName = "SpaceChildRoomDetailViewController"
- internal static let initialScene = InitialSceneType(storyboard: SpaceChildRoomDetailViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SpaceChildRoomDetailViewController.self)
}
internal enum SpaceDetailViewController: StoryboardType {
internal static let storyboardName = "SpaceDetailViewController"
- internal static let initialScene = InitialSceneType(storyboard: SpaceDetailViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SpaceDetailViewController.self)
}
internal enum SpaceExploreRoomViewController: StoryboardType {
internal static let storyboardName = "SpaceExploreRoomViewController"
- internal static let initialScene = InitialSceneType(storyboard: SpaceExploreRoomViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SpaceExploreRoomViewController.self)
}
internal enum SpaceFeatureUnaivableViewController: StoryboardType {
internal static let storyboardName = "SpaceFeatureUnaivableViewController"
- internal static let initialScene = InitialSceneType(storyboard: SpaceFeatureUnaivableViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SpaceFeatureUnaivableViewController.self)
}
internal enum SpaceListViewController: StoryboardType {
internal static let storyboardName = "SpaceListViewController"
- internal static let initialScene = InitialSceneType(storyboard: SpaceListViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SpaceListViewController.self)
}
internal enum SpaceMenuViewController: StoryboardType {
internal static let storyboardName = "SpaceMenuViewController"
- internal static let initialScene = InitialSceneType(storyboard: SpaceMenuViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: SpaceMenuViewController.self)
}
internal enum TemplateScreenViewController: StoryboardType {
internal static let storyboardName = "TemplateScreenViewController"
- internal static let initialScene = InitialSceneType(storyboard: TemplateScreenViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: TemplateScreenViewController.self)
}
internal enum ThreadListViewController: StoryboardType {
internal static let storyboardName = "ThreadListViewController"
- internal static let initialScene = InitialSceneType(storyboard: ThreadListViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: ThreadListViewController.self)
}
internal enum ThreadsBetaViewController: StoryboardType {
internal static let storyboardName = "ThreadsBetaViewController"
- internal static let initialScene = InitialSceneType(storyboard: ThreadsBetaViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: ThreadsBetaViewController.self)
}
internal enum ThreadsNoticeViewController: StoryboardType {
internal static let storyboardName = "ThreadsNoticeViewController"
- internal static let initialScene = InitialSceneType(storyboard: ThreadsNoticeViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: ThreadsNoticeViewController.self)
}
internal enum UserVerificationSessionStatusViewController: StoryboardType {
internal static let storyboardName = "UserVerificationSessionStatusViewController"
- internal static let initialScene = InitialSceneType(storyboard: UserVerificationSessionStatusViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: UserVerificationSessionStatusViewController.self)
}
internal enum UserVerificationSessionsStatusViewController: StoryboardType {
internal static let storyboardName = "UserVerificationSessionsStatusViewController"
- internal static let initialScene = InitialSceneType(storyboard: UserVerificationSessionsStatusViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: UserVerificationSessionsStatusViewController.self)
}
internal enum UserVerificationStartViewController: StoryboardType {
internal static let storyboardName = "UserVerificationStartViewController"
- internal static let initialScene = InitialSceneType(storyboard: UserVerificationStartViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: UserVerificationStartViewController.self)
}
internal enum WidgetPermissionViewController: StoryboardType {
internal static let storyboardName = "WidgetPermissionViewController"
- internal static let initialScene = InitialSceneType(storyboard: WidgetPermissionViewController.self)
+ internal static let initialScene = InitialSceneType(storyboard: WidgetPermissionViewController.self)
}
}
-// swiftlint:enable explicit_type_interface identifier_name line_length type_body_length type_name
+// swiftlint:enable explicit_type_interface identifier_name line_length prefer_self_in_static_references
+// swiftlint:enable type_body_length type_name
// MARK: - Implementation Details
diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift
index a098114a0d..d4323c05dc 100644
--- a/Riot/Generated/Strings.swift
+++ b/Riot/Generated/Strings.swift
@@ -115,6 +115,82 @@ public class VectorL10n: NSObject {
public static var add: String {
return VectorL10n.tr("Vector", "add")
}
+ /// All
+ public static var allChatsAllFilter: String {
+ return VectorL10n.tr("Vector", "all_chats_all_filter")
+ }
+ /// Layout preferences
+ public static var allChatsEditLayout: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout")
+ }
+ /// Sort by activity
+ public static var allChatsEditLayoutActivityOrder: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_activity_order")
+ }
+ /// Automatically filter your messages into the categories of your choice
+ public static var allChatsEditLayoutAddFiltersMessage: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_add_filters_message")
+ }
+ /// Filter your messages
+ public static var allChatsEditLayoutAddFiltersTitle: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_add_filters_title")
+ }
+ /// Pin sections to home for easy access
+ public static var allChatsEditLayoutAddSectionMessage: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_add_section_message")
+ }
+ /// Add section to home
+ public static var allChatsEditLayoutAddSectionTitle: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_add_section_title")
+ }
+ /// Sort A-Z
+ public static var allChatsEditLayoutAlphabeticalOrder: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_alphabetical_order")
+ }
+ /// Pin your spaces
+ public static var allChatsEditLayoutPinSpacesTitle: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_pin_spaces_title")
+ }
+ /// Recents
+ public static var allChatsEditLayoutRecents: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_recents")
+ }
+ /// Show filters
+ public static var allChatsEditLayoutShowFilters: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_show_filters")
+ }
+ /// Show recents
+ public static var allChatsEditLayoutShowRecents: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_show_recents")
+ }
+ /// Sort messages by
+ public static var allChatsEditLayoutSortingOptionsTitle: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_sorting_options_title")
+ }
+ /// Unreads
+ public static var allChatsEditLayoutUnreads: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_layout_unreads")
+ }
+ /// Leave %@
+ public static func allChatsEditMenuLeaveSpace(_ p1: String) -> String {
+ return VectorL10n.tr("Vector", "all_chats_edit_menu_leave_space", p1)
+ }
+ /// Space settings
+ public static var allChatsEditMenuSpaceSettings: String {
+ return VectorL10n.tr("Vector", "all_chats_edit_menu_space_settings")
+ }
+ /// Chats
+ public static var allChatsSectionTitle: String {
+ return VectorL10n.tr("Vector", "all_chats_section_title")
+ }
+ /// All chats
+ public static var allChatsTitle: String {
+ return VectorL10n.tr("Vector", "all_chats_title")
+ }
+ /// User settings
+ public static var allChatsUserMenuSettings: String {
+ return VectorL10n.tr("Vector", "all_chats_user_menu_settings")
+ }
/// Help us identify issues and improve %@ by sharing anonymous usage data. To understand how people use multiple devices, we’ll generate a random identifier, shared by your devices.
public static func analyticsPromptMessageNewUser(_ p1: String) -> String {
return VectorL10n.tr("Vector", "analytics_prompt_message_new_user", p1)
@@ -3115,6 +3191,10 @@ public class VectorL10n: NSObject {
public static var locationSharingMapCreditsTitle: String {
return VectorL10n.tr("Vector", "location_sharing_map_credits_title")
}
+ /// Unable to load map\nThis homeserver is not configured to display maps
+ public static var locationSharingMapLoadingError: String {
+ return VectorL10n.tr("Vector", "location_sharing_map_loading_error")
+ }
/// Open in Apple Maps
public static var locationSharingOpenAppleMaps: String {
return VectorL10n.tr("Vector", "location_sharing_open_apple_maps")
@@ -6063,6 +6143,10 @@ public class VectorL10n: NSObject {
public static var roomRecentsPeopleSection: String {
return VectorL10n.tr("Vector", "room_recents_people_section")
}
+ /// Recently viewed
+ public static var roomRecentsRecentlyViewedSection: String {
+ return VectorL10n.tr("Vector", "room_recents_recently_viewed_section")
+ }
/// SYSTEM ALERTS
public static var roomRecentsServerNoticeSection: String {
return VectorL10n.tr("Vector", "room_recents_server_notice_section")
@@ -7707,6 +7791,10 @@ public class VectorL10n: NSObject {
public static var spacePublicJoinRuleDetail: String {
return VectorL10n.tr("Vector", "space_public_join_rule_detail")
}
+ /// My spaces
+ public static var spaceSelectorTitle: String {
+ return VectorL10n.tr("Vector", "space_selector_title")
+ }
/// Who can access this space?
public static var spaceSettingsAccessSection: String {
return VectorL10n.tr("Vector", "space_settings_access_section")
@@ -7747,6 +7835,10 @@ public class VectorL10n: NSObject {
public static var spacesAddSpaceTitle: String {
return VectorL10n.tr("Vector", "spaces_add_space_title")
}
+ /// Create space within %@
+ public static func spacesAddSubspaceTitle(_ p1: String) -> String {
+ return VectorL10n.tr("Vector", "spaces_add_subspace_title", p1)
+ }
/// This feature hasn’t been implemented here, but it’s on the way. For now, you can do that with %@ on your computer.
public static func spacesComingSoonDetail(_ p1: String) -> String {
return VectorL10n.tr("Vector", "spaces_coming_soon_detail", p1)
@@ -7759,6 +7851,10 @@ public class VectorL10n: NSObject {
public static var spacesCreateSpaceTitle: String {
return VectorL10n.tr("Vector", "spaces_create_space_title")
}
+ /// Create a subspace
+ public static var spacesCreateSubspaceTitle: String {
+ return VectorL10n.tr("Vector", "spaces_create_subspace_title")
+ }
/// As this space is just for you, no one will be informed. You can add more later.
public static var spacesCreationAddRoomsMessage: String {
return VectorL10n.tr("Vector", "spaces_creation_add_rooms_message")
@@ -7991,6 +8087,14 @@ public class VectorL10n: NSObject {
public static var spacesNoRoomFoundDetail: String {
return VectorL10n.tr("Vector", "spaces_no_room_found_detail")
}
+ /// The created space will be added to %@.
+ public static func spacesSubspaceCreationVisibilityMessage(_ p1: String) -> String {
+ return VectorL10n.tr("Vector", "spaces_subspace_creation_visibility_message", p1)
+ }
+ /// What type of subspace do you want to create?
+ public static var spacesSubspaceCreationVisibilityTitle: String {
+ return VectorL10n.tr("Vector", "spaces_subspace_creation_visibility_title")
+ }
/// Suggested
public static var spacesSuggestedRoom: String {
return VectorL10n.tr("Vector", "spaces_suggested_room")
diff --git a/Riot/Managers/PushNotification/PushNotificationService.m b/Riot/Managers/PushNotification/PushNotificationService.m
index 58b9aaaf90..5dd11e31c7 100644
--- a/Riot/Managers/PushNotification/PushNotificationService.m
+++ b/Riot/Managers/PushNotification/PushNotificationService.m
@@ -347,7 +347,8 @@ - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNot
{
completionHandler(UNNotificationPresentationOptionBadge
| UNNotificationPresentationOptionSound
- | UNNotificationPresentationOptionBanner);
+ | UNNotificationPresentationOptionBanner
+ | UNNotificationPresentationOptionList);
}
}
else
diff --git a/Riot/Managers/Theme/Themes/DarkTheme.swift b/Riot/Managers/Theme/Themes/DarkTheme.swift
index 388105356c..eaf4c41841 100644
--- a/Riot/Managers/Theme/Themes/DarkTheme.swift
+++ b/Riot/Managers/Theme/Themes/DarkTheme.swift
@@ -26,7 +26,7 @@ class DarkTheme: NSObject, Theme {
var backgroundColor: UIColor = UIColor(rgb: 0x15191E)
- var baseColor: UIColor = UIColor(rgb: 0x21262C)
+ var baseColor: UIColor = BuildSettings.newAppLayoutEnabled ? UIColor(rgb: 0x15191E) : UIColor(rgb: 0x21262C)
var baseIconPrimaryColor: UIColor = UIColor(rgb: 0xEDF3FF)
var baseTextPrimaryColor: UIColor = UIColor(rgb: 0xFFFFFF)
var baseTextSecondaryColor: UIColor = UIColor(rgb: 0xA9B2BC)
@@ -35,7 +35,7 @@ class DarkTheme: NSObject, Theme {
var searchPlaceholderColor: UIColor = UIColor(rgb: 0xA9B2BC)
var searchResultHighlightColor: UIColor = UIColor(rgb: 0xFCC639).withAlphaComponent(0.3)
- var headerBackgroundColor: UIColor = UIColor(rgb: 0x21262C)
+ var headerBackgroundColor: UIColor = BuildSettings.newAppLayoutEnabled ? UIColor(rgb: 0x15191E) : UIColor(rgb: 0x21262C)
var headerBorderColor: UIColor = UIColor(rgb: 0x15191E)
var headerTextPrimaryColor: UIColor = UIColor(rgb: 0xFFFFFF)
var headerTextSecondaryColor: UIColor = UIColor(rgb: 0xA9B2BC)
@@ -131,13 +131,17 @@ class DarkTheme: NSObject, Theme {
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = baseColor
+
if !modernScrollEdgeAppearance {
appearance.shadowColor = nil
}
appearance.titleTextAttributes = [
- NSAttributedString.Key.foregroundColor: textPrimaryColor
+ .foregroundColor: textPrimaryColor
]
-
+ appearance.largeTitleTextAttributes = [
+ .foregroundColor: textPrimaryColor
+ ]
+
navigationBar.standardAppearance = appearance
navigationBar.scrollEdgeAppearance = modernScrollEdgeAppearance ? nil : appearance
} else {
diff --git a/Riot/Managers/Theme/Themes/DefaultTheme.swift b/Riot/Managers/Theme/Themes/DefaultTheme.swift
index 7ec7101c89..f2d9231ec8 100644
--- a/Riot/Managers/Theme/Themes/DefaultTheme.swift
+++ b/Riot/Managers/Theme/Themes/DefaultTheme.swift
@@ -25,7 +25,7 @@ class DefaultTheme: NSObject, Theme {
var backgroundColor: UIColor = UIColor(rgb: 0xFFFFFF)
- var baseColor: UIColor = UIColor(rgb: 0xF5F7FA)
+ var baseColor: UIColor = BuildSettings.newAppLayoutEnabled ? UIColor(rgb: 0xFFFFFF) : UIColor(rgb: 0xF5F7FA)
var baseIconPrimaryColor: UIColor = UIColor(rgb: 0xFFFFFF)
var baseTextPrimaryColor: UIColor = UIColor(rgb: 0xFFFFFF)
var baseTextSecondaryColor: UIColor = UIColor(rgb: 0x8F97A3)
@@ -34,7 +34,7 @@ class DefaultTheme: NSObject, Theme {
var searchPlaceholderColor: UIColor = UIColor(rgb: 0x8F97A3)
var searchResultHighlightColor: UIColor = UIColor(rgb: 0xFCC639).withAlphaComponent(0.2)
- var headerBackgroundColor: UIColor = UIColor(rgb: 0xF5F7FA)
+ var headerBackgroundColor: UIColor = BuildSettings.newAppLayoutEnabled ? UIColor(rgb: 0xFFFFFF) : UIColor(rgb: 0xF5F7FA)
var headerBorderColor: UIColor = UIColor(rgb: 0xE9EDF1)
var headerTextPrimaryColor: UIColor = UIColor(rgb: 0x17191C)
var headerTextSecondaryColor: UIColor = UIColor(rgb: 0x737D8C)
@@ -136,13 +136,17 @@ class DefaultTheme: NSObject, Theme {
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = baseColor
+
if !modernScrollEdgeAppearance {
appearance.shadowColor = nil
}
appearance.titleTextAttributes = [
- NSAttributedString.Key.foregroundColor: textPrimaryColor
+ .foregroundColor: textPrimaryColor
]
-
+ appearance.largeTitleTextAttributes = [
+ .foregroundColor: textPrimaryColor
+ ]
+
navigationBar.standardAppearance = appearance
navigationBar.scrollEdgeAppearance = modernScrollEdgeAppearance ? nil : appearance
} else {
@@ -164,6 +168,10 @@ class DefaultTheme: NSObject, Theme {
searchBar.backgroundImage = UIImage() // Remove top and bottom shadow
searchBar.tintColor = self.tintColor
+ guard !BuildSettings.newAppLayoutEnabled else {
+ return
+ }
+
if #available(iOS 13.0, *) {
searchBar.searchTextField.backgroundColor = self.searchBackgroundColor
searchBar.searchTextField.textColor = self.searchPlaceholderColor
diff --git a/Riot/Managers/Widgets/WidgetManager.m b/Riot/Managers/Widgets/WidgetManager.m
index 81413d8122..3595eb4df5 100644
--- a/Riot/Managers/Widgets/WidgetManager.m
+++ b/Riot/Managers/Widgets/WidgetManager.m
@@ -779,6 +779,8 @@ - (void)loadConfigs
NSData *configsData = [userDefaults objectForKey:@"integrationManagerConfigs"];
if (configsData)
{
+ // We need to map the config class name since the bundle name was updated otherwise unarchiving crashes.
+ [NSKeyedUnarchiver setClass:WidgetManagerConfig.class forClassName:@"Riot.WidgetManagerConfig"];
configs = [NSMutableDictionary dictionaryWithDictionary:[NSKeyedUnarchiver unarchiveObjectWithData:configsData]];
}
diff --git a/Riot/Modules/Application/AppCoordinator.swift b/Riot/Modules/Application/AppCoordinator.swift
index f380cdc44c..202e698a04 100755
--- a/Riot/Modules/Application/AppCoordinator.swift
+++ b/Riot/Modules/Application/AppCoordinator.swift
@@ -75,6 +75,7 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
super.init()
setupFlexDebuggerOnWindow(window)
+ update(with: ThemeService.shared().theme)
}
// MARK: - Public methods
@@ -107,6 +108,8 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
// 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")
+
+ NotificationCenter.default.addObserver(self, selector: #selector(self.themeDidChange), name: Notification.Name.themeServiceDidChangeTheme, object: nil)
}
func open(url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
@@ -122,6 +125,18 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
}
}
+ // MARK: - Theme management
+
+ @objc private func themeDidChange() {
+ update(with: ThemeService.shared().theme)
+ }
+
+ private func update(with theme: Theme) {
+ for window in UIApplication.shared.windows {
+ window.overrideUserInterfaceStyle = ThemeService.shared().theme.userInterfaceStyle
+ }
+ }
+
// MARK: - Private methods
private func setupLogger() {
UILog.configure(logger: MatrixSDKLogger.self)
diff --git a/Riot/Modules/Application/LegacyAppDelegate.h b/Riot/Modules/Application/LegacyAppDelegate.h
index 429fccb142..b4ed788525 100644
--- a/Riot/Modules/Application/LegacyAppDelegate.h
+++ b/Riot/Modules/Application/LegacyAppDelegate.h
@@ -234,10 +234,10 @@ UINavigationControllerDelegate
Process the fragment part of a vector.im link.
@param fragment the fragment part of the universal link.
- @param universalLinkURL the unprocessed the universal link URL (optional).
+ @param universalLink the original universal link.
@return YES in case of processing success.
*/
-- (BOOL)handleUniversalLinkFragment:(NSString*)fragment fromURL:(NSURL*)universalLinkURL;
+- (BOOL)handleUniversalLinkFragment:(NSString*)fragment fromLink:(UniversalLink*)universalLink;
/**
Process the URL of a vector.im link.
diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m
index 8bb9c9187a..90038c046d 100644
--- a/Riot/Modules/Application/LegacyAppDelegate.m
+++ b/Riot/Modules/Application/LegacyAppDelegate.m
@@ -419,8 +419,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: isProtectedDataAvailable: %@", @([application isProtectedDataAvailable]));
_configuration = [AppConfiguration new];
+
self.clearingCache = NO;
-
// Log app information
NSString *appDisplayName = self.appInfo.displayName;
NSString* appVersion = self.appVersion;
@@ -437,6 +437,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
// Set up theme
ThemeService.shared.themeId = RiotSettings.shared.userInterfaceTheme;
+
+ application.windows.firstObject.overrideUserInterfaceStyle = [ThemeService.shared isCurrentThemeDark] ? UIUserInterfaceStyleDark : UIUserInterfaceStyleLight;
mxSessionArray = [NSMutableArray array];
callEventsListeners = [NSMutableDictionary dictionary];
@@ -1242,7 +1244,7 @@ - (BOOL)handleUniversalLink:(NSUserActivity*)userActivity
// Continue the registration with the passed nextLink
MXLogDebug(@"[AppDelegate] handleUniversalLink. Complete registration with nextLink");
NSURL *nextLink = [NSURL URLWithString:queryParams[@"nextLink"]];
- [self handleUniversalLinkFragment:nextLink.fragment fromURL:nextLink];
+ [self handleUniversalLinkURL:nextLink];
}
else
{
@@ -1295,8 +1297,6 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin
BOOL continueUserActivity = NO;
MXKAccountManager *accountManager = [MXKAccountManager sharedManager];
- MXLogDebug(@"[AppDelegate] Universal link: handleUniversalLinkFragment: %@", fragment);
-
// Make sure we have plain utf8 character for separators
fragment = [fragment stringByRemovingPercentEncoding];
MXLogDebug(@"[AppDelegate] Universal link: handleUniversalLinkFragment: %@", fragment);
@@ -1312,17 +1312,8 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin
// Sanity check
if (!pathParams.count)
{
- // Handle simple room links with aliases/identifiers as UniversalLink will not parse these.
- NSString* absoluteUrl = [universalLink.url.absoluteString stringByRemovingPercentEncoding];
- if ([MXTools isMatrixRoomAlias:absoluteUrl]
- || [MXTools isMatrixRoomIdentifier:absoluteUrl])
- {
- pathParams = @[absoluteUrl];
- }
- else {
- MXLogDebug(@"[AppDelegate] Universal link: Error: No path parameters");
- return NO;
- }
+ MXLogFailure(@"[AppDelegate] Universal link: Error: No path parameters");
+ return NO;
}
NSString *roomIdOrAlias;
@@ -1498,9 +1489,11 @@ - (BOOL)handleUniversalLinkWithParameters:(UniversalLinkParameters*)universalLin
if (newFragment && ![newFragment isEqualToString:fragment])
{
self->universalLinkFragmentPendingRoomAlias = @{resolution.roomId: roomIdOrAlias};
-
+
+ // Create a new link with the updated fragment, otherwise we loop back round resolving the room ID infinitely.
+ UniversalLink *newLink = [[UniversalLink alloc] initWithUrl:universalLink.url updatedFragment:newFragment];
UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:newFragment
- universalLink:universalLink
+ universalLink:newLink
presentationParameters:presentationParameters];
[self handleUniversalLinkWithParameters:newParameters];
}
@@ -1704,8 +1697,9 @@ - (BOOL)handleUniversalLinkURL:(NSURL*)universalLinkURL
{
// iOS Patch: fix vector.im urls before using it
NSURL *fixedURL = [Tools fixURLWithSeveralHashKeys:universalLinkURL];
+ UniversalLink *link = [[UniversalLink alloc] initWithUrl:universalLinkURL];
- return [self handleUniversalLinkFragment:fixedURL.fragment fromURL:universalLinkURL];
+ return [self handleUniversalLinkFragment:fixedURL.fragment fromLink:link];
}
- (void)resetPendingUniversalLink
@@ -4284,6 +4278,12 @@ - (void)setupUserDefaults
{
RiotSettings.shared.showDecryptedContentInNotifications = BuildSettings.decryptNotificationsByDefault;
}
+
+ // Need to set `showAllRoomsInHomeSpace` to `true` for the new App Layout
+ if (BuildSettings.newAppLayoutEnabled)
+ {
+ RiotSettings.shared.showAllRoomsInHomeSpace = YES;
+ }
}
#pragma mark - App version management
diff --git a/Riot/Modules/Authentication/AuthenticationCoordinator.swift b/Riot/Modules/Authentication/AuthenticationCoordinator.swift
index f34f508391..19316a4a13 100644
--- a/Riot/Modules/Authentication/AuthenticationCoordinator.swift
+++ b/Riot/Modules/Authentication/AuthenticationCoordinator.swift
@@ -131,11 +131,11 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
let flow: AuthenticationFlow = initialScreen == .login ? .login : .register
do {
- let homeserverAddress = authenticationService.state.homeserver.addressFromUser ?? authenticationService.state.homeserver.address
- try await authenticationService.startFlow(flow, for: homeserverAddress)
+ // Start the flow using the default server (or a provisioning link if set).
+ try await authenticationService.startFlow(flow)
} catch {
- MXLog.error("[AuthenticationCoordinator] start: Failed to start")
- displayError(message: error.localizedDescription)
+ MXLog.error("[AuthenticationCoordinator] start: Failed to start, showing server selection.")
+ showServerSelectionScreen(for: flow)
return
}
@@ -155,6 +155,42 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
}
}
+ /// Pushes the server selection screen into the flow (other screens may also present it modally later).
+ @MainActor private func showServerSelectionScreen(for flow: AuthenticationFlow) {
+ MXLog.debug("[AuthenticationCoordinator] showServerSelectionScreen")
+ let parameters = AuthenticationServerSelectionCoordinatorParameters(authenticationService: authenticationService,
+ flow: flow,
+ hasModalPresentation: false)
+ let coordinator = AuthenticationServerSelectionCoordinator(parameters: parameters)
+ coordinator.callback = { [weak self, weak coordinator] result in
+ guard let self = self, let coordinator = coordinator else { return }
+ self.serverSelectionCoordinator(coordinator, didCompleteWith: result, for: flow)
+ }
+
+ coordinator.start()
+ add(childCoordinator: coordinator)
+
+ navigationRouter.push(coordinator, animated: true) { [weak self] in
+ self?.remove(childCoordinator: coordinator)
+ }
+ }
+
+ /// Shows the next screen in the flow after the server selection screen.
+ @MainActor private func serverSelectionCoordinator(_ coordinator: AuthenticationServerSelectionCoordinator,
+ didCompleteWith result: AuthenticationServerSelectionCoordinatorResult,
+ for flow: AuthenticationFlow) {
+ switch result {
+ case .updated:
+ if flow == .register {
+ showRegistrationScreen()
+ } else {
+ showLoginScreen()
+ }
+ case .dismiss:
+ MXLog.failure("[AuthenticationCoordinator] AuthenticationServerSelectionScreen is requesting dismiss when part of a stack.")
+ }
+ }
+
/// Presents an alert on top of the navigation router with the supplied error message.
@MainActor private func displayError(message: String) {
let alert = UIAlertController(title: VectorL10n.error, message: message, preferredStyle: .alert)
@@ -307,48 +343,6 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
// MARK: - Registration
- #warning("Unused.")
- /// Pushes the server selection screen into the flow (other screens may also present it modally later).
- @MainActor private func showServerSelectionScreen() {
- MXLog.debug("[AuthenticationCoordinator] showServerSelectionScreen")
- let parameters = AuthenticationServerSelectionCoordinatorParameters(authenticationService: authenticationService,
- flow: .register,
- hasModalPresentation: false)
- let coordinator = AuthenticationServerSelectionCoordinator(parameters: parameters)
- coordinator.callback = { [weak self, weak coordinator] result in
- guard let self = self, let coordinator = coordinator else { return }
- self.serverSelectionCoordinator(coordinator, didCompleteWith: result)
- }
-
- coordinator.start()
- add(childCoordinator: coordinator)
-
- if navigationRouter.modules.isEmpty {
- navigationRouter.setRootModule(coordinator) { [weak self] in
- self?.remove(childCoordinator: coordinator)
- }
- } else {
- navigationRouter.push(coordinator, animated: true) { [weak self] in
- self?.remove(childCoordinator: coordinator)
- }
- }
- }
-
- /// Shows the next screen in the flow after the server selection screen.
- @MainActor private func serverSelectionCoordinator(_ coordinator: AuthenticationServerSelectionCoordinator,
- didCompleteWith result: AuthenticationServerSelectionCoordinatorResult) {
- switch result {
- case .updated:
- if authenticationService.state.homeserver.needsRegistrationFallback {
- showFallback(for: .register)
- } else {
- showRegistrationScreen()
- }
- case .dismiss:
- MXLog.failure("[AuthenticationCoordinator] AuthenticationServerSelectionScreen is requesting dismiss when part of a stack.")
- }
- }
-
/// Shows the registration screen.
@MainActor private func showRegistrationScreen() {
MXLog.debug("[AuthenticationCoordinator] showRegistrationScreen")
diff --git a/Riot/Modules/Authentication/SSO/SSOAuthentificationSession.swift b/Riot/Modules/Authentication/SSO/SSOAuthentificationSession.swift
index fa595fc15b..e0b6d37dd3 100644
--- a/Riot/Modules/Authentication/SSO/SSOAuthentificationSession.swift
+++ b/Riot/Modules/Authentication/SSO/SSOAuthentificationSession.swift
@@ -64,18 +64,11 @@ final class SSOAuthentificationSession: SSOAuthentificationSessionProtocol {
completionHandler(callbackURL, finalError)
}
-
- // Ask the browser for a private authentication session
- if #available(iOS 13.0, *) {
- authentificationSession.prefersEphemeralWebBrowserSession = true
- }
self.authentificationSession = authentificationSession
- if #available(iOS 13.0, *) {
- if let asWebContextProvider = contextProvider as? ASWebAuthenticationPresentationContextProviding {
- authentificationSession.presentationContextProvider = asWebContextProvider
- }
+ if let asWebContextProvider = contextProvider as? ASWebAuthenticationPresentationContextProviding {
+ authentificationSession.presentationContextProvider = asWebContextProvider
}
authentificationSession.start()
diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h
index 44501bad6c..7f0f4a447f 100644
--- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h
+++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h
@@ -34,7 +34,8 @@ typedef NS_ENUM(NSInteger, RecentsDataSourceMode)
RecentsDataSourceModeHome = 1,
RecentsDataSourceModeFavourites,
RecentsDataSourceModePeople,
- RecentsDataSourceModeRooms
+ RecentsDataSourceModeRooms,
+ RecentsDataSourceModeAllChats
};
/**
diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m
index 80bba8f23f..dcf25b5cd8 100644
--- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m
+++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m
@@ -27,6 +27,7 @@
#import "NSArray+Element.h"
#import "GeneratedInterface-Swift.h"
+@import DesignKit;
#define RECENTSDATASOURCE_SECTION_DIRECTORY 0x01
#define RECENTSDATASOURCE_SECTION_INVITES 0x02
@@ -36,8 +37,11 @@
#define RECENTSDATASOURCE_SECTION_SERVERNOTICE 0x20
#define RECENTSDATASOURCE_SECTION_PEOPLE 0x40
#define RECENTSDATASOURCE_SECTION_SUGGESTED 0x80
+#define RECENTSDATASOURCE_SECTION_BREADCRUMBS 0x100
+#define RECENTSDATASOURCE_SECTION_ALL_CHATS 0x101
-#define RECENTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT 30.0
+#define RECENTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT 30.0
+#define RECENTSDATASOURCE_ALL_CHATS_SECTION_BOTTOM_VIEW_HEIGHT 38.0
NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSourceTapOnDirectoryServerChange";
@@ -61,6 +65,9 @@ @interface RecentsDataSource() > *)breadcrumbsRoomCellDataArray
+{
+ return self.recentsListService.breadcrumbsRoomListData.rooms;
+}
+- (NSArray> *)allChatsRoomCellDataArray
+{
+ return self.recentsListService.allChatsRoomListData.rooms;
+}
- (NSInteger)totalVisibleItemCount
{
@@ -163,18 +182,38 @@ - (RecentsDataSourceSections *)makeDataSourceSections
{
[types addObject:@(RecentsDataSourceSectionTypeSecureBackupBanner)];
}
-
- if (self.invitesCellDataArray.count > 0)
+
+ if (!BuildSettings.newAppLayoutEnabled && self.invitesCellDataArray.count > 0)
{
[types addObject:@(RecentsDataSourceSectionTypeInvites)];
}
+
+ if (self.breadcrumbsRoomCellDataArray.count > 0 && _recentsDataSourceMode == RecentsDataSourceModeAllChats)
+ {
+ AllChatsLayoutSettings *settings = AllChatsLayoutSettingsManager.shared.allChatLayoutSettings;
+ if ((settings.sections & AllChatsLayoutSectionTypeRecents) == AllChatsLayoutSectionTypeRecents)
+ {
+ [types addObject:@(RecentsDataSourceSectionTypeBreadcrumbs)];
+ }
+ }
if (self.favoriteCellDataArray.count > 0)
{
- [types addObject:@(RecentsDataSourceSectionTypeFavorites)];
+ if (_recentsDataSourceMode != RecentsDataSourceModeAllChats)
+ {
+ [types addObject:@(RecentsDataSourceSectionTypeFavorites)];
+ }
+ else
+ {
+ AllChatsLayoutSettings *settings = AllChatsLayoutSettingsManager.shared.allChatLayoutSettings;
+ if ((settings.sections & AllChatsLayoutSectionTypeFavourites) == AllChatsLayoutSectionTypeFavourites)
+ {
+ [types addObject:@(RecentsDataSourceSectionTypeFavorites)];
+ }
+ }
}
- if (self.peopleCellDataArray.count > 0 || _recentsDataSourceMode == RecentsDataSourceModeHome)
+ if (self.peopleCellDataArray.count > 0 && _recentsDataSourceMode != RecentsDataSourceModeAllChats)
{
[types addObject:@(RecentsDataSourceSectionTypePeople)];
}
@@ -185,6 +224,21 @@ - (RecentsDataSourceSections *)makeDataSourceSections
[types addObject:@(RecentsDataSourceSectionTypeConversation)];
}
+ if (self.allChatsRoomCellDataArray.count > 0 || _recentsDataSourceMode == RecentsDataSourceModeAllChats)
+ {
+ [types addObject:@(RecentsDataSourceSectionTypeAllChats)];
+ }
+
+ if (self.currentSpace == nil && BuildSettings.newAppLayoutEnabled && self.invitesCellDataArray.count > 0)
+ {
+ [types addObject:@(RecentsDataSourceSectionTypeInvites)];
+ }
+
+ if (self.currentSpace != nil && self.suggestedRoomCellDataArray.count > 0)
+ {
+ [types addObject:@(RecentsDataSourceSectionTypeSuggestedRooms)];
+ }
+
if (self.lowPriorityCellDataArray.count > 0)
{
[types addObject:@(RecentsDataSourceSectionTypeLowPriority)];
@@ -195,11 +249,6 @@ - (RecentsDataSourceSections *)makeDataSourceSections
[types addObject:@(RecentsDataSourceSectionTypeServerNotice)];
}
- if (self.suggestedRoomCellDataArray.count > 0)
- {
- [types addObject:@(RecentsDataSourceSectionTypeSuggestedRooms)];
- }
-
return [[RecentsDataSourceSections alloc] initWithSectionTypes:types.copy];
}
@@ -255,6 +304,21 @@ - (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)fr
return stickyHeader;
}
+- (void)registerAllChatsSettingsUpdateNotification
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(allChatSettingsWillUpdateNotification:) name:AllChatsLayoutSettingsManager.willUpdateSettings object:nil];
+}
+
+- (void)allChatSettingsWillUpdateNotification:(NSNotification*)notification
+{
+ self.allChatsOptionsView = nil;
+}
+
+- (void)unregisterAllChatsSettingsUpdateNotification
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:AllChatsLayoutSettingsManager.willUpdateSettings object:nil];
+}
+
#pragma mark - Space Service notifications
- (void)registerSpaceServiceDidBuildGraphNotification
@@ -567,6 +631,14 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger
{
count = self.suggestedRoomCellDataArray.count;
}
+ else if (sectionType == RecentsDataSourceSectionTypeBreadcrumbs && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_BREADCRUMBS))
+ {
+ count = self.breadcrumbsRoomCellDataArray.count;
+ }
+ else if (sectionType == RecentsDataSourceSectionTypeAllChats && !(shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_ALL_CHATS))
+ {
+ count = self.allChatsRoomCellDataArray.count;
+ }
// Adjust this count according to the potential dragged cell.
if ([self isMovingCellSection:section])
@@ -585,11 +657,22 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger
- (CGFloat)heightForHeaderInSection:(NSInteger)section
{
RecentsDataSourceSectionType sectionType = [self.sections sectionTypeForSectionIndex:section];
- if (sectionType == RecentsDataSourceSectionTypeSecureBackupBanner || sectionType == RecentsDataSourceSectionTypeCrossSigningBanner)
+ if (sectionType == RecentsDataSourceSectionTypeSecureBackupBanner ||
+ sectionType == RecentsDataSourceSectionTypeCrossSigningBanner ||
+ sectionType == RecentsDataSourceSectionTypeBreadcrumbs ||
+ (sectionType == RecentsDataSourceSectionTypeAllChats && !self.allChatsFilterOptions.optionsCount))
{
return 0.0;
}
+ if (sectionType == RecentsDataSourceSectionTypeAllChats && _recentsDataSourceMode == RecentsDataSourceModeAllChats)
+ {
+ if (self.allChatsFilterOptions.optionsCount)
+ {
+ return RECENTSDATASOURCE_ALL_CHATS_SECTION_BOTTOM_VIEW_HEIGHT;
+ }
+ }
+
return RECENTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT;
}
@@ -655,25 +738,36 @@ - (NSAttributedString *)attributedStringForHeaderTitleInSection:(NSInteger)secti
count = self.recentsListService.suggestedRoomListData.counts.total.numberOfRooms;
title = [VectorL10n roomRecentsSuggestedRoomsSection];
}
+ else if (sectionType == RecentsDataSourceSectionTypeBreadcrumbs)
+ {
+ count = self.recentsListService.breadcrumbsRoomListData.counts.total.numberOfRooms;
+ title = [VectorL10n roomRecentsRecentlyViewedSection];
+ }
+ else if (sectionType == RecentsDataSourceSectionTypeAllChats)
+ {
+ count = self.recentsListService.allChatsRoomListData.counts.total.numberOfRooms;
+ title = [VectorL10n allChatsSectionTitle];
+ }
+
- if (count && !(sectionType == RecentsDataSourceSectionTypeInvites))
+ if (count && !(sectionType == RecentsDataSourceSectionTypeInvites) && !BuildSettings.newAppLayoutEnabled)
{
NSString *roomCount = [NSString stringWithFormat:@" %tu", count];
-
+
NSMutableAttributedString *mutableSectionTitle = [[NSMutableAttributedString alloc] initWithString:title
- attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.headerTextPrimaryColor,
- NSFontAttributeName: [UIFont boldSystemFontOfSize:15.0]}];
+ attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.headerTextPrimaryColor,
+ NSFontAttributeName: [UIFont boldSystemFontOfSize:15.0]}];
[mutableSectionTitle appendAttributedString:[[NSMutableAttributedString alloc] initWithString:roomCount
- attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.headerTextSecondaryColor,
- NSFontAttributeName: [UIFont boldSystemFontOfSize:15.0]}]];
-
+ attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.headerTextSecondaryColor,
+ NSFontAttributeName: [UIFont boldSystemFontOfSize:15.0]}]];
+
sectionTitle = mutableSectionTitle;
}
else if (title)
{
- sectionTitle = [[NSAttributedString alloc] initWithString:title
- attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.headerTextPrimaryColor,
- NSFontAttributeName: [UIFont boldSystemFontOfSize:15.0]}];
+ sectionTitle = [[NSAttributedString alloc] initWithString:[title capitalizedString]
+ attributes:@{NSForegroundColorAttributeName : ThemeService.shared.theme.headerTextPrimaryColor,
+ NSFontAttributeName: [ThemeService shared].theme.fonts.calloutSB}];
}
return sectionTitle;
@@ -714,6 +808,10 @@ - (UIView *)badgeViewForHeaderTitleInSection:(NSInteger)section
{
counts = self.recentsListService.suggestedRoomListData.counts;
}
+ else if (sectionType == RecentsDataSourceSectionTypeAllChats)
+ {
+ counts = self.recentsListService.allChatsRoomListData.counts;
+ }
// Invites are counted as highlights for the badge view display.
NSUInteger numberOfNotifications = counts.total.numberOfNotifications + counts.total.numberOfInvitedRooms;
@@ -756,9 +854,12 @@ - (UIView *)badgeViewForHeaderTitleInSection:(NSInteger)section
- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView
{
- // No header view in key backup banner section
+ // No header view in key backup banner section, in cross signing banner section, in recent section, nor in all chats section if flters are disabled
RecentsDataSourceSectionType sectionType = [self.sections sectionTypeForSectionIndex:section];
- if (sectionType == RecentsDataSourceSectionTypeSecureBackupBanner || sectionType == RecentsDataSourceSectionTypeCrossSigningBanner)
+ if (sectionType == RecentsDataSourceSectionTypeSecureBackupBanner ||
+ sectionType == RecentsDataSourceSectionTypeCrossSigningBanner ||
+ sectionType == RecentsDataSourceSectionTypeBreadcrumbs ||
+ (sectionType == RecentsDataSourceSectionTypeAllChats && !self.allChatsFilterOptions.optionsCount))
{
return nil;
}
@@ -771,6 +872,7 @@ - (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame in
sectionHeader.backgroundView = [UIView new];
sectionHeader.frame = frame;
sectionHeader.backgroundView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
+ sectionHeader.topPadding = 0;
sectionHeader.topViewHeight = RECENTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT;
NSInteger sectionBitwise = 0;
@@ -808,6 +910,14 @@ - (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame in
{
sectionBitwise = RECENTSDATASOURCE_SECTION_SUGGESTED;
}
+ else if (sectionType == RecentsDataSourceSectionTypeBreadcrumbs)
+ {
+ sectionBitwise = RECENTSDATASOURCE_SECTION_BREADCRUMBS;
+ }
+ else if (sectionType == RecentsDataSourceSectionTypeAllChats)
+ {
+ sectionBitwise = RECENTSDATASOURCE_SECTION_ALL_CHATS;
+ }
}
if (sectionBitwise)
@@ -835,25 +945,52 @@ - (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame in
chevronView.contentMode = UIViewContentModeCenter;
sectionHeader.accessoryView = chevronView;
}
+
if (_recentsDataSourceMode == RecentsDataSourceModeHome
|| _recentsDataSourceMode == RecentsDataSourceModePeople
|| _recentsDataSourceMode == RecentsDataSourceModeRooms)
{
// Add a badge to display the total of missed notifications by section.
UIView *badgeView = [self badgeViewForHeaderTitleInSection:section];
-
+
if (badgeView)
{
sectionHeader.rightAccessoryView = badgeView;
}
}
- // Add label
- frame.size.height = RECENTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT - 10;
- UILabel *headerLabel = [[UILabel alloc] initWithFrame:frame];
- headerLabel.backgroundColor = [UIColor clearColor];
- headerLabel.attributedText = [self attributedStringForHeaderTitleInSection:section];
- sectionHeader.headerLabel = headerLabel;
+ if (_recentsDataSourceMode == RecentsDataSourceModeAllChats && sectionType == RecentsDataSourceSectionTypeAllChats) {
+ if (!self.allChatsOptionsView) {
+ self.allChatsOptionsView = [self.allChatsFilterOptions createFilterListView];
+ }
+
+ if (self.allChatsOptionsView)
+ {
+ [self.allChatsFilterOptions updateWithFilterOptionListView:self.allChatsOptionsView
+ unreadsCount:1 // unreads is allways visible
+ favouritesCount:self.favoriteCellDataArray.count
+ directRoomsCount:self.peopleCellDataArray.count];
+ return self.allChatsOptionsView;
+ }
+ }
+ else
+ {
+ sectionHeader.bottomView = nil;
+ }
+
+ if (!BuildSettings.newAppLayoutEnabled || !sectionHeader.bottomView)
+ {
+ // Add label
+ frame.size.height = RECENTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT - 10;
+ UILabel *headerLabel = [[UILabel alloc] initWithFrame:frame];
+ headerLabel.backgroundColor = [UIColor clearColor];
+ headerLabel.attributedText = [self attributedStringForHeaderTitleInSection:section];
+ sectionHeader.headerLabel = headerLabel;
+ }
+ else
+ {
+ sectionHeader.headerLabel = nil;
+ }
return sectionHeader;
}
@@ -915,7 +1052,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
return cell;
}
else if ((sectionType == RecentsDataSourceSectionTypeConversation && !self.conversationCellDataArray.count)
- || (sectionType == RecentsDataSourceSectionTypePeople && !self.peopleCellDataArray.count))
+ || (sectionType == RecentsDataSourceSectionTypePeople && !self.peopleCellDataArray.count)
+ || (sectionType == RecentsDataSourceSectionTypeAllChats && !self.allChatsRoomCellDataArray.count))
{
MXKTableViewCell *tableViewCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCell defaultReuseIdentifier]];
if (!tableViewCell)
@@ -1012,7 +1150,21 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
summary = self.suggestedRoomCellDataArray[cellDataIndex];
}
}
-
+ else if (sectionType == RecentsDataSourceSectionTypeBreadcrumbs)
+ {
+ if (cellDataIndex < self.breadcrumbsRoomCellDataArray.count)
+ {
+ summary = self.breadcrumbsRoomCellDataArray[cellDataIndex];
+ }
+ }
+ else if (sectionType == RecentsDataSourceSectionTypeAllChats)
+ {
+ if (cellDataIndex < self.allChatsRoomCellDataArray.count)
+ {
+ summary = self.allChatsRoomCellDataArray[cellDataIndex];
+ }
+ }
+
if (summary)
{
return [[MXKRecentCellData alloc] initWithRoomSummary:summary dataSource:self];
@@ -1192,6 +1344,38 @@ - (NSIndexPath*)cellIndexPathWithRoomId:(NSString*)roomId andMatrixSession:(MXSe
indexPath = [NSIndexPath indexPathForRow:index inSection:sectionIndex];
}
}
+
+ if (!indexPath && ([self.sections contains:RecentsDataSourceSectionTypeBreadcrumbs]))
+ {
+ index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:self.breadcrumbsRoomCellDataArray];
+
+ if (index != NSNotFound)
+ {
+ // Check whether the recent rooms are shrinked
+ if (shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_BREADCRUMBS)
+ {
+ return nil;
+ }
+ NSInteger sectionIndex = [self.sections sectionIndexForSectionType:RecentsDataSourceSectionTypeBreadcrumbs];
+ indexPath = [NSIndexPath indexPathForRow:index inSection:sectionIndex];
+ }
+ }
+
+ if (!indexPath && ([self.sections contains:RecentsDataSourceSectionTypeAllChats]))
+ {
+ index = [self cellIndexPosWithRoomId:roomId andMatrixSession:matrixSession within:self.allChatsRoomCellDataArray];
+
+ if (index != NSNotFound)
+ {
+ // Check whether the all chats rooms are shrinked
+ if (shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_ALL_CHATS)
+ {
+ return nil;
+ }
+ NSInteger sectionIndex = [self.sections sectionIndexForSectionType:RecentsDataSourceSectionTypeAllChats];
+ indexPath = [NSIndexPath indexPathForRow:index inSection:sectionIndex];
+ }
+ }
return indexPath;
}
@@ -1394,6 +1578,10 @@ - (void)paginateInSection:(NSInteger)section
{
[self.recentsListService paginateInSection:RecentsListServiceSectionSuggested];
}
+ else if (sectionType == RecentsDataSourceSectionTypeAllChats)
+ {
+ [self.recentsListService paginateInSection:RecentsListServiceSectionAllChats];
+ }
}
- (void)moveRoomCell:(MXRoom*)room from:(NSIndexPath*)oldPath to:(NSIndexPath*)newPath success:(void (^)(void))moveSuccess failure:(void (^)(NSError *error))moveFailure;
@@ -1537,6 +1725,10 @@ - (RecentsDataSourceSectionType)sectionTypeForServiceSection:(RecentsListService
return RecentsDataSourceSectionTypeServerNotice;
case RecentsListServiceSectionSuggested:
return RecentsDataSourceSectionTypeSuggestedRooms;
+ case RecentsListServiceSectionBreadcrumbs:
+ return RecentsDataSourceSectionTypeBreadcrumbs;
+ case RecentsListServiceSectionAllChats:
+ return RecentsDataSourceSectionTypeAllChats;
}
}
@@ -1589,6 +1781,16 @@ - (BOOL)isSectionShrinkedAt:(NSInteger)section
return YES;
}
+ if (sectionType == RecentsDataSourceSectionTypeBreadcrumbs && (shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_BREADCRUMBS))
+ {
+ return YES;
+ }
+
+ if (sectionType == RecentsDataSourceSectionTypeAllChats && (shrinkedSectionsBitMask & RECENTSDATASOURCE_SECTION_ALL_CHATS))
+ {
+ return YES;
+ }
+
return NO;
}
diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSourceSectionType.swift b/Riot/Modules/Common/Recents/DataSources/RecentsDataSourceSectionType.swift
index b877207572..92a301d9e3 100644
--- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSourceSectionType.swift
+++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSourceSectionType.swift
@@ -27,6 +27,8 @@ import Foundation
case lowPriority
case serverNotice
case suggestedRooms
+ case breadcrumbs
case searchedRoom
+ case allChats
case unknown
}
diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m
index fefdd7ce0d..ba23d57c48 100644
--- a/Riot/Modules/Common/Recents/RecentsViewController.m
+++ b/Riot/Modules/Common/Recents/RecentsViewController.m
@@ -36,7 +36,7 @@
NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewControllerDataReadyNotification";
-@interface RecentsViewController ()
+@interface RecentsViewController ()
{
// Tell whether a recents refresh is pending (suspended during editing mode).
BOOL isRefreshPending;
@@ -140,6 +140,7 @@ - (void)finalizeInit
_contextMenuProvider = [RecentCellContextMenuProvider new];
self.contextMenuProvider.serviceDelegate = self;
+ self.contextMenuProvider.menuProviderDelegate = self;
// Set itself as delegate by default.
self.delegate = self;
@@ -1117,166 +1118,6 @@ - (void)dataSource:(MXKDataSource *)dataSource didCellChange:(id)changes
#pragma mark - Swipe actions
-- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
-{
- [self cancelEditionMode:isRefreshPending];
-}
-
-- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- return UITableViewCellEditingStyleNone;
-}
-
-- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- MXRoom *room = [self.dataSource getRoomAtIndexPath:indexPath];
-
- if (!room)
- {
- return nil;
- }
-
- // Display no action for the invited room
- if (room.summary.membership == MXMembershipInvite)
- {
- return nil;
- }
-
- // Store the identifier of the room related to the edited cell.
- editedRoomId = room.roomId;
-
- UIColor *selectedColor = ThemeService.shared.theme.tintColor;
- UIColor *unselectedColor = ThemeService.shared.theme.tabBarUnselectedItemTintColor;
- UIColor *actionBackgroundColor = ThemeService.shared.theme.baseColor;
-
- NSString* title = @" ";
-
- // Direct chat toggle
-
- BOOL isDirect = room.isDirect;
-
- UIContextualAction *directChatAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
- title:title
- handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
- [self makeDirectEditedRoom:!isDirect];
- completionHandler(YES);
- }];
- directChatAction.backgroundColor = actionBackgroundColor;
-
- UIImage *directChatImage = AssetImages.roomActionDirectChat.image;
- directChatImage = [directChatImage vc_tintedImageUsingColor:isDirect ? selectedColor : unselectedColor];
- directChatAction.image = [directChatImage vc_notRenderedImage];
-
- // Notification toggle
-
- BOOL isMuted = room.isMute || room.isMentionsOnly;
-
- UIContextualAction *muteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
- title:title
- handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
-
- if ([BuildSettings showNotificationsV2])
- {
- [self changeEditedRoomNotificationSettings];
- }
- else
- {
- [self muteEditedRoomNotifications:!isMuted];
- }
-
-
- completionHandler(YES);
- }];
- muteAction.backgroundColor = actionBackgroundColor;
-
- UIImage *notificationImage;
- if([BuildSettings showNotificationsV2] && isMuted)
- {
- notificationImage = AssetImages.roomActionNotificationMuted.image;
- }
- else
- {
- notificationImage = AssetImages.roomActionNotification.image;
- }
-
- notificationImage = [notificationImage vc_tintedImageUsingColor:isMuted ? unselectedColor : selectedColor];
- muteAction.image = [notificationImage vc_notRenderedImage];
-
- // Favorites management
-
- MXRoomTag* currentTag = nil;
-
- // Get the room tag (use only the first one).
- if (room.accountData.tags)
- {
- NSArray* tags = room.accountData.tags.allValues;
- if (tags.count)
- {
- currentTag = tags[0];
- }
- }
-
- BOOL isFavourite = (currentTag && [kMXRoomTagFavourite isEqualToString:currentTag.name]);
-
- UIContextualAction *favouriteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
- title:title
- handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
- NSString *favouriteTag = isFavourite ? nil : kMXRoomTagFavourite;
- [self updateEditedRoomTag:favouriteTag];
- completionHandler(YES);
- }];
- favouriteAction.backgroundColor = actionBackgroundColor;
-
- UIImage *favouriteImage = AssetImages.roomActionFavourite.image;
- favouriteImage = [favouriteImage vc_tintedImageUsingColor:isFavourite ? selectedColor : unselectedColor];
- favouriteAction.image = [favouriteImage vc_notRenderedImage];
-
- // Priority toggle
-
- BOOL isInLowPriority = (currentTag && [kMXRoomTagLowPriority isEqualToString:currentTag.name]);
-
- UIContextualAction *priorityAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
- title:title
- handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
- NSString *priorityTag = isInLowPriority ? nil : kMXRoomTagLowPriority;
- [self updateEditedRoomTag:priorityTag];
- completionHandler(YES);
- }];
- priorityAction.backgroundColor = actionBackgroundColor;
-
- UIImage *priorityImage = isInLowPriority ? AssetImages.roomActionPriorityHigh.image : AssetImages.roomActionPriorityLow.image;
- priorityImage = [priorityImage vc_tintedImageUsingColor:unselectedColor];
- priorityAction.image = [priorityImage vc_notRenderedImage];
-
- // Leave action
-
- UIContextualAction *leaveAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
- title:title
- handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
- [self leaveEditedRoom];
- completionHandler(YES);
- }];
- leaveAction.backgroundColor = actionBackgroundColor;
-
- UIImage *leaveImage = AssetImages.roomActionLeave.image;
- leaveImage = [leaveImage vc_tintedImageUsingColor:unselectedColor];
- leaveAction.image = [leaveImage vc_notRenderedImage];
-
- // Create swipe action configuration
-
- NSArray *actions = @[
- leaveAction,
- priorityAction,
- favouriteAction,
- muteAction,
- directChatAction
- ];
-
- UISwipeActionsConfiguration *swipeActionConfiguration = [UISwipeActionsConfiguration configurationWithActions:actions];
- swipeActionConfiguration.performsFirstActionWithFullSwipe = NO;
- return swipeActionConfiguration;
-}
-
- (void)leaveEditedRoom
{
if (editedRoomId)
@@ -1601,10 +1442,10 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
if (roomIdOrAlias.length)
{
- // Open the room or preview it
- NSString *fragment = [NSString stringWithFormat:@"/room/%@", [MXTools encodeURIComponent:roomIdOrAlias]];
- NSURL *url = [NSURL URLWithString:[MXTools permalinkToRoom:fragment]];
- [[AppDelegate theDelegate] handleUniversalLinkFragment:fragment fromURL:url];
+ // Create a permalink to open or preview the room.
+ NSString *permalink = [MXTools permalinkToRoom:roomIdOrAlias];
+ NSURL *permalinkURL = [NSURL URLWithString:permalink];
+ [[AppDelegate theDelegate] handleUniversalLinkURL:permalinkURL];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
@@ -2549,7 +2390,6 @@ - (UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuCo
return nil;
}
- self.recentsUpdateEnabled = NO;
return [self.contextMenuProvider contextMenuConfigurationWith:cellData from:cell session:self.dataSource.mxSession];
}
@@ -2611,4 +2451,11 @@ - (void)roomContextActionService:(id)service s
editedRoomId = nil;
}
+#pragma mark - RecentCellContextMenuProviderDelegate
+
+- (void)recentCellContextMenuProviderDidStartShowingPreview:(RecentCellContextMenuProvider *)menuProvider
+{
+ self.recentsUpdateEnabled = NO;
+}
+
@end
diff --git a/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift b/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift
index 0503891c6c..64c19bb1a6 100644
--- a/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift
+++ b/Riot/Modules/Common/Recents/Service/MatrixSDK/RecentsListService.swift
@@ -15,6 +15,7 @@
//
import Foundation
+import CoreImage
@objcMembers
public class RecentsListService: NSObject, RecentsListServiceProtocol {
@@ -34,7 +35,7 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
private var invitedRoomListDataFetcher: MXRoomListDataFetcher? {
switch mode {
- case .home:
+ case .home, .allChats:
return invitedRoomListDataFetcherForHome
case .people:
return invitedRoomListDataFetcherForPeople
@@ -47,7 +48,7 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
private var favoritedRoomListDataFetcher: MXRoomListDataFetcher?
private var directRoomListDataFetcher: MXRoomListDataFetcher? {
switch mode {
- case .home:
+ case .home, .allChats:
return directRoomListDataFetcherForHome
case .people:
return directRoomListDataFetcherForPeople
@@ -68,7 +69,9 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
private var lowPriorityRoomListDataFetcher: MXRoomListDataFetcher?
private var serverNoticeRoomListDataFetcher: MXRoomListDataFetcher?
private var suggestedRoomListDataFetcher: MXRoomListDataFetcher?
-
+ private var breadcrumbsRoomListDataFetcher: MXRoomListDataFetcher?
+ private var allChatsRoomListDataFetcher: MXRoomListDataFetcher?
+
private var conversationRoomListDataFetcherForHome: MXRoomListDataFetcher?
private var conversationRoomListDataFetcherForRooms: MXRoomListDataFetcher?
private var directRoomListDataFetcherForHome: MXRoomListDataFetcher?
@@ -83,7 +86,8 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
.home: [.invited, .favorited, .directHome, .conversationHome, .lowPriority, .serverNotice, .suggested],
.favourites: [.favorited],
.people: [.invited, .directPeople],
- .rooms: [.invited, .conversationRooms, .suggested]
+ .rooms: [.invited, .conversationRooms, .suggested],
+ .allChats: [.breadcrumbs, .favorited, .directHome, .invited, .allChats, .lowPriority, .serverNotice, .suggested]
]
private var allFetchers: [MXRoomListDataFetcher] {
@@ -98,7 +102,9 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
conversationRoomListDataFetcherForRooms,
lowPriorityRoomListDataFetcher,
serverNoticeRoomListDataFetcher,
- suggestedRoomListDataFetcher
+ suggestedRoomListDataFetcher,
+ breadcrumbsRoomListDataFetcher,
+ allChatsRoomListDataFetcher
].compactMap({ $0 })
}
@@ -131,7 +137,13 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
if let fetcher = serverNoticeRoomListDataFetcher, fetcherTypes.contains(.serverNotice) {
result.append(fetcher)
}
- if let fetcher = suggestedRoomListDataFetcher, fetcherTypes.contains(.suggested) {
+ if space != nil, let fetcher = suggestedRoomListDataFetcher, fetcherTypes.contains(.suggested) {
+ result.append(fetcher)
+ }
+ if let fetcher = breadcrumbsRoomListDataFetcher, fetcherTypes.contains(.breadcrumbs) {
+ result.append(fetcher)
+ }
+ if let fetcher = allChatsRoomListDataFetcher, fetcherTypes.contains(.allChats) {
result.append(fetcher)
}
return result
@@ -149,6 +161,10 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
private let multicastDelegate: MXMulticastDelegate = MXMulticastDelegate()
// swiftlint:enable weak_delegate
+ private var noSortOptions: MXRoomListDataSortOptions {
+ return MXRoomListDataSortOptions(invitesFirst: false, sentStatus: false, lastEventDate: false, favoriteTag: false, suggested: false, alphabetical: false, missedNotificationsFirst: false, unreadMessagesFirst: false)
+ }
+
private var sortOptions: MXRoomListDataSortOptions {
switch mode {
case .home:
@@ -156,6 +172,26 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
let pinUnread = RiotSettings.shared.pinRoomsWithUnreadMessagesOnHome
return MXRoomListDataSortOptions(missedNotificationsFirst: pinMissed,
unreadMessagesFirst: pinUnread)
+ case .allChats:
+ let pinMissed = RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome
+ let pinUnread = RiotSettings.shared.pinRoomsWithUnreadMessagesOnHome
+ switch AllChatsLayoutSettingsManager.shared.allChatLayoutSettings.sorting {
+ case .alphabetical:
+ return MXRoomListDataSortOptions(invitesFirst: false,
+ sentStatus: false,
+ lastEventDate: false,
+ favoriteTag: false,
+ suggested: false,
+ alphabetical: true,
+ missedNotificationsFirst: false,
+ unreadMessagesFirst: false)
+ case .activity:
+ return MXRoomListDataSortOptions(missedNotificationsFirst: pinMissed,
+ unreadMessagesFirst: pinUnread)
+ @unknown default:
+ return MXRoomListDataSortOptions(missedNotificationsFirst: pinMissed,
+ unreadMessagesFirst: pinUnread)
+ }
default:
return MXRoomListDataSortOptions(missedNotificationsFirst: false,
unreadMessagesFirst: false)
@@ -171,6 +207,9 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
space: nil)
}
+ private var allChatLayoutSettingsManagerObserver: Any?
+ private var allChatLayoutSettingsObserver: Any?
+
private init(withSession session: MXSession,
mode: RecentsDataSourceMode,
query: String?,
@@ -183,6 +222,26 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
createFetchers()
addRiotSettingsObserver()
addSessionStateObserver()
+
+ allChatLayoutSettingsManagerObserver = NotificationCenter.default.addObserver(forName: AllChatsLayoutSettingsManager.didUpdateSettings, object: nil, queue: OperationQueue.main) { [weak self] notification in
+ guard let self = self else { return }
+ self.refresh()
+ for fetcher in self.allFetchers {
+ fetcher.refresh()
+ }
+ if let fetcher = self.allChatsRoomListDataFetcher {
+ self.updateConversationFetcher(fetcher, for: .allChats)
+ fetcher.paginate()
+ }
+ }
+
+ allChatLayoutSettingsObserver = NotificationCenter.default.addObserver(forName: AllChatsLayoutSettingsManager.didUpdateActiveFilters, object: nil, queue: OperationQueue.main) { [weak self] notification in
+ guard let self = self else { return }
+ if let fetcher = self.allChatsRoomListDataFetcher {
+ self.updateConversationFetcher(fetcher, for: .allChats)
+ fetcher.paginate()
+ }
+ }
}
// MARK: - View Data
@@ -215,6 +274,14 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
guard shouldShowSuggested else { return nil }
return suggestedRoomListDataFetcher?.data
}
+ public var breadcrumbsRoomListData: MXRoomListData? {
+ guard shouldShowBreadcrumbs else { return nil }
+ return breadcrumbsRoomListDataFetcher?.data
+ }
+ public var allChatsRoomListData: MXRoomListData? {
+ guard shouldShowAllChats else { return nil }
+ return allChatsRoomListDataFetcher?.data
+ }
public var favoritedMissedDiscussionsCount: DiscussionsCount {
guard let totalCounts = favoritedRoomListDataFetcher?.data?.counts.total else {
@@ -272,10 +339,20 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
public func updateSpace(_ space: MXSpace?) {
self.space = space
allFetchers.forEach({ $0.fetchOptions.filterOptions.space = space })
+
+ if let fetcher = conversationRoomListDataFetcherForHome {
+ self.updateConversationFetcher(fetcher, for: .home)
+ fetcher.paginate()
+ }
+
+ if let fetcher = allChatsRoomListDataFetcher {
+ self.updateConversationFetcher(fetcher, for: .allChats)
+ fetcher.paginate()
+ }
}
public func refresh() {
- allFetchers.forEach({ $0.fetchOptions.sortOptions = sortOptions })
+ allFetchers.forEach({ $0.fetchOptions.sortOptions = $0.fetchOptions.filterOptions.onlyBreadcrumbs ? noSortOptions : sortOptions })
allFetchers.forEach({ $0.fetchOptions.filterOptions.showAllRoomsInHomeSpace = showAllRoomsInHomeSpace })
}
@@ -296,6 +373,8 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
lowPriorityRoomListDataFetcher = nil
serverNoticeRoomListDataFetcher = nil
suggestedRoomListDataFetcher = nil
+ breadcrumbsRoomListDataFetcher = nil
+ allChatsRoomListDataFetcher = nil
}
// MARK: - Delegate
@@ -381,7 +460,7 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
private var shouldShowDirect: Bool {
switch mode {
- case .home:
+ case .home, .allChats:
return fetcherTypesForMode[mode]?.contains(.directHome) ?? false
case .people:
return fetcherTypesForMode[mode]?.contains(.directPeople) ?? false
@@ -413,6 +492,14 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
return fetcherTypesForMode[mode]?.contains(.suggested) ?? false
}
+ private var shouldShowBreadcrumbs: Bool {
+ return fetcherTypesForMode[mode]?.contains(.breadcrumbs) ?? false
+ }
+
+ private var shouldShowAllChats: Bool {
+ return fetcherTypesForMode[mode]?.contains(.allChats) ?? false
+ }
+
private func fetcher(forSection section: RecentsListServiceSection) -> MXRoomListDataFetcher? {
switch section {
case .invited:
@@ -429,6 +516,10 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
return serverNoticeRoomListDataFetcher
case .suggested:
return suggestedRoomListDataFetcher
+ case .breadcrumbs:
+ return breadcrumbsRoomListDataFetcher
+ case .allChats:
+ return allChatsRoomListDataFetcher
}
}
@@ -447,12 +538,17 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
return .serverNotice
} else if fetcher === suggestedRoomListDataFetcher {
return .suggested
+ } else if fetcher === breadcrumbsRoomListDataFetcher {
+ return .breadcrumbs
+ } else if fetcher === allChatsRoomListDataFetcher {
+ return .allChats
}
return nil
}
private func createCommonRoomListDataFetcher(withDataTypes dataTypes: MXRoomSummaryDataTypes = [],
onlySuggested: Bool = false,
+ onlyBreadcrumbs: Bool = false,
paginate: Bool = true,
strictMatches: Bool = false) -> MXRoomListDataFetcher {
guard let session = session else {
@@ -460,13 +556,14 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
}
let filterOptions = MXRoomListDataFilterOptions(dataTypes: dataTypes,
onlySuggested: onlySuggested,
+ onlyBreadcrumbs: onlyBreadcrumbs,
query: query,
space: space,
showAllRoomsInHomeSpace: showAllRoomsInHomeSpace,
strictMatches: strictMatches)
let fetchOptions = MXRoomListDataFetchOptions(filterOptions: filterOptions,
- sortOptions: sortOptions,
+ sortOptions: onlyBreadcrumbs ? noSortOptions : sortOptions,
async: true)
let fetcher = session.roomListDataManager.fetcher(withOptions: fetchOptions)
if paginate {
@@ -516,6 +613,14 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
return fetcher
}
+ private func createConversationRoomListDataFetcherForAllChats() -> MXRoomListDataFetcher {
+ let fetcher = createCommonRoomListDataFetcher(withDataTypes: [], paginate: false)
+ updateConversationFetcher(fetcher, for: .allChats)
+ fetcher.addDelegate(self)
+ fetcher.paginate()
+ return fetcher
+ }
+
private func createConversationRoomListDataFetcherForRooms() -> MXRoomListDataFetcher {
let fetcher = createCommonRoomListDataFetcher(withDataTypes: [], paginate: false)
updateConversationFetcher(fetcher, for: .rooms)
@@ -548,6 +653,8 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
lowPriorityRoomListDataFetcher = createCommonRoomListDataFetcher(withDataTypes: [.lowPriority])
serverNoticeRoomListDataFetcher = createCommonRoomListDataFetcher(withDataTypes: [.serverNotice])
suggestedRoomListDataFetcher = createCommonRoomListDataFetcher(onlySuggested: true)
+ breadcrumbsRoomListDataFetcher = createCommonRoomListDataFetcher(onlyBreadcrumbs: true)
+ allChatsRoomListDataFetcher = createConversationRoomListDataFetcherForAllChats()
fetchersCreated = true
removeSessionStateObserver()
@@ -582,7 +689,11 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
private func updateFavoritedFetcher(_ fetcher: MXRoomListDataFetcher, for mode: RecentsDataSourceMode) {
switch mode {
case .home:
- fetcher.fetchOptions.sortOptions = sortOptions
+ if fetcher.fetchOptions.filterOptions.onlyBreadcrumbs {
+ fetcher.fetchOptions.sortOptions = noSortOptions
+ } else {
+ fetcher.fetchOptions.sortOptions = sortOptions
+ }
case .favourites:
var newSortOptions = sortOptions
newSortOptions.favoriteTag = true
@@ -593,13 +704,39 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
}
private func updateConversationFetcher(_ fetcher: MXRoomListDataFetcher, for mode: RecentsDataSourceMode) {
- var notDataTypes: MXRoomSummaryDataTypes = [.hidden, .conferenceUser, .direct, .invited, .lowPriority, .serverNotice, .space]
+ var notDataTypes: MXRoomSummaryDataTypes = mode == .allChats ? [.hidden, .conferenceUser, .invited, .lowPriority, .serverNotice, .space] : [.hidden, .conferenceUser, .direct, .invited, .lowPriority, .serverNotice, .space]
+
switch mode {
case .home:
notDataTypes.insert(.favorited)
+
fetcher.fetchOptions.filterOptions.notDataTypes = notDataTypes
case .rooms:
fetcher.fetchOptions.filterOptions.notDataTypes = notDataTypes
+ case .allChats:
+ let settingsManager = AllChatsLayoutSettingsManager.shared
+ let settings = AllChatsLayoutSettingsManager.shared.allChatLayoutSettings
+ if settings.sections.contains(.favourites) && !settings.filters.contains(.favourites) {
+ notDataTypes.insert(.favorited)
+ }
+ if settings.filters.contains(.rooms) && settingsManager.activeFilters.contains(.rooms) {
+ notDataTypes.insert(.direct)
+ }
+ fetcher.fetchOptions.filterOptions.notDataTypes = notDataTypes
+
+ if settings.filters.contains(.unreads) && settingsManager.activeFilters.contains(.unreads) {
+ fetcher.fetchOptions.filterOptions.dataTypes = [.unread]
+ return
+ }
+ if settings.filters.contains(.people) && settingsManager.activeFilters.contains(.people) {
+ fetcher.fetchOptions.filterOptions.dataTypes = [.direct]
+ return
+ }
+ if settings.filters.contains(.favourites) && settingsManager.activeFilters.contains(.favourites) {
+ fetcher.fetchOptions.filterOptions.dataTypes = [.favorited]
+ return
+ }
+ fetcher.fetchOptions.filterOptions.dataTypes = []
default:
break
}
@@ -617,6 +754,12 @@ public class RecentsListService: NSObject, RecentsListServiceProtocol {
}
deinit {
+ if let observer = allChatLayoutSettingsManagerObserver {
+ NotificationCenter.default.removeObserver(observer)
+ }
+ if let observer = allChatLayoutSettingsObserver {
+ NotificationCenter.default.removeObserver(observer)
+ }
stop()
}
@@ -651,8 +794,10 @@ private struct FetcherTypes: OptionSet {
static let lowPriority = FetcherTypes(rawValue: 1 << 6)
static let serverNotice = FetcherTypes(rawValue: 1 << 7)
static let suggested = FetcherTypes(rawValue: 1 << 8)
+ static let breadcrumbs = FetcherTypes(rawValue: 1 << 9)
+ static let allChats = FetcherTypes(rawValue: 1 << 10)
static let none: FetcherTypes = []
static let all: FetcherTypes = [
- .invited, .favorited, .directHome, .directPeople, .conversationHome, .conversationRooms, .lowPriority, .serverNotice, .suggested]
+ .invited, .favorited, .directHome, .directPeople, .conversationHome, .conversationRooms, .lowPriority, .serverNotice, .suggested, .breadcrumbs, .allChats]
}
diff --git a/Riot/Modules/Common/Recents/Service/Mock/MockRecentsListService.swift b/Riot/Modules/Common/Recents/Service/Mock/MockRecentsListService.swift
index 7cb3ca4ab1..77cecac6fc 100644
--- a/Riot/Modules/Common/Recents/Service/Mock/MockRecentsListService.swift
+++ b/Riot/Modules/Common/Recents/Service/Mock/MockRecentsListService.swift
@@ -27,6 +27,8 @@ public class MockRecentsListService: NSObject, RecentsListServiceProtocol {
private var _conversationRoomListData: MXRoomListData?
private var _lowPriorityRoomListData: MXRoomListData?
private var _serverNoticeRoomListData: MXRoomListData?
+ private var _recentsRoomListData: MXRoomListData?
+ private var _allChatsRoomListData: MXRoomListData?
// swiftlint:disable weak_delegate
private let multicastDelegate: MXMulticastDelegate = MXMulticastDelegate()
@@ -72,6 +74,8 @@ public class MockRecentsListService: NSObject, RecentsListServiceProtocol {
_conversationRoomListData = MockRoomListData(withRooms: conversation)
_lowPriorityRoomListData = MockRoomListData(withRooms: lowPriority)
_serverNoticeRoomListData = MockRoomListData(withRooms: serverNotice)
+ _recentsRoomListData = MockRoomListData(withRooms: conversation)
+ _allChatsRoomListData = MockRoomListData(withRooms: conversation)
super.init()
}
@@ -149,6 +153,10 @@ public class MockRecentsListService: NSObject, RecentsListServiceProtocol {
public var suggestedRoomListData: MXRoomListData?
+ public var breadcrumbsRoomListData: MXRoomListData?
+
+ public var allChatsRoomListData: MXRoomListData?
+
public var favoritedMissedDiscussionsCount: DiscussionsCount = .zero
public var peopleMissedDiscussionsCount: DiscussionsCount = .zero
@@ -165,6 +173,8 @@ public class MockRecentsListService: NSObject, RecentsListServiceProtocol {
return peopleRoomListData?.counts.numberOfRooms ?? 0
case .rooms:
return conversationRoomListData?.counts.numberOfRooms ?? 0
+ case .allChats:
+ return allChatsRoomListData?.counts.numberOfRooms ?? 0
@unknown default:
return 0
}
@@ -198,6 +208,8 @@ public class MockRecentsListService: NSObject, RecentsListServiceProtocol {
_conversationRoomListData = nil
_lowPriorityRoomListData = nil
_serverNoticeRoomListData = nil
+ _recentsRoomListData = nil
+ _allChatsRoomListData = nil
removeAllDelegates()
}
diff --git a/Riot/Modules/Common/Recents/Service/RecentsListServiceProtocol.swift b/Riot/Modules/Common/Recents/Service/RecentsListServiceProtocol.swift
index 72ab08f08d..8eec17ed5d 100644
--- a/Riot/Modules/Common/Recents/Service/RecentsListServiceProtocol.swift
+++ b/Riot/Modules/Common/Recents/Service/RecentsListServiceProtocol.swift
@@ -53,6 +53,12 @@ public protocol RecentsListServiceProtocol {
/// Suggested rooms for current mode
var suggestedRoomListData: MXRoomListData? { get }
+ /// Breadcrumbs
+ var breadcrumbsRoomListData: MXRoomListData? { get }
+
+ /// All Chats room for current mode
+ var allChatsRoomListData: MXRoomListData? { get }
+
// MARK: Discussion counts
/// Counts for favorite screen
diff --git a/Riot/Modules/Common/Recents/Service/RecentsListServiceSection.swift b/Riot/Modules/Common/Recents/Service/RecentsListServiceSection.swift
index 99ef113532..d954439d9c 100644
--- a/Riot/Modules/Common/Recents/Service/RecentsListServiceSection.swift
+++ b/Riot/Modules/Common/Recents/Service/RecentsListServiceSection.swift
@@ -25,4 +25,6 @@ public enum RecentsListServiceSection: Int {
case lowPriority
case serverNotice
case suggested
+ case allChats
+ case breadcrumbs
}
diff --git a/Riot/Modules/Common/Recents/Views/RecentTableViewCell.m b/Riot/Modules/Common/Recents/Views/RecentTableViewCell.m
index ffb429c01e..2e3052fc06 100644
--- a/Riot/Modules/Common/Recents/Views/RecentTableViewCell.m
+++ b/Riot/Modules/Common/Recents/Views/RecentTableViewCell.m
@@ -95,7 +95,7 @@ - (void)render:(MXKCellData *)cellData
// Notify unreads and bing
if (roomCellData.hasUnread)
{
- self.missedNotifAndUnreadIndicator.hidden = NO;
+ self.missedNotifAndUnreadIndicator.hidden = BuildSettings.newAppLayoutEnabled;
if (0 < roomCellData.notificationCount)
{
@@ -113,7 +113,7 @@ - (void)render:(MXKCellData *)cellData
{
self.missedNotifAndUnreadIndicator.backgroundColor = ThemeService.shared.theme.unreadRoomIndentColor;
}
-
+
// Use bold font for the room title
self.roomTitle.font = [UIFont systemFontOfSize:17 weight:UIFontWeightBold];
}
diff --git a/Riot/Modules/Common/Recents/Views/RecentTableViewCell.xib b/Riot/Modules/Common/Recents/Views/RecentTableViewCell.xib
index f0718884a7..51c615fafd 100644
--- a/Riot/Modules/Common/Recents/Views/RecentTableViewCell.xib
+++ b/Riot/Modules/Common/Recents/Views/RecentTableViewCell.xib
@@ -26,7 +26,7 @@
-
+
@@ -35,7 +35,7 @@