diff --git a/CHANGES.md b/CHANGES.md index 27abf63509..19854177cb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +## Changes in 1.11.14 (2024-06-17) + +No significant changes. + + ## Changes in 1.11.13 (2024-06-12) Others diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 281e714ad7..e53ee78429 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.13 -CURRENT_PROJECT_VERSION = 1.11.13 +MARKETING_VERSION = 1.11.14 +CURRENT_PROJECT_VERSION = 1.11.14 diff --git a/Podfile.lock b/Podfile.lock index 673d4ecc0d..979f760d96 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -39,9 +39,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.27.8): - - MatrixSDK/Core (= 0.27.8) - - MatrixSDK/Core (0.27.8): + - MatrixSDK (0.27.9): + - MatrixSDK/Core (= 0.27.9) + - MatrixSDK/Core (0.27.9): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -49,7 +49,7 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/JingleCallStack (0.27.8): + - MatrixSDK/JingleCallStack (0.27.9): - JitsiMeetSDKLite (= 8.1.2-lite) - MatrixSDK/Core - MatrixSDKCrypto (0.4.2) @@ -187,7 +187,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 4c5a8572a481340ab233451ad36c1322d371fae5 + MatrixSDK: 246fd1d3620afcbf8cb76794e9343ebf3cbf881b MatrixSDKCrypto: 736069ee0a5ec12852ab3498bf2242acecc443fc OLMKit: da115f16582e47626616874e20f7bb92222c7a51 ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -209,4 +209,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b622ffadc1a0fe5442787bd9023ca3d110384814 -COCOAPODS: 1.15.2 +COCOAPODS: 1.14.3 diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index c965d650ce..216ab88fdb 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -1352,7 +1352,7 @@ "event_formatter_call_ringing" = "Hívás…"; "event_formatter_call_connecting" = "Kapcsolás…"; "settings_labs_enable_ringing_for_group_calls" = "Csengetés csoportos hívásokhoz"; -"room_no_privileges_to_create_group_call" = "Adminisztrátornak vagy moderátornak kell lenned a hívás indításához."; +"room_no_privileges_to_create_group_call" = "Adminisztrátornak vagy moderátornak kell lennie a hívás indításához."; "room_join_group_call" = "Csatlakozás"; // Chat @@ -2501,8 +2501,8 @@ "room_first_message_placeholder" = "Küld el az első üzenetedet…"; "authentication_qr_login_confirm_title" = "Biztonságos kapcsolat beállítva"; "room_event_encryption_info_key_authenticity_not_guaranteed" = "A titkosított üzenetek valódiságát ezen az eszközön nem lehet garantálni."; -"wysiwyg_composer_format_action_underline" = "Aláhúzott"; -"wysiwyg_composer_format_action_strikethrough" = "Áthúzott"; +"wysiwyg_composer_format_action_underline" = "Aláhúzott formázás alkalmazása"; +"wysiwyg_composer_format_action_strikethrough" = "Áthúzott formázás alkalmazása"; "wysiwyg_composer_format_action_italic" = "Dőlt"; // Formatting Actions @@ -2755,3 +2755,11 @@ "room_command_kick_user_description" = "Eltávolítja az adott azonosítójú felhasználót ebből a szobából"; "room_command_ban_user_description" = "Kitiltja az adott azonosítójú felhasználót"; "room_command_unban_user_description" = "Feloldja az adott azonosítójú felhasználó kitiltását"; +"notice_display_name_changed_to" = "%@ erre módosította a megjelenítendő nevét: %@"; +"poll_timeline_loading" = "Betöltés..."; +"manage_session_redirect" = "Át lesz irányítva a kiszolgálója hitelesítési szolgáltatójához, hogy befejezze a kijelentkezést."; +"manage_session_redirect_error" = "A funkcionalitás jelenleg nem érhető el. Lépjen kapcsolatba a Matrix-kiszolgáló rendszergazdájával."; +"settings_manage_account_title" = "Fiók"; +"settings_manage_account_action" = "Fiók kezelése"; +"settings_manage_account_description" = "A fiókja kezelése itt: %@"; +"room_command_change_room_topic_description" = "Beállítja a szoba témáját"; diff --git a/Riot/Assets/nn.lproj/InfoPlist.strings b/Riot/Assets/nn.lproj/InfoPlist.strings new file mode 100644 index 0000000000..c1f10e5b0a --- /dev/null +++ b/Riot/Assets/nn.lproj/InfoPlist.strings @@ -0,0 +1,7 @@ + + +"NSCalendarsUsageDescription" = "Sjå dei planlagde møta dine i appen."; +"NSFaceIDUsageDescription" = "Face ID vert brukt til å få tilgang til appen din."; +// Permissions usage explanations +"NSCameraUsageDescription" = "Kameraet vert brukt til videosamtalar, og til å ta og laste opp bilde og videoar."; +"NSMicrophoneUsageDescription" = "Appen treng tilgang til mikrofonen for samtalar, og for å spele inn video og lydmeldingar."; diff --git a/Riot/Assets/nn.lproj/Localizable.strings b/Riot/Assets/nn.lproj/Localizable.strings new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/Riot/Assets/nn.lproj/Localizable.strings @@ -0,0 +1 @@ + diff --git a/Riot/Assets/nn.lproj/Vector.strings b/Riot/Assets/nn.lproj/Vector.strings index 1eec1c5583..533975c2fa 100644 --- a/Riot/Assets/nn.lproj/Vector.strings +++ b/Riot/Assets/nn.lproj/Vector.strings @@ -9,3 +9,74 @@ "warning" = "Åtvaring"; // String for App Store "store_short_description" = "Sikker desentralisert chat/IP-telefoni"; +"ok" = "OK"; +"callbar_only_single_paused" = "Samtale sett på pause"; +"cancel" = "Avbryt"; +"save" = "Lagra"; +"join" = "Ver med"; +"decline" = "Avslå"; +"accept" = "Godta"; +"preview" = "Førehandsvising"; +"camera" = "Kamera"; +"voice" = "Røyst"; +"video" = "Video"; +"active_call" = "Aktiv samtale"; +"active_call_details" = "Aktiv samtale (%@)"; +"joined" = "Vart med"; +"later" = "Seinare"; +"rename" = "Endre namn"; +"collapse" = "Skjul"; +"send_to" = "Send til %@"; +"sending" = "Sender"; +"close" = "Lat att"; +"skip" = "Hopp over"; +"switch" = "Byt"; +"more" = "Meir"; +"less" = "Mindre"; +"open" = "Opne"; +"done" = "Ferdig"; + +// Call Bar +"callbar_only_single_active" = "Trykk for å gå tilbake til samtalen (%@)"; +"callbar_only_multiple_paused" = "%@ samtalar sett på pause"; +"callbar_return" = "Gå tilbake"; +"callbar_only_single_active_group" = "Trykk for å bli med i konferansesamtalen (%@)"; + +// Accessibility +"accessibility_checkbox_label" = "avkryssingsboks"; +"accessibility_button_label" = "knapp"; +"error" = "Feil"; +"invite_to" = "Inviter til %@"; + +// MARK: Onboarding +"onboarding_splash_register_button_title" = "Opprett konto"; +"accessibility_selected" = "vald"; +"private" = "Privat"; +"public" = "Offentleg"; +"stop" = "Stopp"; +"new_word" = "Ny"; +"existing" = "Eksisterande"; +"add" = "Legg til"; +"suggest" = "Føreslå"; +"edit" = "Rediger"; + +// Activities +"loading" = "Lastar"; +"saving" = "Lagrar"; +"callbar_active_and_single_paused" = "1 aktiv samtale (%@) · 1 samtale sett i pause"; +"callbar_active_and_multiple_paused" = "1 aktiv samtale (%@) · %@ samtalar sett på pause"; +"confirm" = "Stadfest"; +"onboarding_splash_login_button_title" = "Eg har allereie ein konto"; +"authentication_forgot_password_text_field_placeholder" = "E-postadresse"; +"next" = "Neste"; +"back" = "Tilbake"; +"continue" = "Fortset"; +"create" = "Lag"; +"remove" = "Fjern"; +"invite" = "Inviter"; +"retry" = "Prøv på nytt"; +"on" = "På"; +"off" = "Av"; +"authentication_login_username" = "Brukarnamn / e-postadresse / telefonnummer"; +"onboarding_display_name_placeholder" = "Visingsnamn"; +"authentication_login_with_qr" = "Logg inn med QR-kode"; diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings index 991716cd9f..edd2cf70e6 100644 --- a/Riot/Assets/pt_BR.lproj/Vector.strings +++ b/Riot/Assets/pt_BR.lproj/Vector.strings @@ -1226,7 +1226,7 @@ "secrets_recovery_reset_action_part_2" = "Resettar tudo"; "secrets_setup_recovery_passphrase_summary_information" = "Lembre-se de sua Frase de Segurança. Ela pode ser usada para destrancar suas mensagens & dados encriptados."; "secrets_setup_recovery_passphrase_summary_title" = "Salvar sua Frase de Segurança"; -"home_empty_view_information" = "O app de chat seguro tudo-em-um para equipes, amigas(os) e organizações. Toque no botão + abaixo para adicionar pessoas e salas."; +"home_empty_view_information" = "O app de chat seguro tudo-em-um para equipes, amigos e organizações. Toque no botão + abaixo para adicionar pessoas e salas."; // MARK: - Home @@ -1244,7 +1244,7 @@ // MARK: - Invite friends -"invite_friends_action" = "Convidar amigas(os) para %@"; +"invite_friends_action" = "Convidar amigos para %@"; "pin_protection_settings_change_pin" = "Mudar PIN"; "pin_protection_confirm_pin_to_change" = "Confirme PIN para mudar PIN"; "bug_report_background_mode" = "Continuar em background"; @@ -1348,7 +1348,7 @@ "side_menu_action_feedback" = "Feedback"; "side_menu_action_help" = "Ajuda"; "side_menu_action_settings" = "Ajustes"; -"side_menu_action_invite_friends" = "Convidar amigas(os)"; +"side_menu_action_invite_friends" = "Convidar amigos"; // Mark: - Side menu @@ -1632,7 +1632,7 @@ "onboarding_use_case_not_sure_yet" = "Não tem certeza ainda? %@"; "onboarding_use_case_community_messaging" = "Comunidades"; "onboarding_use_case_work_messaging" = "Times"; -"onboarding_use_case_personal_messaging" = "Amigas(os) e família"; +"onboarding_use_case_personal_messaging" = "Amigos e família"; "onboarding_use_case_message" = "Nós vamos ajudá-la(o) a ficar conectada(o)"; "onboarding_use_case_title" = "Com quem você vai fazer chat mais?"; @@ -2654,3 +2654,20 @@ "user_other_session_security_recommendation_title" = "Outras sessões"; "room_creation_only_one_email_invite" = "Você só pode convidar um e-mail de cada vez"; "accessibility_selected" = "selecionado"; +"room_creation_user_not_found_prompt_title" = "Confirmação"; +"room_creation_user_not_found_prompt_message" = "Não foi possível encontrar perfis para este ID do Matrix. Quer começar uma conversa mesmo assim?"; +"room_creation_user_not_found_prompt_invite_action" = "Começar conversa mesmo assim"; +"room_participants_invite_anyway" = "Convidar mesmo assim"; +"room_command_part_room_description" = "Sair da sala"; +"room_command_kick_user_description" = "Remove o usuário com o ID fornecido desta sala"; +"room_command_unban_user_description" = "Desbane o usuário com o ID fornecido"; +"room_command_set_user_power_level_description" = "Define o nível de poder de um usuário"; +"room_participants_invite_unknown_participant_prompt_to_msg" = "Não foi possível encontrar perfis para este ID do Matrix. Tem certeza que deseja convidar %@ para %@?"; +"room_command_ban_user_description" = "Bane o usuário com o ID fornecido"; + +// Room commands descriptions +"room_command_change_display_name_description" = "Altera o seu nome de exibição"; +"room_command_emote_description" = "Exibe ação"; +"room_command_join_room_description" = "Entra na sala com o endereço fornecido"; +"room_command_invite_user_description" = "Convida o usuário com o ID fornecido para a sala atual"; +"authentication_qr_login_failure_device_not_supported" = "Vincular com este dispositivo não é suportado."; diff --git a/Riot/Categories/MXRoomSummary.swift b/Riot/Categories/MXRoomSummary.swift new file mode 100644 index 0000000000..b48f1a70f4 --- /dev/null +++ b/Riot/Categories/MXRoomSummary.swift @@ -0,0 +1,58 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +extension Notification.Name { + static let roomSummaryDidRemoveExpiredDataFromStore = Notification.Name(MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore) +} + +extension MXRoomSummary { + @objc static let roomSummaryDidRemoveExpiredDataFromStore = "roomSummaryDidRemoveExpiredDataFromStore" + @objc static let roomRetentionStateEventType = "m.room.retention" + + private enum Constants { + static let roomRetentionInDaysKey = "roomRetentionInDays" + } + /// Get the room messages retention period in days + func roomRetentionPeriodInDays() -> uint { + if let period = self.others[Constants.roomRetentionInDaysKey] as? uint { + return period + } else { + return 365 + } + } + + /// Get the timestamp below which the received messages must be removed from the store, and the display + @objc func minimumTimestamp() -> UInt64 { + let periodInMs = Tools.durationInMs(fromDays: self.roomRetentionPeriodInDays()) + let currentTs = (UInt64)(Date().timeIntervalSince1970 * 1000) + return (currentTs - periodInMs) + } + + /// Remove the expired messages from the store. + /// If some data are removed, this operation posts the notification: roomSummaryDidRemoveExpiredDataFromStore. + /// This operation does not commit the potential change. We let the caller trigger the commit when this is the more suitable. + /// + /// Provide a boolean telling whether some data have been removed. + @objc func removeExpiredRoomContentsFromStore() -> Bool { + let ret = self.mxSession.store.removeAllMessagesSent(before: self.minimumTimestamp(), inRoom: roomId) + if ret { + NotificationCenter.default.post(name: .roomSummaryDidRemoveExpiredDataFromStore, object: self) + } + return ret + } +} diff --git a/Riot/Categories/MXSession.swift b/Riot/Categories/MXSession.swift index 10df98141f..4d7256b62f 100644 --- a/Riot/Categories/MXSession.swift +++ b/Riot/Categories/MXSession.swift @@ -25,4 +25,16 @@ extension MXSession { matrixItemId: userId, displayName: user?.displayname) } + + /// Clean the storage of a session by removing the expired contents. + @objc func removeExpiredMessages() { + var hasStoreChanged = false + for room in self.rooms { + hasStoreChanged = hasStoreChanged || room.summary.removeExpiredRoomContentsFromStore() + } + + if hasStoreChanged { + self.store.commit?() + } + } } diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 79d263cef1..c5030714dd 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1826,6 +1826,9 @@ - (void)initMatrixSessions [self registerNewRequestNotificationForSession:mxSession]; [self.pushNotificationService checkPushKitPushersInSession:mxSession]; + + // Clean the storage by removing expired data + [mxSession removeExpiredMessages]; } else if (mxSession.state == MXSessionStateRunning) { diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 16e05c4231..55ef184f13 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -33,6 +33,9 @@ @interface RoomDataSource() )delegate +{ + [self unregisterRoomSummaryDidRemoveExpiredDataFromStoreNotifications]; + [self removeRoomRetentionEventListener]; + + if (delegate && self.isLive) + { + if (self.room) + { + // Remove the potential expired messages from the store + if ([self.room.summary removeExpiredRoomContentsFromStore]) + { + [self.mxSession.store commit]; + } + [self addRoomRetentionEventListener]; + } + + // Observe room history flush (expired content data) + [self registerRoomSummaryDidRemoveExpiredDataFromStoreNotifications]; + [self roomSummaryDidRemoveExpiredDataFromStore]; + } + + [super setDelegate:delegate]; +} + - (void)destroy { if (kThemeServiceDidChangeThemeNotificationObserver) @@ -197,6 +225,9 @@ - (void)destroy [self.mxSession.aggregations.beaconAggregations removeListener:self.beaconInfoSummaryDeletionListener]; } + [self unregisterRoomSummaryDidRemoveExpiredDataFromStoreNotifications]; + [self removeRoomRetentionEventListener]; + [super destroy]; } @@ -1242,4 +1273,79 @@ - (void)updateCurrentUserLocationSharingStatus } } +#pragma mark - roomSummaryDidRemoveExpiredDataFromStore notifications + +- (void)registerRoomSummaryDidRemoveExpiredDataFromStoreNotifications +{ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(roomSummaryDidRemoveExpiredDataFromStore:) name:MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore object:nil]; +} + +- (void)unregisterRoomSummaryDidRemoveExpiredDataFromStoreNotifications +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore object:nil]; +} + +- (void)roomSummaryDidRemoveExpiredDataFromStore:(NSNotification*)notification +{ + MXRoomSummary *roomSummary = notification.object; + if (self.mxSession == roomSummary.mxSession && [self.roomId isEqualToString:roomSummary.roomId]) + { + [self roomSummaryDidRemoveExpiredDataFromStore]; + } +} + +- (void)roomSummaryDidRemoveExpiredDataFromStore +{ + // Check whether the first cell data refers to an expired event (this may be a state event + MXEvent *firstMessageEvent; + for (id cellData in bubbles) + { + for (MXEvent *event in cellData.events) + { + if (!event.isState) { + firstMessageEvent = event; + break; + } + } + + if (firstMessageEvent) + { + break; + } + } + + if (firstMessageEvent && firstMessageEvent.originServerTs < self.room.summary.minimumTimestamp) + { + [self reload]; + } +} + +#pragma mark - room retention event listener + +- (void)addRoomRetentionEventListener +{ + // Register a listener to handle the room retention in live timelines + retentionListener = [self.timeline listenToEventsOfTypes:@[MXRoomSummary.roomRetentionStateEventType] onEvent:^(MXEvent *redactionEvent, MXTimelineDirection direction, MXRoomState *roomState) { + + // Consider only live events + if (direction == MXTimelineDirectionForwards) + { + // Remove the potential expired messages from the store + if ([self.room.summary removeExpiredRoomContentsFromStore]) + { + [self.mxSession.store commit]; + } + } + }]; +} + +- (void)removeRoomRetentionEventListener +{ + if (retentionListener) + { + [self.timeline removeListener:retentionListener]; + retentionListener = nil; + } +} + @end diff --git a/Riot/Utils/Tools.h b/Riot/Utils/Tools.h index 57eacbcdb5..8d54e06b1d 100644 --- a/Riot/Utils/Tools.h +++ b/Riot/Utils/Tools.h @@ -48,4 +48,17 @@ */ + (NSURL*)fixURLWithSeveralHashKeys:(NSURL*)url; +#pragma mark - Time utilities + +/** + * Convert a number of days to a duration in ms. + */ ++ (uint64_t)durationInMsFromDays:(uint)days; + +/** + * Convert a duration in ms to a number of days. + */ ++ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration; + + @end diff --git a/Riot/Utils/Tools.m b/Riot/Utils/Tools.m index 128fe3694a..5866273ac8 100644 --- a/Riot/Utils/Tools.m +++ b/Riot/Utils/Tools.m @@ -117,4 +117,16 @@ + (NSURL *)fixURLWithSeveralHashKeys:(NSURL *)url return fixedURL; } +#pragma mark - Time utilities + ++ (uint64_t)durationInMsFromDays:(uint)days +{ + return days * (uint64_t)(86400000); +} + ++ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration +{ + return (uint)(duration / 86400000); +} + @end diff --git a/Tools/Release/buildRelease.sh b/Tools/Release/buildRelease.sh index 583b00b62c..0f925efc1c 100755 --- a/Tools/Release/buildRelease.sh +++ b/Tools/Release/buildRelease.sh @@ -42,7 +42,7 @@ cp -R ../../../.. /tmp/$REPO_NAME mv /tmp/$REPO_NAME . else echo "Git clone $REPO_URL with branch/tag $TAG..." -git clone $REPO_URL --depth=1 --branch $TAG +git clone --recursive $REPO_URL --depth=1 --branch $TAG fi cd $REPO_NAME @@ -55,11 +55,6 @@ bundle update # Update fastlane plugins bundle exec fastlane update_plugins -# Use appropriated dependencies according to the current branch -if [ "$LOCAL_SOURCE" != true ]; then -bundle exec fastlane point_dependencies_to_same_feature -fi - # Build bundle exec fastlane app_store build_number:$BUILD_NUMBER git_tag:$TAG diff --git a/matrix-ios-sdk b/matrix-ios-sdk index 3052a396b8..fcfbb67182 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit 3052a396b88095cbcfe1b4f488127f69e3280cda +Subproject commit fcfbb6718224e9819105b93fa9e86a9db1cf04a6