From 3e985b7666a7f59597c968eed8775949c548ec8a Mon Sep 17 00:00:00 2001 From: Osoitz Date: Sat, 2 Jun 2018 12:33:41 +0000 Subject: [PATCH 01/54] Translated using Weblate (Basque) Currently translated at 100.0% (501 of 501 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/eu/ --- Riot/Assets/eu.lproj/Vector.strings | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Riot/Assets/eu.lproj/Vector.strings b/Riot/Assets/eu.lproj/Vector.strings index 49dc621a3..a2999c449 100644 --- a/Riot/Assets/eu.lproj/Vector.strings +++ b/Riot/Assets/eu.lproj/Vector.strings @@ -522,3 +522,21 @@ // GDPR "gdpr_consent_not_given_alert_message" = "%@ hasiera-zerbitzaria erabiltzen jarraitzeko erabilera baldintzak irakurri eta onartu behar dituzu."; "gdpr_consent_not_given_alert_review_now_action" = "Irakurri orain"; +"room_action_send_photo_or_video" = "Bidali argazki edo bideoa"; +"room_action_send_sticker" = "Bidali eranskailua"; +"settings_deactivate_account" = "DESAKTIBATU KONTUA"; +"settings_deactivate_my_account" = "Desaktibatu nire kontua"; +"widget_sticker_picker_no_stickerpacks_alert" = "Ez duzu orain eranskailu multzo aktiborik."; +"widget_sticker_picker_no_stickerpacks_alert_add_now" = "Baten bat gehitu orain?"; +"deactivate_account_title" = "Desaktibatu kontua"; +"deactivate_account_informations_part1" = "Honek kontua behin betirako erabilgaitza bihurtuko du. Ezin izango duzu saioa hasi, eta ezin izango du beste inork ID hori erabili. Kontua dagoen gela guztietatik aterako da, eta kontuaren xehetasunak identitate-zerbitzaritik ezabatuko dira. "; +"deactivate_account_informations_part2_emphasize" = "Ekintza hau ezin da desegin."; +"deactivate_account_informations_part3" = "\n\nZure kontua desaktibatzen "; +"deactivate_account_informations_part4_emphasize" = "ez du lehenetsita guk zuk bidalitako mezuak ahaztea eragingo "; +"deactivate_account_informations_part5" = "Guk zure mezuak ahaztea nahi baduzu markatu beheko kutxa.\n\nMatrix-eko mezuen ikusgaitasuna e-mail sistemaren antekoa da. Guk zure mezuak ahaztean ez dizkiogu erabiltzaile berriei edo izena eman ez dutenei erakutsiko, baina jada zure mezuak jaso dituzten erregistratutako erabiltzaileen bere kopia izaten jarraituko dute."; +"deactivate_account_forget_messages_information_part1" = "Ahaztu bidali ditudan mezu guztiak kontua desaktibatzean ("; +"deactivate_account_forget_messages_information_part2_emphasize" = "Abisua"; +"deactivate_account_forget_messages_information_part3" = ": Honekin etorkizuneko erabiltzaileek elkarrizketaren bertsio ez oso bat ikusiko dute)"; +"deactivate_account_validate_action" = "Desaktibatu kontua"; +"deactivate_account_password_alert_title" = "Desaktibatu kontua"; +"deactivate_account_password_alert_message" = "Jarraitzeko sartu zure pasahitza"; From 5480cc77effefba6274d91b1f157ebed1297d122 Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 4 Jun 2018 14:47:36 +0200 Subject: [PATCH 02/54] Pod: Update GBDeviceInfo --- Podfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile b/Podfile index 8901c7ffc..7d537bedb 100644 --- a/Podfile +++ b/Podfile @@ -58,7 +58,7 @@ end abstract_target 'RiotPods' do - pod 'GBDeviceInfo', '~> 5.1.0' + pod 'GBDeviceInfo', '~> 5.2.0' # Piwik for analytics # While https://github.com/matomo-org/matomo-sdk-ios/pull/223 is not released, use the PR branch From cddf2c77d1c4cf1a6227ec805e615cca25092615 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Fri, 8 Jun 2018 11:31:39 +0200 Subject: [PATCH 03/54] Fix a memory leak with direct room border color and add constants for border layer customization. --- Riot/Views/RoomList/RecentTableViewCell.m | 13 +++++++++++-- Riot/Views/RoomList/RoomCollectionViewCell.m | 13 +++++++++++-- Riot/Views/RoomList/RoomTableViewCell.m | 13 +++++++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Riot/Views/RoomList/RecentTableViewCell.m b/Riot/Views/RoomList/RecentTableViewCell.m index b0bf69a75..48c15da08 100644 --- a/Riot/Views/RoomList/RecentTableViewCell.m +++ b/Riot/Views/RoomList/RecentTableViewCell.m @@ -25,6 +25,11 @@ #import "MXRoomSummary+Riot.h" +#pragma mark - Defines & Constants + +static const CGFloat kDirectRoomBorderColorAlpha = 0.75; +static const CGFloat kDirectRoomBorderWidth = 3.0; + @implementation RecentTableViewCell #pragma mark - Class methods @@ -48,10 +53,14 @@ self.missedNotifAndUnreadBadgeLabel.textColor = kRiotPrimaryBgColor; // Prepare direct room border + CGColorRef directRoomBorderColor = CGColorCreateCopyWithAlpha(kRiotColorGreen.CGColor, kDirectRoomBorderColorAlpha); + [self.directRoomBorderView.layer setCornerRadius:self.directRoomBorderView.frame.size.width / 2]; self.directRoomBorderView.clipsToBounds = YES; - self.directRoomBorderView.layer.borderColor = CGColorCreateCopyWithAlpha(kRiotColorGreen.CGColor, 0.75); - self.directRoomBorderView.layer.borderWidth = 3; + self.directRoomBorderView.layer.borderColor = directRoomBorderColor; + self.directRoomBorderView.layer.borderWidth = kDirectRoomBorderWidth; + + CFRelease(directRoomBorderColor); self.roomAvatar.defaultBackgroundColor = [UIColor clearColor]; } diff --git a/Riot/Views/RoomList/RoomCollectionViewCell.m b/Riot/Views/RoomList/RoomCollectionViewCell.m index e5492ac38..d1844a06b 100644 --- a/Riot/Views/RoomList/RoomCollectionViewCell.m +++ b/Riot/Views/RoomList/RoomCollectionViewCell.m @@ -24,6 +24,11 @@ #import "MXTools.h" +#pragma mark - Defines & Constants + +static const CGFloat kDirectRoomBorderColorAlpha = 0.75; +static const CGFloat kDirectRoomBorderWidth = 3.0; + @implementation RoomCollectionViewCell #pragma mark - Class methods @@ -66,10 +71,14 @@ self.missedNotifAndUnreadBadgeLabel.textColor = kRiotPrimaryBgColor; // Prepare direct room border + CGColorRef directRoomBorderColor = CGColorCreateCopyWithAlpha(kRiotColorGreen.CGColor, kDirectRoomBorderColorAlpha); + [self.directRoomBorderView.layer setCornerRadius:self.directRoomBorderView.frame.size.width / 2]; self.directRoomBorderView.clipsToBounds = YES; - self.directRoomBorderView.layer.borderColor = CGColorCreateCopyWithAlpha(kRiotColorGreen.CGColor, 0.75); - self.directRoomBorderView.layer.borderWidth = 3; + self.directRoomBorderView.layer.borderColor = directRoomBorderColor; + self.directRoomBorderView.layer.borderWidth = kDirectRoomBorderWidth; + + CFRelease(directRoomBorderColor); self.editionArrowView.backgroundColor = kRiotSecondaryBgColor; diff --git a/Riot/Views/RoomList/RoomTableViewCell.m b/Riot/Views/RoomList/RoomTableViewCell.m index 4f33d2821..b4d53ca5b 100644 --- a/Riot/Views/RoomList/RoomTableViewCell.m +++ b/Riot/Views/RoomList/RoomTableViewCell.m @@ -20,6 +20,11 @@ #import "RiotDesignValues.h" #import "MXRoomSummary+Riot.h" +#pragma mark - Defines & Constants + +static const CGFloat kDirectRoomBorderColorAlpha = 0.75; +static const CGFloat kDirectRoomBorderWidth = 3.0; + @implementation RoomTableViewCell #pragma mark - Class methods @@ -31,10 +36,14 @@ self.titleLabel.textColor = kRiotPrimaryTextColor; // Prepare direct room border + CGColorRef directRoomBorderColor = CGColorCreateCopyWithAlpha(kRiotColorGreen.CGColor, kDirectRoomBorderColorAlpha); + [self.directRoomBorderView.layer setCornerRadius:self.directRoomBorderView.frame.size.width / 2]; self.directRoomBorderView.clipsToBounds = YES; - self.directRoomBorderView.layer.borderColor = CGColorCreateCopyWithAlpha(kRiotColorGreen.CGColor, 0.75); - self.directRoomBorderView.layer.borderWidth = 3; + self.directRoomBorderView.layer.borderColor = directRoomBorderColor; + self.directRoomBorderView.layer.borderWidth = kDirectRoomBorderWidth; + + CFRelease(directRoomBorderColor); self.avatarImageView.defaultBackgroundColor = [UIColor clearColor]; } From 8cdb4d849368db7da5f436792343d2b5620f35c2 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 8 Jun 2018 17:21:52 +0200 Subject: [PATCH 04/54] RoomVC: Add a re-request keys button on message unable to decrypt #1879 --- Riot/Assets/en.lproj/Vector.strings | 7 ++++ Riot/Utils/EventFormatter.h | 10 ++++++ Riot/Utils/EventFormatter.m | 42 +++++++++++++++++++++- Riot/ViewController/RoomViewController.m | 46 ++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 05f7ed41f..6cd859aed 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -518,6 +518,8 @@ "event_formatter_widget_removed" = "%@ widget removed by %@"; "event_formatter_jitsi_widget_added" = "VoIP conference added by %@"; "event_formatter_jitsi_widget_removed" = "VoIP conference removed by %@"; +"event_formatter_rerequest_keys_part1_link" = "Re-request encryption keys"; +"event_formatter_rerequest_keys_part2" = " from your other devices."; // Others "or" = "or"; @@ -622,3 +624,8 @@ "deactivate_account_password_alert_title" = "Deactivate Account"; "deactivate_account_password_alert_message" = "To continue, please enter your password"; + +// Re-request confirmation dialog +"rerequest_keys_alert_title" = "Re-request encryption keys"; +"rerequest_keys_alert_message" = "Your key share request has been sent - please check your other devices for key share requests.\n\nKey share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, you can request the keys for this session again."; +"rerequest_keys_alert_button" = "Re-request"; diff --git a/Riot/Utils/EventFormatter.h b/Riot/Utils/EventFormatter.h index ba5d6a60c..d55c03257 100644 --- a/Riot/Utils/EventFormatter.h +++ b/Riot/Utils/EventFormatter.h @@ -16,6 +16,16 @@ #import +/** + Link string used in attributed strings to mark a keys re-request action. + */ +FOUNDATION_EXPORT NSString *const kEventFormatterOnReRequestKeysLinkAction; + +/** + Parameters separator in the link string. + */ +FOUNDATION_EXPORT NSString *const kEventFormatterOnReRequestKeysLinkActionSeparator; + /** `EventFormatter` class inherits from `MXKEventFormatter` to define Vector formatting */ diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index ef1732e49..09f92f344 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -21,6 +21,13 @@ #import "WidgetManager.h" +#import "MXDecryptionResult.h" + +#pragma mark - Constants definitions + +NSString *const kEventFormatterOnReRequestKeysLinkAction = @"kEventFormatterOnReRequestKeysLinkAction"; +NSString *const kEventFormatterOnReRequestKeysLinkActionSeparator = @"/"; + @interface EventFormatter () { /** @@ -107,7 +114,40 @@ } } - return [super attributedStringFromEvent:event withRoomState:roomState error:error]; + NSAttributedString *attributedString = [super attributedStringFromEvent:event withRoomState:roomState error:error]; + + if (event.sentState == MXEventSentStateSent + && [event.decryptionError.domain isEqualToString:MXDecryptingErrorDomain] + && event.decryptionError.code == MXDecryptingErrorUnknownInboundSessionIdCode) + { + // Append to the displayed error an attibuted string with a tappable link + // so that the user can try to fix the UTC + NSMutableAttributedString *attributedStringWithRerequestMessage = [attributedString mutableCopy]; + [attributedStringWithRerequestMessage appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]]; + + NSString *linkActionString = [NSString stringWithFormat:@"%@%@%@", kEventFormatterOnReRequestKeysLinkAction, + kEventFormatterOnReRequestKeysLinkActionSeparator, + event.eventId]; + + [attributedStringWithRerequestMessage appendAttributedString: + [[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"event_formatter_rerequest_keys_part1_link", @"Vector", nil) + attributes:@{ + NSLinkAttributeName: linkActionString, + NSForegroundColorAttributeName: self.sendingTextColor, + NSFontAttributeName: self.encryptedMessagesTextFont + }]]; + + [attributedStringWithRerequestMessage appendAttributedString: + [[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"event_formatter_rerequest_keys_part2", @"Vector", nil) + attributes:@{ + NSForegroundColorAttributeName: self.sendingTextColor, + NSFontAttributeName: self.encryptedMessagesTextFont + }]]; + + attributedString = attributedStringWithRerequestMessage; + } + + return attributedString; } - (NSAttributedString*)attributedStringFromEvents:(NSArray*)events withRoomState:(MXRoomState*)roomState error:(MXKEventFormatterError*)error diff --git a/Riot/ViewController/RoomViewController.m b/Riot/ViewController/RoomViewController.m index 093f89e17..0e45eaf38 100644 --- a/Riot/ViewController/RoomViewController.m +++ b/Riot/ViewController/RoomViewController.m @@ -117,6 +117,8 @@ #import "WidgetPickerViewController.h" #import "StickerPickerViewController.h" +#import "EventFormatter.h" + @interface RoomViewController () { // The expanded header @@ -2680,6 +2682,20 @@ NSString *fragment = [NSString stringWithFormat:@"/group/%@", [absoluteURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; [[AppDelegate theDelegate] handleUniversalLinkFragment:fragment]; } + else if ([absoluteURLString hasPrefix:kEventFormatterOnReRequestKeysLinkAction]) + { + NSArray *arguments = [absoluteURLString componentsSeparatedByString:kEventFormatterOnReRequestKeysLinkActionSeparator]; + if (arguments.count > 1) + { + NSString *eventId = arguments[1]; + MXEvent *event = [self.roomDataSource eventWithEventId:eventId]; + + if (event) + { + [self showRerequestConfirmationAlert:event]; + } + } + } } return shouldDoAction; @@ -4582,5 +4598,35 @@ [self presentViewController:currentAlert animated:YES completion:nil]; } +#pragma mark - Re-request encryption keys + +- (void)showRerequestConfirmationAlert:(MXEvent*)event +{ + currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"rerequest_keys_alert_title", @"Vector", nil) + message:NSLocalizedStringFromTable(@"rerequest_keys_alert_message", @"Vector", nil) + preferredStyle:UIAlertControllerStyleAlert]; + + MXWeakify(self); + [currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + }]]; + + [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"rerequest_keys_alert_button", @"Vector", nil) + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + + [self.mainSession.crypto reRequestRoomKeyForEvent:event]; + }]]; + + [self presentViewController:currentAlert animated:YES completion:nil]; +} + @end From 96cc8df85603010d7f7f82614eea469c97d22710 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 8 Jun 2018 17:23:32 +0200 Subject: [PATCH 05/54] RoomVC: Add a re-request keys button on message unable to decrypt #1879 --- CHANGES.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 3be965fab..fcffdee2c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,12 @@ +Changes in 0.6.18 () +=============================================== + +Improvements: + * Upgrade MatrixKit version (). + * RoomVC: Add a re-request keys button on message unable to decrypt (#1879). + +Bug fix: + Changes in 0.6.17 (2018-06-01) =============================================== From 1f45b233d76ea8fe0bf93e38092a8bd8a0acd501 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 12 Jun 2018 16:28:26 +0200 Subject: [PATCH 06/54] RoomVC: Add a re-request keys button on message unable to decrypt The flow has changed a bit. #1879 --- Riot/Assets/en.lproj/Vector.strings | 5 +-- Riot/ViewController/RoomViewController.m | 50 +++++++++++++++++------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 6cd859aed..dbf93d256 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -626,6 +626,5 @@ "deactivate_account_password_alert_message" = "To continue, please enter your password"; // Re-request confirmation dialog -"rerequest_keys_alert_title" = "Re-request encryption keys"; -"rerequest_keys_alert_message" = "Your key share request has been sent - please check your other devices for key share requests.\n\nKey share requests are sent to your other devices automatically. If you rejected or dismissed the key share request on your other devices, you can request the keys for this session again."; -"rerequest_keys_alert_button" = "Re-request"; +"rerequest_keys_alert_title" = "Request Sent"; +"rerequest_keys_alert_message" = "Please check your other devices for key share requests."; diff --git a/Riot/ViewController/RoomViewController.m b/Riot/ViewController/RoomViewController.m index 0e45eaf38..7d6630516 100644 --- a/Riot/ViewController/RoomViewController.m +++ b/Riot/ViewController/RoomViewController.m @@ -2692,7 +2692,7 @@ if (event) { - [self showRerequestConfirmationAlert:event]; + [self reRequestKeysAndShowExplanationAlert:event]; } } } @@ -4600,31 +4600,51 @@ #pragma mark - Re-request encryption keys -- (void)showRerequestConfirmationAlert:(MXEvent*)event +- (void)reRequestKeysAndShowExplanationAlert:(MXEvent*)event { - currentAlert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"rerequest_keys_alert_title", @"Vector", nil) + MXWeakify(self); + __block UIAlertController *alert; + + // Make the re-request + [self.mainSession.crypto reRequestRoomKeyForEvent:event]; + + // Observe kMXEventDidDecryptNotification to remove automatically the dialog + // if the user has shared the keys from another device + id didDecryptObserver; + didDecryptObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXEventDidDecryptNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + + MXEvent *decryptedEvent = notif.object; + + if ([decryptedEvent.eventId isEqualToString:event.eventId]) + { + [[NSNotificationCenter defaultCenter] removeObserver:didDecryptObserver]; + + MXStrongifyAndReturnIfNil(self); + if (self->currentAlert == alert) + { + [self->currentAlert dismissViewControllerAnimated:YES completion:nil]; + self->currentAlert = nil; + } + } + }]; + + // Show the explanation dialog + alert = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"rerequest_keys_alert_title", @"Vector", nil) message:NSLocalizedStringFromTable(@"rerequest_keys_alert_message", @"Vector", nil) preferredStyle:UIAlertControllerStyleAlert]; + currentAlert = alert; - MXWeakify(self); - [currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] + + [alert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"ok"] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [[NSNotificationCenter defaultCenter] removeObserver:didDecryptObserver]; + MXStrongifyAndReturnIfNil(self); self->currentAlert = nil; }]]; - [currentAlert addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"rerequest_keys_alert_button", @"Vector", nil) - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) - { - MXStrongifyAndReturnIfNil(self); - self->currentAlert = nil; - - [self.mainSession.crypto reRequestRoomKeyForEvent:event]; - }]]; - [self presentViewController:currentAlert animated:YES completion:nil]; } From bfdc4e898f1b272d87d73ff57a4cc324f7a31491 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 12 Jun 2018 16:35:12 +0200 Subject: [PATCH 07/54] RoomVC: Add a re-request keys button on message unable to decrypt Update string --- Riot/Assets/en.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index dbf93d256..801e1e6d7 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -627,4 +627,4 @@ // Re-request confirmation dialog "rerequest_keys_alert_title" = "Request Sent"; -"rerequest_keys_alert_message" = "Please check your other devices for key share requests."; +"rerequest_keys_alert_message" = "Please check your other devices for key share requests"; From 2115970a490d4f34db4f7ef9c4e318a51555a55a Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 12 Jun 2018 18:21:04 +0200 Subject: [PATCH 08/54] RoomVC: Add a re-request keys button on message unable to decrypt Take Steve's remark into account --- Riot/ViewController/RoomViewController.m | 28 +++++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Riot/ViewController/RoomViewController.m b/Riot/ViewController/RoomViewController.m index 7d6630516..325e63ff1 100644 --- a/Riot/ViewController/RoomViewController.m +++ b/Riot/ViewController/RoomViewController.m @@ -183,6 +183,9 @@ // Observer kMXRoomSummaryDidChangeNotification to keep updated the missed discussion count id mxRoomSummaryDidChangeObserver; + + // Observer for removing the re-request explanation/waiting dialog + id mxEventDidDecryptNotificationObserver; // The table view cell in which the read marker is displayed (nil by default). MXKRoomBubbleTableViewCell *readMarkerTableViewCell; @@ -594,6 +597,12 @@ [[NSNotificationCenter defaultCenter] removeObserver:mxRoomSummaryDidChangeObserver]; mxRoomSummaryDidChangeObserver = nil; } + + if (mxEventDidDecryptNotificationObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:mxEventDidDecryptNotificationObserver]; + mxEventDidDecryptNotificationObserver = nil; + } } - (void)viewDidLayoutSubviews @@ -1105,6 +1114,11 @@ [[NSNotificationCenter defaultCenter] removeObserver:mxRoomSummaryDidChangeObserver]; mxRoomSummaryDidChangeObserver = nil; } + if (mxEventDidDecryptNotificationObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:mxEventDidDecryptNotificationObserver]; + mxEventDidDecryptNotificationObserver = nil; + } [self removeCallNotificationsListeners]; [self removeWidgetNotificationsListeners]; @@ -4610,16 +4624,16 @@ // Observe kMXEventDidDecryptNotification to remove automatically the dialog // if the user has shared the keys from another device - id didDecryptObserver; - didDecryptObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXEventDidDecryptNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + mxEventDidDecryptNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXEventDidDecryptNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + MXStrongifyAndReturnIfNil(self); MXEvent *decryptedEvent = notif.object; if ([decryptedEvent.eventId isEqualToString:event.eventId]) { - [[NSNotificationCenter defaultCenter] removeObserver:didDecryptObserver]; + [[NSNotificationCenter defaultCenter] removeObserver:self->mxEventDidDecryptNotificationObserver]; + self->mxEventDidDecryptNotificationObserver = nil; - MXStrongifyAndReturnIfNil(self); if (self->currentAlert == alert) { [self->currentAlert dismissViewControllerAnimated:YES completion:nil]; @@ -4639,9 +4653,11 @@ style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - [[NSNotificationCenter defaultCenter] removeObserver:didDecryptObserver]; - MXStrongifyAndReturnIfNil(self); + + [[NSNotificationCenter defaultCenter] removeObserver:self->mxEventDidDecryptNotificationObserver]; + self->mxEventDidDecryptNotificationObserver = nil; + self->currentAlert = nil; }]]; From 345523862f82b69a634eec36a327785a90ff06f9 Mon Sep 17 00:00:00 2001 From: manuroe Date: Thu, 14 Jun 2018 10:21:45 +0200 Subject: [PATCH 09/54] RoomVC: Update re-request dialog message --- Riot/Assets/en.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 801e1e6d7..2920c6ec5 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -627,4 +627,4 @@ // Re-request confirmation dialog "rerequest_keys_alert_title" = "Request Sent"; -"rerequest_keys_alert_message" = "Please check your other devices for key share requests"; +"rerequest_keys_alert_message" = "Please launch Riot on another device that can decrypt the message so it can send the keys to this device."; From ca13349243e96f60e74130dd75c0bbe508fb1c75 Mon Sep 17 00:00:00 2001 From: Silke Date: Mon, 11 Jun 2018 20:26:26 +0000 Subject: [PATCH 10/54] Translated using Weblate (Dutch) Currently translated at 96.4% (483 of 501 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/nl/ --- Riot/Assets/nl.lproj/Vector.strings | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Riot/Assets/nl.lproj/Vector.strings b/Riot/Assets/nl.lproj/Vector.strings index af7887b1d..aeaa70bd1 100644 --- a/Riot/Assets/nl.lproj/Vector.strings +++ b/Riot/Assets/nl.lproj/Vector.strings @@ -79,7 +79,7 @@ "auth_password_dont_match" = "De wachtwoorden komen niet overeen"; "auth_username_in_use" = "De gebruikersnaam is al in gebruik"; "auth_forgot_password" = "Wachtwoord vergeten?"; -"auth_use_server_options" = "Gebruik aangepaste server options (geavanceerd)"; +"auth_use_server_options" = "Gebruik alternatieve serverinstellingen (geavanceerd)"; "auth_email_validation_message" = "Bekijk je e-mail om verder te gaan met de registratie"; "auth_msisdn_validation_title" = "Verificatie Aanhangig"; "auth_msisdn_validation_message" = "We hebben een SMS met een activatie code gestuurd. Vul deze code hieronder in."; @@ -227,7 +227,7 @@ "room_event_action_cancel_upload" = "Uploaden annuleren"; "room_event_action_cancel_download" = "Downloaden annuleren"; "room_event_action_view_encryption" = "Versleutelingsinformatie"; -"room_warning_about_encryption" = "Eind-tot-eind versleuteling is nog in beta en kan onbetrouwbaar zijn.\n\nHet is beter om het nog niet met gevoelige gegevens te vertrouwen.\n\nApparaten kunnen nog niet de geschiedenis van voordat ze de ruimte betraden kunnen ontsleutelen.\n\nVersleutelde berichten zullen nog niet zichtbaar zijn op applicaties die geen versleuteling ondersteunen."; +"room_warning_about_encryption" = "End-to-endbeveiliging is in bèta en kan onbetrouwbaar zijn.\n\nHet is beter om het nog niet met gevoelige gegevens te vertrouwen.\n\nApparaten kunnen de geschiedenis van voordat ze de ruimte betraden nog niet ontsleutelen.\n\nVersleutelde berichten zullen nog niet zichtbaar zijn op programma's die geen versleuteling ondersteunen."; // Unknown devices "unknown_devices_alert_title" = "Ruimte bevat onbekende apparaten"; "unknown_devices_alert" = "Deze ruimte bevat onbekende apparaten die niet geen geverifieerd.\nDit betekent dat er geen garantie is dat de apparaten bij de gebruikers horen waar het beweert dat het bij hoort.\nWe raden je aan om bij elk apparaat door het verificatieprocces heen te gaan voordat je doorgaat, maar je kan het bericht opnieuw versturen zonder te verifiëren als je dat prefereert."; @@ -302,7 +302,7 @@ "settings_unignore_user" = "Alle berichten van %@ laten zien?"; "settings_contacts_discover_matrix_users" = "Gebruik e-mailadressen en telefoonnummers om gebruikers te vinden"; "settings_contacts_phonebook_country" = "Telefoonboek land"; -"settings_labs_e2e_encryption" = "Eind-tot-Eind versleuteling"; +"settings_labs_e2e_encryption" = "End-to-endbeveiliging"; "settings_labs_e2e_encryption_prompt_message" = "Om het opzetten van de versleuteling af te ronden moet je opnieuw inloggen."; "settings_version" = "Versie %@"; "settings_olm_version" = "Olm Versie %@"; @@ -365,8 +365,8 @@ "room_details_advanced_e2e_encryption_enabled" = "Versleuteling staat aan in deze ruimte"; "room_details_advanced_e2e_encryption_disabled" = "Versleuteling staat niet aan in deze ruimte."; "room_details_advanced_e2e_encryption_blacklist_unverified_devices" = "Alleen naar geverifieerde apparaten versleutelen"; -"room_details_advanced_e2e_encryption_prompt_message" = "Eind-tot-eind versleuteling is experimenteel en kan onbetrouwbaar zijn.\n\nHet is beter om het nog niet met gevoelige gegevens te vertrouwen.\n\nApparaten kunnen nog niet de geschiedenis van voordat ze de ruimte betraden kunnen ontsleutelen.\n\nZodra de versleuteling aan staat kan het niet meer worden uitgezet (voor nu).\n\nVersleutelde berichten zullen nog niet zichtbaar zijn op applicaties die geen versleuteling ondersteunen."; -"room_details_fail_to_update_avatar" = "Ruimte foto vernieuwen mislukt"; +"room_details_advanced_e2e_encryption_prompt_message" = "End-to-endbeveiliging is experimenteel en kan onbetrouwbaar zijn.\n\nHet is beter om het nog niet met gevoelige gegevens te vertrouwen.\n\nApparaten kunnen de geschiedenis van voordat ze de ruimte betraden nog niet ontsleutelen.\n\nZodra de versleuteling aan staat kan het (voorlopig) niet worden uitgezet.\n\nVersleutelde berichten zullen nog niet zichtbaar zijn op programma's die geen versleuteling ondersteunen."; +"room_details_fail_to_update_avatar" = "Ruimte-foto vernieuwen mislukt"; "room_details_fail_to_update_room_name" = "Ruimtenaam vernieuwen mislukt"; "room_details_fail_to_update_topic" = "Ruimteonderwerp vernieuwen mislukt"; "room_details_fail_to_update_room_guest_access" = "Ruimte's gast toegang vernieuwen mislukt"; @@ -420,7 +420,7 @@ "google_analytics_use_prompt" = "Wil je helpen met het verbeteren van %@ bij het automatisch rapporteren van crash rapporten en data van gebruik?"; // Crypto "e2e_enabling_on_app_update" = "Riot ondersteunt nu eind-tot-eind sleuteling maar je moet opnieuw inloggen om het aan te zetten.\n\nJe kan het nu of later doen vanaf de applicatie instellingen."; -"e2e_need_log_in_again" = "Je moet opnieuw inloggen om eind-tot-eind versleuteling sleutels te genereren voor dit apparaat en om de publieke sleutel naar de thuisserver te sturen.\nDit is eenmalig; excuses voor het ongemak."; +"e2e_need_log_in_again" = "Je moet opnieuw inloggen om end-to-endbeveligingssleutels te genereren voor dit apparaat en om de publieke sleutel naar de thuisserver te sturen.\nDit is eenmalig; excuses voor het ongemak."; // Bug report "bug_report_title" = "Foutmelding"; "bug_report_description" = "Beschrijf de foutmelding. Wat heb je gedaan? Wat verwachte je dat er zou gebeuren? Wat gebeurde er werkelijk?"; From 0ed8e3b764b47d59da9c312d51316262e2e136f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Thu, 7 Jun 2018 21:19:56 +0000 Subject: [PATCH 11/54] Translated using Weblate (German) Currently translated at 100.0% (501 of 501 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/de/ Typo --- Riot/Assets/de.lproj/Vector.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index 2da915898..6a2f86517 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -318,7 +318,7 @@ "settings_add_phone_number" = "Telefonnummer hinzufügen"; "settings_fail_to_update_profile" = "Profilaktualisierung fehlgeschlagen"; "settings_global_settings_info" = "Globale Benachrichtungseinstellungen sind verfügbar auf dem %@ Web Client"; -"settings_pin_rooms_with_missed_notif" = "Pinnen von Räumen mit vepassten Benachrichtigungen"; +"settings_pin_rooms_with_missed_notif" = "Pinnen von Räumen mit verpassten Benachrichtigungen"; "settings_pin_rooms_with_unread" = "Pinnen von Räumen mit ungelesenen Nachrichten"; "settings_on_denied_notification" = "Benachrichtigungen verboten für %@, bitte in den Geräte-Einstellungen erlauben"; "settings_contacts_discover_matrix_users" = "Entdecke andere Benutzer mittels E-Mail-Adressen oder Telefonnummern"; From adb2f0a093947a0036eca0b8d53e760f1a8186ce Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 14 Jun 2018 08:47:58 +0000 Subject: [PATCH 12/54] Translated using Weblate (Russian) Currently translated at 100.0% (505 of 505 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/ru/ --- Riot/Assets/ru.lproj/Vector.strings | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Riot/Assets/ru.lproj/Vector.strings b/Riot/Assets/ru.lproj/Vector.strings index 28ca66b2a..1901456f0 100644 --- a/Riot/Assets/ru.lproj/Vector.strings +++ b/Riot/Assets/ru.lproj/Vector.strings @@ -539,3 +539,8 @@ "deactivate_account_password_alert_title" = "Деактивировать аккаунт"; "deactivate_account_password_alert_message" = "Чтобы продолжить, введите пароль"; "widget_sticker_picker_no_stickerpacks_alert" = "У вас пока нет включенных пакетов стикеров."; +"event_formatter_rerequest_keys_part1_link" = "Повторно запросить ключи шифрования"; +"event_formatter_rerequest_keys_part2" = " с других устройств."; +// Re-request confirmation dialog +"rerequest_keys_alert_title" = "Запрос отправлен"; +"rerequest_keys_alert_message" = "Запустите Riot на другом устройстве, которое может расшифровать сообщение, чтобы оно могло отправить ключи этому устройству."; From 7a6f9e2684856ca273c2ac7878486a518e709d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20C?= Date: Thu, 14 Jun 2018 08:59:28 +0000 Subject: [PATCH 13/54] Translated using Weblate (French) Currently translated at 100.0% (505 of 505 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/fr/ --- Riot/Assets/fr.lproj/Vector.strings | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Riot/Assets/fr.lproj/Vector.strings b/Riot/Assets/fr.lproj/Vector.strings index 7f10f1756..15df5a9ee 100644 --- a/Riot/Assets/fr.lproj/Vector.strings +++ b/Riot/Assets/fr.lproj/Vector.strings @@ -538,3 +538,8 @@ "deactivate_account_validate_action" = "Désactiver le compte"; "deactivate_account_password_alert_title" = "Désactiver le compte"; "deactivate_account_password_alert_message" = "Pour continuer, veuillez renseigner votre mot de passe"; +"event_formatter_rerequest_keys_part1_link" = "Redemander les clés de chiffrement"; +"event_formatter_rerequest_keys_part2" = " depuis vos autres appareils."; +// Re-request confirmation dialog +"rerequest_keys_alert_title" = "Demande envoyée"; +"rerequest_keys_alert_message" = "Veuillez lancer Riot sur un autre appareil qui peut déchiffrer le message pour qu'il puisse envoyer les clés sur cet appareil."; From 22281c0fbcd91a7269e9baa8d436f58813fcceb9 Mon Sep 17 00:00:00 2001 From: Osoitz Date: Sun, 17 Jun 2018 08:35:36 +0000 Subject: [PATCH 14/54] Translated using Weblate (Basque) Currently translated at 100.0% (505 of 505 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/eu/ --- Riot/Assets/eu.lproj/Vector.strings | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Riot/Assets/eu.lproj/Vector.strings b/Riot/Assets/eu.lproj/Vector.strings index a2999c449..202ce233a 100644 --- a/Riot/Assets/eu.lproj/Vector.strings +++ b/Riot/Assets/eu.lproj/Vector.strings @@ -540,3 +540,8 @@ "deactivate_account_validate_action" = "Desaktibatu kontua"; "deactivate_account_password_alert_title" = "Desaktibatu kontua"; "deactivate_account_password_alert_message" = "Jarraitzeko sartu zure pasahitza"; +"event_formatter_rerequest_keys_part1_link" = "Berreskatu zifratze gakoak"; +"event_formatter_rerequest_keys_part2" = " zure beste gailuetatik."; +// Re-request confirmation dialog +"rerequest_keys_alert_title" = "Eskaria bidalita"; +"rerequest_keys_alert_message" = "Abiatu Riot mezua deszifratu dezakeen beste gailuren batean handik hona gakoak bidali ahal izateko."; From dddceec56c48fe15bfcb2f3f637c104a8d0a0129 Mon Sep 17 00:00:00 2001 From: daniel tygel Date: Sun, 17 Jun 2018 17:16:33 +0000 Subject: [PATCH 15/54] Added translation using Weblate (Portuguese (Brazil)) --- Riot/Assets/pt_BR.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) create mode 100644 Riot/Assets/pt_BR.lproj/Vector.strings diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Riot/Assets/pt_BR.lproj/Vector.strings @@ -0,0 +1 @@ + From 7f5a5d06e534d9f9a9ba5d8d5600da35296131ee Mon Sep 17 00:00:00 2001 From: daniel tygel Date: Sun, 17 Jun 2018 17:17:20 +0000 Subject: [PATCH 16/54] Added translation using Weblate (Portuguese (Brazil)) --- Riot/Assets/pt_BR.lproj/InfoPlist.strings | 1 + 1 file changed, 1 insertion(+) create mode 100644 Riot/Assets/pt_BR.lproj/InfoPlist.strings diff --git a/Riot/Assets/pt_BR.lproj/InfoPlist.strings b/Riot/Assets/pt_BR.lproj/InfoPlist.strings new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Riot/Assets/pt_BR.lproj/InfoPlist.strings @@ -0,0 +1 @@ + From 476c0b1a62b6a6a4d3480cdeb868356764a9ff6c Mon Sep 17 00:00:00 2001 From: daniel tygel Date: Sun, 17 Jun 2018 17:18:36 +0000 Subject: [PATCH 17/54] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (4 of 4 strings) Translation: Riot iOS/Riot iOS (Dialogs) Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios-dialogs/pt_BR/ --- Riot/Assets/pt_BR.lproj/InfoPlist.strings | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/pt_BR.lproj/InfoPlist.strings b/Riot/Assets/pt_BR.lproj/InfoPlist.strings index 8b1378917..da30fcefa 100644 --- a/Riot/Assets/pt_BR.lproj/InfoPlist.strings +++ b/Riot/Assets/pt_BR.lproj/InfoPlist.strings @@ -1 +1,5 @@ - +// Permissions usage explanations +"NSCameraUsageDescription" = "A câmera será usada para tomar fotos e vídeos, e também para a realização de chamadas de vídeo."; +"NSPhotoLibraryUsageDescription" = "A galeria de fotos é usada para o envio de fotos e vídeos."; +"NSMicrophoneUsageDescription" = "O microfone é usado para gravar vídeos e fazer chamadas, tanto de áudio como de vídeo."; +"NSContactsUsageDescription" = "O cadernos de contatos é usado para fazer busca de usuárias/os no Riot a partir do e-mail ou do número de telefone."; From 2fb2dd463b74fab45d0df6c6ffb846724d1bf6c9 Mon Sep 17 00:00:00 2001 From: daniel tygel Date: Sun, 17 Jun 2018 17:19:36 +0000 Subject: [PATCH 18/54] Added translation using Weblate (Portuguese (Brazil)) --- Riot/Assets/pt_BR.lproj/Localizable.strings | 1 + 1 file changed, 1 insertion(+) create mode 100644 Riot/Assets/pt_BR.lproj/Localizable.strings diff --git a/Riot/Assets/pt_BR.lproj/Localizable.strings b/Riot/Assets/pt_BR.lproj/Localizable.strings new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Riot/Assets/pt_BR.lproj/Localizable.strings @@ -0,0 +1 @@ + From eec00a1c443493edafe6b4cdac6eb98948b219e7 Mon Sep 17 00:00:00 2001 From: daniel tygel Date: Sun, 17 Jun 2018 17:28:26 +0000 Subject: [PATCH 19/54] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (26 of 26 strings) Translation: Riot iOS/Riot iOS (Push) Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios-push/pt_BR/ --- Riot/Assets/pt_BR.lproj/Localizable.strings | 53 ++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/pt_BR.lproj/Localizable.strings b/Riot/Assets/pt_BR.lproj/Localizable.strings index 8b1378917..767bb6cc3 100644 --- a/Riot/Assets/pt_BR.lproj/Localizable.strings +++ b/Riot/Assets/pt_BR.lproj/Localizable.strings @@ -1 +1,52 @@ - +/* New message from a specific person, not referencing a room */ +"MSG_FROM_USER" = "Mensagem de %@"; +/* New message from a specific person in a named room */ +"MSG_FROM_USER_IN_ROOM" = "%@ enviou mensagem em %@"; +/* New message from a specific person, not referencing a room. Content included. */ +"MSG_FROM_USER_WITH_CONTENT" = "%@: %@"; +/* New message from a specific person in a named room. Content included. */ +"MSG_FROM_USER_IN_ROOM_WITH_CONTENT" = "%@ em %@: %@"; +/* New action message from a specific person, not referencing a room. */ +"ACTION_FROM_USER" = "* %@ %@"; +/* New action message from a specific person in a named room. */ +"ACTION_FROM_USER_IN_ROOM" = "%@ : * %@ %@"; +/* New action message from a specific person, not referencing a room. */ +"IMAGE_FROM_USER" = "%@ enviou a você uma imagem %@"; +/* New action message from a specific person in a named room. */ +"IMAGE_FROM_USER_IN_ROOM" = "%@ enviou uma imagem %@ na sala %@"; +/* A single unread message in a room */ +"SINGLE_UNREAD_IN_ROOM" = "Você recebeu uma mensagem na sala %@"; +/* A single unread message */ +"SINGLE_UNREAD" = "Você recebeu uma mensagem"; +/* Multiple unread messages in a room */ +"UNREAD_IN_ROOM" = "%@ novas mensagens na sala %@"; +/* Multiple unread messages from a specific person, not referencing a room */ +"MSGS_FROM_USER" = "%@ novas mensagens de %@"; +/* Multiple unread messages from two people */ +"MSGS_FROM_TWO_USERS" = "%@ novas mensagens de %@ e %@"; +/* Multiple unread messages from three people */ +"MSGS_FROM_THREE_USERS" = "%@ novas mensagens de %@, %@ e %@"; +/* Multiple unread messages from two plus people (ie. for 4+ people: 'others' replaces the third person) */ +"MSGS_FROM_TWO_PLUS_USERS" = "%@ novas mensagens de %@, %@ e outras/os"; +/* Multiple messages in two rooms */ +"MSGS_IN_TWO_ROOMS" = "%@ novas mensagens nas salas %@ e %@"; +/* Look, stuff's happened, alright? Just open the app. */ +"MSGS_IN_TWO_PLUS_ROOMS" = "%@ novas mensagens nas salas %@ e %@, dentre outras"; +/* A user has invited you to a chat */ +"USER_INVITE_TO_CHAT" = "%@ convidou você para conversar"; +/* A user has invited you to an (unamed) group chat */ +"USER_INVITE_TO_CHAT_GROUP_CHAT" = "%@ convidou você para uma conversa em grupo"; +/* A user has invited you to a named room */ +"USER_INVITE_TO_NAMED_ROOM" = "%@ convidou você para a sala %@"; +/* Incoming one-to-one voice call */ +"VOICE_CALL_FROM_USER" = "Chamada de %@"; +/* Incoming one-to-one video call */ +"VIDEO_CALL_FROM_USER" = "Chamada de vídeo de %@"; +/* Incoming unnamed voice conference invite from a specific person */ +"VOICE_CONF_FROM_USER" = "Chamada coletiva de %@"; +/* Incoming unnamed video conference invite from a specific person */ +"VIDEO_CONF_FROM_USER" = "Vídeo-chamada coletiva de %@"; +/* Incoming named voice conference invite from a specific person */ +"VOICE_CONF_NAMED_FROM_USER" = "Vídeo chamada coletiva de %@: '%@'"; +/* Incoming named video conference invite from a specific person */ +"VIDEO_CONF_NAMED_FROM_USER" = "Vídeo-chamada coletiva de %@: '%@'"; From f433b61d0984d515cc08897ddfed6d3391320039 Mon Sep 17 00:00:00 2001 From: Krombel Date: Mon, 18 Jun 2018 10:56:45 +0000 Subject: [PATCH 20/54] Translated using Weblate (German) Currently translated at 100.0% (505 of 505 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/de/ --- Riot/Assets/de.lproj/Vector.strings | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Riot/Assets/de.lproj/Vector.strings b/Riot/Assets/de.lproj/Vector.strings index 6a2f86517..f6bd2be7b 100644 --- a/Riot/Assets/de.lproj/Vector.strings +++ b/Riot/Assets/de.lproj/Vector.strings @@ -538,3 +538,8 @@ "deactivate_account_validate_action" = "Account deaktiveren"; "deactivate_account_password_alert_title" = "Account deaktivieren"; "deactivate_account_password_alert_message" = "Zum Fortfahren, Password eingeben"; +"event_formatter_rerequest_keys_part1_link" = "Verschlüsselungsschlüssel erneut"; +"event_formatter_rerequest_keys_part2" = " von deinen anderen Geräten anfragen."; +// Re-request confirmation dialog +"rerequest_keys_alert_title" = "Anfrage gesendet"; +"rerequest_keys_alert_message" = "Öffne Riot bitte auf einem anderen Gerät, dass die Nachricht entschlüsseln kann, damit es die Schlüssel an dieses Gerät senden kann."; From b11e1c8a8a5b8afbfca416555047394e15ad3dba Mon Sep 17 00:00:00 2001 From: einMarco Date: Wed, 20 Jun 2018 10:51:44 +0200 Subject: [PATCH 21/54] Added accessibility labels for issue: "Voiceover support for accessibility #1842" --- Riot/Base.lproj/Main.storyboard | 10 +++++----- Riot/ViewController/MasterTabBarController.m | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Riot/Base.lproj/Main.storyboard b/Riot/Base.lproj/Main.storyboard index b53f424ad..383630d7a 100644 --- a/Riot/Base.lproj/Main.storyboard +++ b/Riot/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + @@ -51,7 +51,7 @@ - + @@ -247,7 +247,7 @@ - + @@ -608,7 +608,7 @@ - + diff --git a/Riot/ViewController/MasterTabBarController.m b/Riot/ViewController/MasterTabBarController.m index 6a1a6c667..da7e92860 100644 --- a/Riot/ViewController/MasterTabBarController.m +++ b/Riot/ViewController/MasterTabBarController.m @@ -77,6 +77,15 @@ _roomsViewController = [self.viewControllers objectAtIndex:TABBAR_ROOMS_INDEX]; _groupsViewController = [self.viewControllers objectAtIndex:TABBAR_GROUPS_INDEX]; + // Set the accessibility labels for all buttons #1842 + [_settingsBarButtonItem setAccessibilityLabel:@"Settings"]; + [_searchBarButtonIem setAccessibilityLabel:@"Search"]; + [_homeViewController setAccessibilityLabel:@"Home"]; + [_favouritesViewController setAccessibilityLabel:@"Favorites"]; + [_peopleViewController setAccessibilityLabel:@"People"]; + [_roomsViewController setAccessibilityLabel:@"Rooms"]; + [_groupsViewController setAccessibilityLabel:@"Groups"]; + // Sanity check NSAssert(_homeViewController && _favouritesViewController && _peopleViewController && _roomsViewController && _groupsViewController, @"Something wrong in Main.storyboard"); From 4185924a13d377c91112ca0b009d96dba4f10f24 Mon Sep 17 00:00:00 2001 From: einMarco Date: Wed, 20 Jun 2018 10:51:44 +0200 Subject: [PATCH 22/54] Added accessibility labels for issue: "Voiceover support for accessibility #1842" Signed-off-by: Marco Seizew --- Riot/Base.lproj/Main.storyboard | 10 +++++----- Riot/ViewController/MasterTabBarController.m | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Riot/Base.lproj/Main.storyboard b/Riot/Base.lproj/Main.storyboard index b53f424ad..383630d7a 100644 --- a/Riot/Base.lproj/Main.storyboard +++ b/Riot/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + @@ -51,7 +51,7 @@ - + @@ -247,7 +247,7 @@ - + @@ -608,7 +608,7 @@ - + diff --git a/Riot/ViewController/MasterTabBarController.m b/Riot/ViewController/MasterTabBarController.m index 6a1a6c667..da7e92860 100644 --- a/Riot/ViewController/MasterTabBarController.m +++ b/Riot/ViewController/MasterTabBarController.m @@ -77,6 +77,15 @@ _roomsViewController = [self.viewControllers objectAtIndex:TABBAR_ROOMS_INDEX]; _groupsViewController = [self.viewControllers objectAtIndex:TABBAR_GROUPS_INDEX]; + // Set the accessibility labels for all buttons #1842 + [_settingsBarButtonItem setAccessibilityLabel:@"Settings"]; + [_searchBarButtonIem setAccessibilityLabel:@"Search"]; + [_homeViewController setAccessibilityLabel:@"Home"]; + [_favouritesViewController setAccessibilityLabel:@"Favorites"]; + [_peopleViewController setAccessibilityLabel:@"People"]; + [_roomsViewController setAccessibilityLabel:@"Rooms"]; + [_groupsViewController setAccessibilityLabel:@"Groups"]; + // Sanity check NSAssert(_homeViewController && _favouritesViewController && _peopleViewController && _roomsViewController && _groupsViewController, @"Something wrong in Main.storyboard"); From 6a2babd05df5acdd5e3e30d94bf4d7e0b4198fa7 Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 25 Jun 2018 13:29:32 +0200 Subject: [PATCH 23/54] RoomVC: BF: Read receipts processing dramatically slows down UI #1899 Build, cache and update read receipts on the processing queue. --- CHANGES.rst | 1 + Riot/Model/Room/RoomBubbleCellData.h | 4 - Riot/Model/Room/RoomBubbleCellData.m | 51 +++--------- Riot/Model/Room/RoomDataSource.m | 115 ++++++++++++++++++++++----- 4 files changed, 110 insertions(+), 61 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index fcffdee2c..42c769c6c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,6 +6,7 @@ Improvements: * RoomVC: Add a re-request keys button on message unable to decrypt (#1879). Bug fix: + * RoomVC: Read receipts processing dramatically slows down UI (#1899). Changes in 0.6.17 (2018-06-01) =============================================== diff --git a/Riot/Model/Room/RoomBubbleCellData.h b/Riot/Model/Room/RoomBubbleCellData.h index 5e4a876b9..7ce9162fc 100644 --- a/Riot/Model/Room/RoomBubbleCellData.h +++ b/Riot/Model/Room/RoomBubbleCellData.h @@ -34,10 +34,6 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag) */ @property(nonatomic) BOOL containsLastMessage; -/** - A Boolean value that determines whether some read receipts are currently displayed in this bubble. - */ -@property(nonatomic) BOOL hasReadReceipts; /** The event id of the current selected event inside the bubble. Default is nil. diff --git a/Riot/Model/Room/RoomBubbleCellData.m b/Riot/Model/Room/RoomBubbleCellData.m index bfea7fc3f..a78a5680b 100644 --- a/Riot/Model/Room/RoomBubbleCellData.m +++ b/Riot/Model/Room/RoomBubbleCellData.m @@ -48,13 +48,9 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; // Increase maximum number of components self.maxComponentCount = 20; - // Initialize receipts flag - _hasReadReceipts = NO; - - // Force the update of the text message to take into account the potential read receipts in the bubble display. - // Note: we don't update this attributed string here because the RoomBubbleCellData instances are created on a processing - // thread different from the UI thread. - self.attributedTextMessage = nil; + // Initialize read receipts + self.readReceipts = [NSMutableDictionary dictionary]; + self.readReceipts[event.eventId] = [roomDataSource.room getEventReceipts:event.eventId sorted:YES]; } return self; @@ -79,7 +75,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; [self refreshBubbleComponentsPosition]; } - shouldUpdateComponentsPosition = NO; } } @@ -163,9 +158,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; NSMutableAttributedString *currentAttributedTextMsg; - // Refresh the receipt flag during this process - _hasReadReceipts = NO; - NSInteger selectedComponentIndex = self.selectedComponentIndex; NSInteger lastMessageIndex = self.containsLastMessage ? self.mostRecentComponentIndex : NSNotFound; @@ -203,11 +195,10 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; // Init attributed string with the first text component currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:componentString]; } - - // Vertical whitespace is added in case of read receipts - if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO]) + + if (self.readReceipts[component.event.eventId].count) { - _hasReadReceipts = YES; + // Add vertical whitespace in case of read receipts [currentAttributedTextMsg appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]]; } @@ -246,10 +237,9 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; // Append attributed text [currentAttributedTextMsg appendAttributedString:componentString]; - // Add vertical whitespace in case of read receipts - if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO]) + if (self.readReceipts[component.event.eventId].count) { - _hasReadReceipts = YES; + // Add vertical whitespace in case of read receipts [currentAttributedTextMsg appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]]; } } @@ -262,9 +252,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; { // CAUTION: This method must be called on the main thread. - // Refresh the receipt flag during this process. - _hasReadReceipts = NO; - @synchronized(bubbleComponents) { // Check whether there is at least one component. @@ -283,7 +270,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; if (component.attributedTextMessage) { - _hasReadReceipts = ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO] != nil); break; } } @@ -308,7 +294,7 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; } // Vertical whitespace is added in case of read receipts - if (_hasReadReceipts) + if (self.readReceipts.count) { [attributedString appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]]; } @@ -348,9 +334,8 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; component.position = CGPointMake(0, positionY); // Add vertical whitespace in case of read receipts. - if ([roomDataSource.room getEventReceipts:component.event.eventId sorted:NO]) + if (self.readReceipts[component.event.eventId]) { - _hasReadReceipts = YES; [attributedString appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]]; } @@ -379,19 +364,6 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; } } -- (void)setHasReadReceipts:(BOOL)hasReadReceipts -{ - // Check whether there is something to do - if (_hasReadReceipts || hasReadReceipts) - { - // Update flag - _hasReadReceipts = hasReadReceipts; - - // Recompute the text message layout - self.attributedTextMessage = nil; - } -} - - (void)setSelectedEventId:(NSString *)selectedEventId { // Check whether there is something to do @@ -517,6 +489,9 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; return NO; } + // Update read receipts for this bubble + self.readReceipts[event.eventId] = [roomDataSource.room getEventReceipts:event.eventId sorted:YES]; + return [super addEvent:event andRoomState:roomState]; } diff --git a/Riot/Model/Room/RoomDataSource.m b/Riot/Model/Room/RoomDataSource.m index e6401e54d..4fe9680c0 100644 --- a/Riot/Model/Room/RoomDataSource.m +++ b/Riot/Model/Room/RoomDataSource.m @@ -96,24 +96,101 @@ - (void)didReceiveReceiptEvent:(MXEvent *)receiptEvent roomState:(MXRoomState *)roomState { - // Override this callback to force rendering of each cell with read receipts information. - @synchronized(bubbles) - { - for (RoomBubbleCellData *cellData in bubbles) + // Do the processing on the same processing queue as MXKRoomDataSource + dispatch_async(MXKRoomDataSource.processingQueue, ^{ + + // Remove the previous displayed read receipt for each user who sent a + // new read receipt. + // To implement it, we need to find the sender id of each new read receipt + // among the read receipts array of all events in all bubbles. + NSMutableArray *readReceiptSenders = [receiptEvent.readReceiptSenders mutableCopy]; + + @synchronized(bubbles) { - cellData.hasReadReceipts = NO; + NSMutableDictionary *> *updatedCellDataReadReceipts = [NSMutableDictionary dictionary]; + for (RoomBubbleCellData *cellData in bubbles) + { + for (NSString *eventId in cellData.readReceipts) + { + for (MXReceiptData *receiptData in cellData.readReceipts[eventId]) + { + NSMutableArray *foundSenders = [NSMutableArray array]; + for (NSString *senderId in readReceiptSenders) + { + if ([receiptData.userId isEqualToString:senderId]) + { + // We find an existing displayed receipt, remove it + [foundSenders addObject:senderId]; + + if (!updatedCellDataReadReceipts[eventId]) + { + updatedCellDataReadReceipts[eventId] = [cellData.readReceipts[eventId] mutableCopy]; + } + + [updatedCellDataReadReceipts[eventId] removeObject:receiptData]; + break; + } + } + + // As there is one (the last) read receipt displayed per user, + // we do not need to search for other read receipts of found users. + [readReceiptSenders removeObjectsInArray:foundSenders]; + if (!readReceiptSenders.count) + { + // All senders have been found + break; + } + } + } + + // Flush found changed to the cell data + for (NSString *eventId in updatedCellDataReadReceipts) + { + if (updatedCellDataReadReceipts[eventId].count) + { + cellData.readReceipts[eventId] = updatedCellDataReadReceipts[eventId]; + } + else + { + cellData.readReceipts[eventId] = nil; + } + } + + if (!readReceiptSenders.count) + { + // All senders have been found + break; + } + } } - } - - NSArray *readEventIds = receiptEvent.readReceiptEventIds; - for (NSString* eventId in readEventIds) - { - RoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId]; - // Ignore the read receipts on the events without an actual display. - cellData.hasReadReceipts = !cellData.hasNoDisplay; - } - - [super didReceiveReceiptEvent:receiptEvent roomState:roomState]; + + // Update cell data we have received a read receipt for + NSArray *readEventIds = receiptEvent.readReceiptEventIds; + for (NSString* eventId in readEventIds) + { + RoomBubbleCellData *cellData = [self cellDataOfEventWithEventId:eventId]; + if (cellData) + { + @synchronized(bubbles) + { + if (!cellData.hasNoDisplay) + { + cellData.readReceipts[eventId] = [self.room getEventReceipts:eventId sorted:YES]; + } + else + { + // Ignore the read receipts on the events without an actual display. + cellData.readReceipts[eventId] = nil; + } + } + } + } + + dispatch_async(dispatch_get_main_queue(), ^{ + // TODO: Be smarter and update only updated cells + [super didReceiveReceiptEvent:receiptEvent roomState:roomState]; + }); + }); } #pragma mark - @@ -181,7 +258,7 @@ // Handle read receipts and read marker display. // Ignore the read receipts on the bubble without actual display. // Ignore the read receipts on collapsed bubbles - if ((self.showBubbleReceipts && cellData.hasReadReceipts && !isCollapsableCellCollapsed) || self.showReadMarker) + if ((self.showBubbleReceipts && cellData.readReceipts.count && !isCollapsableCellCollapsed) || self.showReadMarker) { // Read receipts container are inserted here on the right side into the content view. // Some vertical whitespaces are added in message text view (see RoomBubbleCellData class) to insert correctly multiple receipts. @@ -194,10 +271,10 @@ if (component.event.sentState != MXEventSentStateFailed) { // Handle read receipts (if any) - if (self.showBubbleReceipts && cellData.hasReadReceipts && !isCollapsableCellCollapsed) + if (self.showBubbleReceipts && cellData.readReceipts.count && !isCollapsableCellCollapsed) { // Get the events receipts by ignoring the current user receipt. - NSArray* receipts = [self.room getEventReceipts:component.event.eventId sorted:YES]; + NSArray* receipts = cellData.readReceipts[component.event.eventId]; NSMutableArray *roomMembers; NSMutableArray *placeholders; From f6fc27dc4362937b9abd0edef342723321646eb8 Mon Sep 17 00:00:00 2001 From: Marco Seizew Date: Mon, 25 Jun 2018 15:07:54 +0200 Subject: [PATCH 24/54] Added the i18n localisation strings to the accessibility labels Signed-off-by: Marco Seizew --- Riot/ViewController/MasterTabBarController.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Riot/ViewController/MasterTabBarController.m b/Riot/ViewController/MasterTabBarController.m index da7e92860..3b2bd62fe 100644 --- a/Riot/ViewController/MasterTabBarController.m +++ b/Riot/ViewController/MasterTabBarController.m @@ -78,13 +78,13 @@ _groupsViewController = [self.viewControllers objectAtIndex:TABBAR_GROUPS_INDEX]; // Set the accessibility labels for all buttons #1842 - [_settingsBarButtonItem setAccessibilityLabel:@"Settings"]; - [_searchBarButtonIem setAccessibilityLabel:@"Search"]; - [_homeViewController setAccessibilityLabel:@"Home"]; - [_favouritesViewController setAccessibilityLabel:@"Favorites"]; - [_peopleViewController setAccessibilityLabel:@"People"]; - [_roomsViewController setAccessibilityLabel:@"Rooms"]; - [_groupsViewController setAccessibilityLabel:@"Groups"]; + [_settingsBarButtonItem setAccessibilityLabel:NSLocalizedStringFromTable(@"settings_title", @"Vector", nil)]; + [_searchBarButtonIem setAccessibilityLabel:NSLocalizedStringFromTable(@"search_default_placeholder", @"Vector", nil)]; + [_homeViewController setAccessibilityLabel:NSLocalizedStringFromTable(@"title_home", @"Vector", nil)]; + [_favouritesViewController setAccessibilityLabel:NSLocalizedStringFromTable(@"title_favourites", @"Vector", nil)]; + [_peopleViewController setAccessibilityLabel:NSLocalizedStringFromTable(@"title_people", @"Vector", nil)]; + [_roomsViewController setAccessibilityLabel:NSLocalizedStringFromTable(@"title_rooms", @"Vector", nil)]; + [_groupsViewController setAccessibilityLabel:NSLocalizedStringFromTable(@"title_groups", @"Vector", nil)]; // Sanity check NSAssert(_homeViewController && _favouritesViewController && _peopleViewController && _roomsViewController && _groupsViewController, @"Something wrong in Main.storyboard"); From ca5b17ca0b73b4b7cf8ee3e91f520677fe7e7d00 Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 25 Jun 2018 16:12:36 +0200 Subject: [PATCH 25/54] RoomVC: BF: Read receipts processing dramatically slows down UI #1899 Fix wrong alignment of read receipts avatars with their message --- Riot/Model/Room/RoomBubbleCellData.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Model/Room/RoomBubbleCellData.m b/Riot/Model/Room/RoomBubbleCellData.m index a78a5680b..d0f7ff4a2 100644 --- a/Riot/Model/Room/RoomBubbleCellData.m +++ b/Riot/Model/Room/RoomBubbleCellData.m @@ -51,6 +51,9 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; // Initialize read receipts self.readReceipts = [NSMutableDictionary dictionary]; self.readReceipts[event.eventId] = [roomDataSource.room getEventReceipts:event.eventId sorted:YES]; + + // Reset attributedTextMessage to force reset MXKRoomCellData parameters + self.attributedTextMessage = nil; } return self; From 9115b15426214a4d9589db7f58d4ea873c8b2b46 Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 27 Jun 2018 07:55:50 +0200 Subject: [PATCH 26/54] Update CHANGES --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index fcffdee2c..5617893b5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,7 @@ Changes in 0.6.18 () Improvements: * Upgrade MatrixKit version (). * RoomVC: Add a re-request keys button on message unable to decrypt (#1879). + * Added the i18n localisation strings to the accessibility labels (#1842), thanks to @einMarco (PR#1906). Bug fix: From 054b2afdedba24e4d90e5d3ec209c11bd98871a0 Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 27 Jun 2018 09:55:06 +0200 Subject: [PATCH 27/54] Analytics: Move code from AppDelegate to a dedicated class: Analytics --- CHANGES.rst | 3 +- Riot.xcodeproj/project.pbxproj | 31 ++++++ Riot/Analytics/Analytics.h | 53 +++++++++ Riot/Analytics/Analytics.m | 105 ++++++++++++++++++ Riot/AppDelegate.h | 7 +- Riot/AppDelegate.m | 75 +------------ .../AttachmentsViewController.m | 2 +- .../AuthenticationViewController.m | 2 +- .../Communities/GroupDetailsViewController.m | 2 +- .../Communities/GroupHomeViewController.m | 2 +- .../GroupParticipantsViewController.m | 2 +- .../Communities/GroupRoomsViewController.m | 2 +- .../Communities/GroupsViewController.m | 2 +- .../ContactDetailsViewController.m | 2 +- .../ContactsTableViewController.h | 2 +- .../ContactsTableViewController.m | 2 +- .../CountryPickerViewController.m | 2 +- .../DeactivateAccountViewController.m | 2 +- .../DirectoryServerPickerViewController.m | 2 +- Riot/ViewController/DirectoryViewController.m | 2 +- .../HomeFilesSearchViewController.m | 2 +- .../HomeMessagesSearchViewController.m | 2 +- .../LanguagePickerViewController.m | 2 +- Riot/ViewController/MasterTabBarController.m | 4 +- .../MediaAlbumContentViewController.m | 2 +- .../MediaPickerViewController.m | 2 +- Riot/ViewController/RecentsViewController.h | 2 +- Riot/ViewController/RecentsViewController.m | 2 +- .../RoomFilesSearchViewController.m | 2 +- .../RoomMemberDetailsViewController.m | 2 +- .../RoomMessagesSearchViewController.m | 2 +- .../RoomParticipantsViewController.m | 2 +- .../ViewController/RoomSearchViewController.m | 2 +- .../RoomSettingsViewController.m | 2 +- Riot/ViewController/RoomViewController.m | 2 +- Riot/ViewController/SettingsViewController.m | 6 +- .../UnifiedSearchViewController.m | 2 +- .../UsersDevicesViewController.m | 2 +- 38 files changed, 232 insertions(+), 112 deletions(-) create mode 100644 Riot/Analytics/Analytics.h create mode 100644 Riot/Analytics/Analytics.m diff --git a/CHANGES.rst b/CHANGES.rst index fcffdee2c..e5c64d9c1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,7 @@ Changes in 0.6.18 () Improvements: * Upgrade MatrixKit version (). * RoomVC: Add a re-request keys button on message unable to decrypt (#1879). + * Analytics: Move code from AppDelegate to a dedicated class: Analytics Bug fix: @@ -1125,4 +1126,4 @@ Changes in Vector iOS in 0.1.0 (2016-01-29) Changes in Vector iOS in 0.0.1 (2015-11-16) =============================================== - * Creation : The first implementation of Vector application based on Matrix iOS Kit v0.2.7. \ No newline at end of file + * Creation : The first implementation of Vector application based on Matrix iOS Kit v0.2.7. diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index f3a963be3..097705c6a 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -59,6 +59,11 @@ 32471CE11F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 32471CDF1F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.m */; }; 32471CE21F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32471CE01F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.xib */; }; 325E1C151E8D03950018D91E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 325E1C131E8D03950018D91E /* LaunchScreen.storyboard */; }; + 3267EFB220E2A04100FF1CAA /* Analytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 3267EFB120E2A04100FF1CAA /* Analytics.m */; }; + 3267EFB720E379FE00FF1CAA /* CHANGES.rst in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB320E379FD00FF1CAA /* CHANGES.rst */; }; + 3267EFB820E379FE00FF1CAA /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB420E379FD00FF1CAA /* Podfile */; }; + 3267EFB920E379FE00FF1CAA /* AUTHORS.rst in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */; }; + 3267EFBA20E379FE00FF1CAA /* README.rst in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB620E379FD00FF1CAA /* README.rst */; }; 327382B51F276AD200356143 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382A81F276AD200356143 /* InfoPlist.strings */; }; 327382B61F276AD200356143 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382AA1F276AD200356143 /* Localizable.strings */; }; 327382B71F276AD200356143 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382AC1F276AD200356143 /* Vector.strings */; }; @@ -725,6 +730,12 @@ 32471CDF1F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMembershipExpandedWithPaginationTitleBubbleCell.m; sourceTree = ""; }; 32471CE01F13AC1500BDF50A /* RoomMembershipExpandedWithPaginationTitleBubbleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomMembershipExpandedWithPaginationTitleBubbleCell.xib; sourceTree = ""; }; 325E1C141E8D03950018D91E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 3267EFB020E2A04100FF1CAA /* Analytics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Analytics.h; path = Riot/Analytics/Analytics.h; sourceTree = SOURCE_ROOT; }; + 3267EFB120E2A04100FF1CAA /* Analytics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Analytics.m; path = Riot/Analytics/Analytics.m; sourceTree = SOURCE_ROOT; }; + 3267EFB320E379FD00FF1CAA /* CHANGES.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGES.rst; sourceTree = ""; }; + 3267EFB420E379FD00FF1CAA /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = ""; }; + 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS.rst; sourceTree = ""; }; + 3267EFB620E379FD00FF1CAA /* README.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.rst; sourceTree = ""; }; 327382A91F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = InfoPlist.strings; sourceTree = ""; }; 327382AB1F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Localizable.strings; sourceTree = ""; }; 327382AD1F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Vector.strings; sourceTree = ""; }; @@ -1597,6 +1608,16 @@ path = "jitsi-meet"; sourceTree = ""; }; + 3267EFAF20E2A00F00FF1CAA /* Analytics */ = { + isa = PBXGroup; + children = ( + 3267EFB020E2A04100FF1CAA /* Analytics.h */, + 3267EFB120E2A04100FF1CAA /* Analytics.m */, + ); + name = Analytics; + path = "New Group"; + sourceTree = ""; + }; 327382A71F276AD200356143 /* de.lproj */ = { isa = PBXGroup; children = ( @@ -1796,6 +1817,7 @@ F083BB081E7009EC00A9B29C /* Riot */ = { isa = PBXGroup; children = ( + 3267EFAF20E2A00F00FF1CAA /* Analytics */, F083BB091E7009EC00A9B29C /* API */, F083BB0E1E7009EC00A9B29C /* Assets */, F083BBE41E7009EC00A9B29C /* Categories */, @@ -2682,6 +2704,10 @@ isa = PBXGroup; children = ( F083BB081E7009EC00A9B29C /* Riot */, + 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */, + 3267EFB320E379FD00FF1CAA /* CHANGES.rst */, + 3267EFB420E379FD00FF1CAA /* Podfile */, + 3267EFB620E379FD00FF1CAA /* README.rst */, F083BB021E7005FD00A9B29C /* RiotTests */, 24CBEC4F1F0EAD310093EABB /* RiotShareExtension */, 92726A441F58737A004AD26F /* SiriIntents */, @@ -2988,6 +3014,7 @@ F083BD641E7009ED00A9B29C /* direct_icon@3x.png in Resources */, F083BE261E7009ED00A9B29C /* SegmentedViewController.xib in Resources */, F083BE161E7009ED00A9B29C /* MediaAlbumContentViewController.xib in Resources */, + 3267EFB720E379FE00FF1CAA /* CHANGES.rst in Resources */, F083BD441E7009ED00A9B29C /* call_speaker_on_icon@3x.png in Resources */, F0614A0F1EDDCCE700F5DC9A /* jump_to_unread@3x.png in Resources */, F083BE511E7009ED00A9B29C /* RoomOutgoingEncryptedTextMsgBubbleCell.xib in Resources */, @@ -3040,6 +3067,7 @@ 32BB89F0204D86DA002F3AEC /* InfoPlist.strings in Resources */, F083BD3E1E7009ED00A9B29C /* call_hangup_icon@3x.png in Resources */, 32AE61F21F0D2183007255F4 /* InfoPlist.strings in Resources */, + 3267EFB920E379FE00FF1CAA /* AUTHORS.rst in Resources */, F083BDB91E7009ED00A9B29C /* remove_icon_pink.png in Resources */, F083BE531E7009ED00A9B29C /* RoomOutgoingEncryptedTextMsgWithoutSenderInfoBubbleCell.xib in Resources */, F083BD7F1E7009ED00A9B29C /* error@3x.png in Resources */, @@ -3070,6 +3098,7 @@ F083BD5F1E7009ED00A9B29C /* details_icon.png in Resources */, F083BE241E7009ED00A9B29C /* RoomViewController.xib in Resources */, F083BE7B1E7009ED00A9B29C /* RoomInputToolbarView.xib in Resources */, + 3267EFB820E379FE00FF1CAA /* Podfile in Resources */, F0E05A3D1EA0F9EB004B83FB /* tab_people_selected@2x.png in Resources */, F0E05A451EA0F9EB004B83FB /* tab_rooms.png in Resources */, F083BE751E7009ED00A9B29C /* RoomOutgoingTextMsgWithoutSenderNameBubbleCell.xib in Resources */, @@ -3319,6 +3348,7 @@ F0E05A3C1EA0F9EB004B83FB /* tab_people_selected.png in Resources */, F083BD221E7009ED00A9B29C /* add_participant.png in Resources */, F083BDC61E7009ED00A9B29C /* search_bg@2x.png in Resources */, + 3267EFBA20E379FE00FF1CAA /* README.rst in Resources */, F083BD421E7009ED00A9B29C /* call_speaker_on_icon.png in Resources */, F04AF26D1F83A4C100D20F4D /* Localizable.strings in Resources */, F083BD9A1E7009ED00A9B29C /* logo@3x.png in Resources */, @@ -3543,6 +3573,7 @@ 321082B21F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.m in Sources */, 32C2356F1F7B871800E38FC5 /* WidgetPickerViewController.m in Sources */, F083BE661E7009ED00A9B29C /* RoomIncomingTextMsgWithPaginationTitleBubbleCell.m in Sources */, + 3267EFB220E2A04100FF1CAA /* Analytics.m in Sources */, F083BE141E7009ED00A9B29C /* HomeViewController.m in Sources */, F083BDFB1E7009ED00A9B29C /* RoomSearchDataSource.m in Sources */, 32EF474920B6EE990031695C /* StickerPickerViewController.m in Sources */, diff --git a/Riot/Analytics/Analytics.h b/Riot/Analytics/Analytics.h new file mode 100644 index 000000000..72f493c0a --- /dev/null +++ b/Riot/Analytics/Analytics.h @@ -0,0 +1,53 @@ +/* + Copyright 2018 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 + +/** + `Analytics` sends analytics to an analytics tool. + */ +@interface Analytics : NSObject + +/** + Returns the shared Analytics manager. + + @return the shared Analytics manager. + */ ++ (instancetype)sharedInstance; + +/** + Start doing analytics if the settings `enableCrashReport` is enabled. + */ +- (void)start; + +/** + Stop doing analytics. + */ +- (void)stop; + +/** + Track a screen display. + + @param screenName the name of the displayed screen. + */ +- (void)trackScreen:(NSString*)screenName; + +/** + Flush analytics data. + */ +- (void)dispatch; + +@end diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m new file mode 100644 index 000000000..9fe2d460a --- /dev/null +++ b/Riot/Analytics/Analytics.m @@ -0,0 +1,105 @@ +/* + Copyright 2018 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 "Analytics.h" + +#import "AppDelegate.h" + +@import PiwikTracker; + +@implementation Analytics + ++ (instancetype)sharedInstance +{ + static Analytics *sharedInstance = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + sharedInstance = [[Analytics alloc] init]; + }); + + return sharedInstance; +} + +- (void)start +{ + NSDictionary *piwikConfig = [[NSUserDefaults standardUserDefaults] objectForKey:@"piwik"]; + [PiwikTracker configureSharedInstanceWithSiteID:piwikConfig[@"siteId"] + baseURL:[NSURL URLWithString:piwikConfig[@"url"]] + userAgent:@"iOSPiwikTracker"]; + + // Check whether the user has enabled the sending of crash reports. + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]) + { + [PiwikTracker shared].isOptedOut = NO; + + [[PiwikTracker shared] setCustomVariableWithIndex:1 name:@"App Platform" value:@"iOS Platform"]; + [[PiwikTracker shared] setCustomVariableWithIndex:2 name:@"App Version" value:[AppDelegate theDelegate].appVersion]; + + // The language is either the one selected by the user within the app + // or, else, the one configured by the OS + NSString *language = [NSBundle mxk_language] ? [NSBundle mxk_language] : [[NSBundle mainBundle] preferredLocalizations][0]; + [[PiwikTracker shared] setCustomVariableWithIndex:4 name:@"Chosen Language" value:language]; + + MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + if (account) + { + [[PiwikTracker shared] setCustomVariableWithIndex:7 name:@"Homeserver URL" value:account.mxCredentials.homeServer]; + [[PiwikTracker shared] setCustomVariableWithIndex:8 name:@"Identity Server URL" value:account.identityServerURL]; + } + + // TODO: We should also track device and os version + // But that needs to be decided for all platforms + + // Catch and log crashes + [MXLogger logCrashes:YES]; + [MXLogger setBuildVersion:[AppDelegate theDelegate].build]; + +#ifdef DEBUG + // Disable analytics in debug as it pollutes stats + [PiwikTracker shared].isOptedOut = YES; +#endif + } + else if ([[NSUserDefaults standardUserDefaults] objectForKey:@"enableCrashReport"]) + { + NSLog(@"[AppDelegate] The user decided to not "); + [PiwikTracker shared].isOptedOut = YES; + [MXLogger logCrashes:NO]; + } +} + +- (void)stop +{ + [PiwikTracker shared].isOptedOut = YES; + [MXLogger logCrashes:NO]; +} + +- (void)trackScreen:(NSString *)screenName +{ + // Use the same pattern as Android + NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"]; + NSString *appVersion = [AppDelegate theDelegate].appVersion; + + [[PiwikTracker shared] trackWithView:@[@"ios", appName, appVersion, screenName] + url:nil]; +} + +- (void)dispatch +{ + [[PiwikTracker shared] dispatch]; +} + +@end diff --git a/Riot/AppDelegate.h b/Riot/AppDelegate.h index ede68dacd..305650eab 100644 --- a/Riot/AppDelegate.h +++ b/Riot/AppDelegate.h @@ -22,6 +22,7 @@ #import "JitsiViewController.h" #import "RageShakeManager.h" +#import "Analytics.h" #import "RiotDesignValues.h" @@ -128,12 +129,6 @@ extern NSString *const kAppDelegateNetworkStatusDidChangeNotification; - (void)selectMatrixAccount:(void (^)(MXKAccount *selectedAccount))onSelection; -#pragma mark - Analytics - -- (void)startAnalytics; -- (void)stopAnalytics; -- (void)trackScreen:(NSString*)screenName; - #pragma mark - Push notifications - (void)registerUserNotificationSettings; diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 5ced25b79..07386ee4b 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -48,8 +48,6 @@ #import "WebViewViewController.h" -@import PiwikTracker; - // Calls #import "CallViewController.h" @@ -235,7 +233,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN MXSDKOptions *sdkOptions = [MXSDKOptions sharedInstance]; sdkOptions.applicationGroupIdentifier = @"group.im.vector"; - // Track SDK performance on Google analytics + // Track SDK performance our analytics // TODO: needs the same tool //sdkOptions.analyticsDelegate = [[MXGoogleAnalytics alloc] init]; @@ -468,8 +466,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; [[NSUserDefaults standardUserDefaults] synchronize]; - // Configure Google Analytics here if the option is enabled - [self startAnalytics]; + // Configure our analytics. It will indeed start if the option is enabled + [[Analytics sharedInstance] start]; // Prepare Pushkit handling _incomingPushEventIds = [NSMutableDictionary dictionary]; @@ -563,7 +561,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN _isAppForeground = NO; // Analytics: Force to send the pending actions - [[PiwikTracker shared] dispatch]; + [[Analytics sharedInstance] dispatch]; } - (void)applicationWillEnterForeground:(UIApplication *)application @@ -1026,70 +1024,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } } -#pragma mark - Analytics - -- (void)startAnalytics -{ - NSDictionary *piwikConfig = [[NSUserDefaults standardUserDefaults] objectForKey:@"piwik"]; - [PiwikTracker configureSharedInstanceWithSiteID:piwikConfig[@"siteId"] - baseURL:[NSURL URLWithString:piwikConfig[@"url"]] - userAgent:@"iOSPiwikTracker"]; - - // Check whether the user has enabled the sending of crash reports. - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]) - { - [PiwikTracker shared].isOptedOut = NO; - - [[PiwikTracker shared] setCustomVariableWithIndex:1 name:@"App Platform" value:@"iOS Platform"]; - [[PiwikTracker shared] setCustomVariableWithIndex:2 name:@"App Version" value:[self appVersion]]; - - // The language is either the one selected by the user within the app - // or, else, the one configured by the OS - NSString *language = [NSBundle mxk_language] ? [NSBundle mxk_language] : [[NSBundle mainBundle] preferredLocalizations][0]; - [[PiwikTracker shared] setCustomVariableWithIndex:4 name:@"Chosen Language" value:language]; - - MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject; - if (account) - { - [[PiwikTracker shared] setCustomVariableWithIndex:7 name:@"Homeserver URL" value:account.mxCredentials.homeServer]; - [[PiwikTracker shared] setCustomVariableWithIndex:8 name:@"Identity Server URL" value:account.identityServerURL]; - } - - // TODO: We should also track device and os version - // But that needs to be decided for all platforms - - // Catch and log crashes - [MXLogger logCrashes:YES]; - [MXLogger setBuildVersion:[AppDelegate theDelegate].build]; - -#ifdef DEBUG - // Disable analytics in debug as it pollutes stats - [PiwikTracker shared].isOptedOut = YES; -#endif - } - else if ([[NSUserDefaults standardUserDefaults] objectForKey:@"enableCrashReport"]) - { - NSLog(@"[AppDelegate] The user decided to not "); - [PiwikTracker shared].isOptedOut = YES; - [MXLogger logCrashes:NO]; - } -} - -- (void)stopAnalytics -{ - [PiwikTracker shared].isOptedOut = YES; - [MXLogger logCrashes:NO]; -} - -- (void)trackScreen:(NSString *)screenName -{ - // Use the same pattern as Android - NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"]; - NSString *appVersion = [self appVersion]; - - [[PiwikTracker shared] trackWithView:@[@"ios", appName, appVersion, screenName] - url:nil]; -} +#pragma mark - Crash handling // Check if there is a crash log to send to server - (void)checkExceptionToReport diff --git a/Riot/ViewController/AttachmentsViewController.m b/Riot/ViewController/AttachmentsViewController.m index 77a3afdb9..72f2dd5b0 100644 --- a/Riot/ViewController/AttachmentsViewController.m +++ b/Riot/ViewController/AttachmentsViewController.m @@ -73,7 +73,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"AttachmentsViewer"]; + [[Analytics sharedInstance] trackScreen:@"AttachmentsViewer"]; } - (void)destroy diff --git a/Riot/ViewController/AuthenticationViewController.m b/Riot/ViewController/AuthenticationViewController.m index 889a922df..47d6ffd64 100644 --- a/Riot/ViewController/AuthenticationViewController.m +++ b/Riot/ViewController/AuthenticationViewController.m @@ -193,7 +193,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"Authentication"]; + [[Analytics sharedInstance] trackScreen:@"Authentication"]; } - (void)viewDidAppear:(BOOL)animated diff --git a/Riot/ViewController/Communities/GroupDetailsViewController.m b/Riot/ViewController/Communities/GroupDetailsViewController.m index 95c2635ac..08bf19492 100644 --- a/Riot/ViewController/Communities/GroupDetailsViewController.m +++ b/Riot/ViewController/Communities/GroupDetailsViewController.m @@ -135,7 +135,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"GroupDetails"]; + [[Analytics sharedInstance] trackScreen:@"GroupDetails"]; } - (void)viewWillDisappear:(BOOL)animated diff --git a/Riot/ViewController/Communities/GroupHomeViewController.m b/Riot/ViewController/Communities/GroupHomeViewController.m index 983710c56..88ab6533b 100644 --- a/Riot/ViewController/Communities/GroupHomeViewController.m +++ b/Riot/ViewController/Communities/GroupHomeViewController.m @@ -182,7 +182,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"GroupDetailsHome"]; + [[Analytics sharedInstance] trackScreen:@"GroupDetailsHome"]; // Release the potential pushed view controller [self releasePushedViewController]; diff --git a/Riot/ViewController/Communities/GroupParticipantsViewController.m b/Riot/ViewController/Communities/GroupParticipantsViewController.m index 8b20b8369..ef7ba2360 100644 --- a/Riot/ViewController/Communities/GroupParticipantsViewController.m +++ b/Riot/ViewController/Communities/GroupParticipantsViewController.m @@ -217,7 +217,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"GroupDetailsPeople"]; + [[Analytics sharedInstance] trackScreen:@"GroupDetailsPeople"]; // Release the potential pushed view controller [self releasePushedViewController]; diff --git a/Riot/ViewController/Communities/GroupRoomsViewController.m b/Riot/ViewController/Communities/GroupRoomsViewController.m index 0a11ef080..9d2e0bfe1 100644 --- a/Riot/ViewController/Communities/GroupRoomsViewController.m +++ b/Riot/ViewController/Communities/GroupRoomsViewController.m @@ -181,7 +181,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"GroupDetailsRooms"]; + [[Analytics sharedInstance] trackScreen:@"GroupDetailsRooms"]; // Release the potential pushed view controller [self releasePushedViewController]; diff --git a/Riot/ViewController/Communities/GroupsViewController.m b/Riot/ViewController/Communities/GroupsViewController.m index cde207edb..a96ead33f 100644 --- a/Riot/ViewController/Communities/GroupsViewController.m +++ b/Riot/ViewController/Communities/GroupsViewController.m @@ -186,7 +186,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"Groups"]; + [[Analytics sharedInstance] trackScreen:@"Groups"]; // Deselect the current selected row, it will be restored on viewDidAppear (if any) NSIndexPath *indexPath = [self.groupsTableView indexPathForSelectedRow]; diff --git a/Riot/ViewController/ContactDetailsViewController.m b/Riot/ViewController/ContactDetailsViewController.m index 0bf37eeed..ed477c040 100644 --- a/Riot/ViewController/ContactDetailsViewController.m +++ b/Riot/ViewController/ContactDetailsViewController.m @@ -263,7 +263,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"ContactDetails"]; + [[Analytics sharedInstance] trackScreen:@"ContactDetails"]; // Hide the bottom border of the navigation bar to display the expander header [self hideNavigationBarBorder:YES]; diff --git a/Riot/ViewController/ContactsTableViewController.h b/Riot/ViewController/ContactsTableViewController.h index 521f8be81..a196bd788 100644 --- a/Riot/ViewController/ContactsTableViewController.h +++ b/Riot/ViewController/ContactsTableViewController.h @@ -73,7 +73,7 @@ @property (nonatomic) BOOL shouldScrollToTopOnRefresh; /** - The Google Analytics Instance screen name (Default is "ContactsTable"). + The analytics instance screen name (Default is "ContactsTable"). */ @property (nonatomic) NSString *screenName; diff --git a/Riot/ViewController/ContactsTableViewController.m b/Riot/ViewController/ContactsTableViewController.m index 842a208e1..c5f199fd5 100644 --- a/Riot/ViewController/ContactsTableViewController.m +++ b/Riot/ViewController/ContactsTableViewController.m @@ -144,7 +144,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:_screenName]; + [[Analytics sharedInstance] trackScreen:_screenName]; // Check whether the access to the local contacts has not been already asked. if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) diff --git a/Riot/ViewController/CountryPickerViewController.m b/Riot/ViewController/CountryPickerViewController.m index 881295893..1c0a2fa40 100644 --- a/Riot/ViewController/CountryPickerViewController.m +++ b/Riot/ViewController/CountryPickerViewController.m @@ -99,7 +99,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"CountryPicker"]; + [[Analytics sharedInstance] trackScreen:@"CountryPicker"]; } - (void)destroy diff --git a/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.m b/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.m index a8fe4b6ca..dfbd4f8ca 100644 --- a/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.m +++ b/Riot/ViewController/DeactivateAccount/DeactivateAccountViewController.m @@ -96,7 +96,7 @@ static CGFloat const kTextFontSize = 15.0; [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"DeactivateAccount"]; + [[Analytics sharedInstance] trackScreen:@"DeactivateAccount"]; } - (void)viewDidLayoutSubviews diff --git a/Riot/ViewController/DirectoryServerPickerViewController.m b/Riot/ViewController/DirectoryServerPickerViewController.m index 22f33a7f2..a7450b622 100644 --- a/Riot/ViewController/DirectoryServerPickerViewController.m +++ b/Riot/ViewController/DirectoryServerPickerViewController.m @@ -143,7 +143,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"DirectoryServerPicker"]; + [[Analytics sharedInstance] trackScreen:@"DirectoryServerPicker"]; // Observe kAppDelegateDidTapStatusBarNotificationObserver. kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { diff --git a/Riot/ViewController/DirectoryViewController.m b/Riot/ViewController/DirectoryViewController.m index 5bd12e113..90bb1bfd5 100644 --- a/Riot/ViewController/DirectoryViewController.m +++ b/Riot/ViewController/DirectoryViewController.m @@ -105,7 +105,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"Directory"]; + [[Analytics sharedInstance] trackScreen:@"Directory"]; // Observe kAppDelegateDidTapStatusBarNotificationObserver. kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { diff --git a/Riot/ViewController/HomeFilesSearchViewController.m b/Riot/ViewController/HomeFilesSearchViewController.m index 83235f5bb..6cf51a715 100644 --- a/Riot/ViewController/HomeFilesSearchViewController.m +++ b/Riot/ViewController/HomeFilesSearchViewController.m @@ -107,7 +107,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"FilesGlobalSearch"]; + [[Analytics sharedInstance] trackScreen:@"FilesGlobalSearch"]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshSearchResult:) name:kMXSessionDidLeaveRoomNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshSearchResult:) name:kMXSessionNewRoomNotification object:nil]; diff --git a/Riot/ViewController/HomeMessagesSearchViewController.m b/Riot/ViewController/HomeMessagesSearchViewController.m index ac1544db3..d239acbc6 100644 --- a/Riot/ViewController/HomeMessagesSearchViewController.m +++ b/Riot/ViewController/HomeMessagesSearchViewController.m @@ -114,7 +114,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"MessagesGlobalSearch"]; + [[Analytics sharedInstance] trackScreen:@"MessagesGlobalSearch"]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshSearchResult:) name:kMXSessionDidLeaveRoomNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshSearchResult:) name:kMXSessionNewRoomNotification object:nil]; diff --git a/Riot/ViewController/LanguagePickerViewController.m b/Riot/ViewController/LanguagePickerViewController.m index 0a64838e7..ef3ac56d8 100644 --- a/Riot/ViewController/LanguagePickerViewController.m +++ b/Riot/ViewController/LanguagePickerViewController.m @@ -109,7 +109,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"CountryPicker"]; + [[Analytics sharedInstance] trackScreen:@"CountryPicker"]; } - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath; diff --git a/Riot/ViewController/MasterTabBarController.m b/Riot/ViewController/MasterTabBarController.m index 3b2bd62fe..31d4605ff 100644 --- a/Riot/ViewController/MasterTabBarController.m +++ b/Riot/ViewController/MasterTabBarController.m @@ -810,8 +810,8 @@ typeof(self) self = weakSelf; self->currentAlert = nil; } - - [[AppDelegate theDelegate] startAnalytics]; + + [[Analytics sharedInstance] start]; }]]; diff --git a/Riot/ViewController/MediaAlbumContentViewController.m b/Riot/ViewController/MediaAlbumContentViewController.m index 025a2e54f..4ed3f011f 100644 --- a/Riot/ViewController/MediaAlbumContentViewController.m +++ b/Riot/ViewController/MediaAlbumContentViewController.m @@ -157,7 +157,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"MediaAlbumContent"]; + [[Analytics sharedInstance] trackScreen:@"MediaAlbumContent"]; self.navigationItem.title = _assetsCollection.localizedTitle; diff --git a/Riot/ViewController/MediaPickerViewController.m b/Riot/ViewController/MediaPickerViewController.m index b81f5b34f..f0f30b847 100644 --- a/Riot/ViewController/MediaPickerViewController.m +++ b/Riot/ViewController/MediaPickerViewController.m @@ -236,7 +236,7 @@ static void *RecordingContext = &RecordingContext; [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"MediaPicker"]; + [[Analytics sharedInstance] trackScreen:@"MediaPicker"]; if (!userAlbumsQueue) { diff --git a/Riot/ViewController/RecentsViewController.h b/Riot/ViewController/RecentsViewController.h index 09117f31d..6fefeed34 100644 --- a/Riot/ViewController/RecentsViewController.h +++ b/Riot/ViewController/RecentsViewController.h @@ -79,7 +79,7 @@ @property (nonatomic) CGFloat stickyHeaderHeight; /** - The Google Analytics Instance screen name (Default is "RecentsScreen"). + The analytics instance screen name (Default is "RecentsScreen"). */ @property (nonatomic) NSString *screenName; diff --git a/Riot/ViewController/RecentsViewController.m b/Riot/ViewController/RecentsViewController.m index 24b8d97db..8bb715eaa 100644 --- a/Riot/ViewController/RecentsViewController.m +++ b/Riot/ViewController/RecentsViewController.m @@ -231,7 +231,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:_screenName]; + [[Analytics sharedInstance] trackScreen:_screenName]; // Deselect the current selected row, it will be restored on viewDidAppear (if any) NSIndexPath *indexPath = [self.recentsTableView indexPathForSelectedRow]; diff --git a/Riot/ViewController/RoomFilesSearchViewController.m b/Riot/ViewController/RoomFilesSearchViewController.m index 6973cde1c..a710dc8cb 100644 --- a/Riot/ViewController/RoomFilesSearchViewController.m +++ b/Riot/ViewController/RoomFilesSearchViewController.m @@ -108,7 +108,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"RoomFilesSearch"]; + [[Analytics sharedInstance] trackScreen:@"RoomFilesSearch"]; // Observe kAppDelegateDidTapStatusBarNotificationObserver. kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { diff --git a/Riot/ViewController/RoomMemberDetailsViewController.m b/Riot/ViewController/RoomMemberDetailsViewController.m index d7b9ecf94..f0c78e61f 100644 --- a/Riot/ViewController/RoomMemberDetailsViewController.m +++ b/Riot/ViewController/RoomMemberDetailsViewController.m @@ -251,7 +251,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"RoomMemberDetails"]; + [[Analytics sharedInstance] trackScreen:@"RoomMemberDetails"]; // Hide the bottom border of the navigation bar to display the expander header [self hideNavigationBarBorder:YES]; diff --git a/Riot/ViewController/RoomMessagesSearchViewController.m b/Riot/ViewController/RoomMessagesSearchViewController.m index 7ac1b8031..f152865d4 100644 --- a/Riot/ViewController/RoomMessagesSearchViewController.m +++ b/Riot/ViewController/RoomMessagesSearchViewController.m @@ -109,7 +109,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"RoomMessagesSearch"]; + [[Analytics sharedInstance] trackScreen:@"RoomMessagesSearch"]; // Observe kAppDelegateDidTapStatusBarNotificationObserver. kAppDelegateDidTapStatusBarNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kAppDelegateDidTapStatusBarNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { diff --git a/Riot/ViewController/RoomParticipantsViewController.m b/Riot/ViewController/RoomParticipantsViewController.m index 4b83342aa..c6d76ffeb 100644 --- a/Riot/ViewController/RoomParticipantsViewController.m +++ b/Riot/ViewController/RoomParticipantsViewController.m @@ -245,7 +245,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"RoomParticipants"]; + [[Analytics sharedInstance] trackScreen:@"RoomParticipants"]; if (memberDetailsViewController) { diff --git a/Riot/ViewController/RoomSearchViewController.m b/Riot/ViewController/RoomSearchViewController.m index ba5367be1..19d50a700 100644 --- a/Riot/ViewController/RoomSearchViewController.m +++ b/Riot/ViewController/RoomSearchViewController.m @@ -101,7 +101,7 @@ } // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"RoomsSearch"]; + [[Analytics sharedInstance] trackScreen:@"RoomsSearch"]; // Enable the search field by default at the screen opening if (self.searchBarHidden) diff --git a/Riot/ViewController/RoomSettingsViewController.m b/Riot/ViewController/RoomSettingsViewController.m index 279b6edd3..bfb2c105f 100644 --- a/Riot/ViewController/RoomSettingsViewController.m +++ b/Riot/ViewController/RoomSettingsViewController.m @@ -289,7 +289,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"RoomSettings"]; + [[Analytics sharedInstance] trackScreen:@"RoomSettings"]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateRules:) name:kMXNotificationCenterDidUpdateRules object:nil]; diff --git a/Riot/ViewController/RoomViewController.m b/Riot/ViewController/RoomViewController.m index 325e63ff1..eba5abf36 100644 --- a/Riot/ViewController/RoomViewController.m +++ b/Riot/ViewController/RoomViewController.m @@ -450,7 +450,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"ChatRoom"]; + [[Analytics sharedInstance] trackScreen:@"ChatRoom"]; // Refresh the room title view [self refreshRoomTitle]; diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index 5c7e2d5d5..ee3685927 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -423,7 +423,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"Settings"]; + [[Analytics sharedInstance] trackScreen:@"Settings"]; // Release the potential pushed view controller [self releasePushedViewController]; @@ -2854,7 +2854,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"enableCrashReport"]; [[NSUserDefaults standardUserDefaults] synchronize]; - [[AppDelegate theDelegate] stopAnalytics]; + [[Analytics sharedInstance] stop]; // Remove potential crash file. [MXLogger deleteCrashLog]; @@ -2865,7 +2865,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"enableCrashReport"]; [[NSUserDefaults standardUserDefaults] synchronize]; - [[AppDelegate theDelegate] startAnalytics]; + [[Analytics sharedInstance] start]; } } diff --git a/Riot/ViewController/UnifiedSearchViewController.m b/Riot/ViewController/UnifiedSearchViewController.m index 79149cb4a..3d6145a67 100644 --- a/Riot/ViewController/UnifiedSearchViewController.m +++ b/Riot/ViewController/UnifiedSearchViewController.m @@ -137,7 +137,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"UnifiedSearch"]; + [[Analytics sharedInstance] trackScreen:@"UnifiedSearch"]; // Let's child display the loading not the home view controller if (self.activityIndicator) diff --git a/Riot/ViewController/UsersDevicesViewController.m b/Riot/ViewController/UsersDevicesViewController.m index 4241c60c4..b2847f6ac 100644 --- a/Riot/ViewController/UsersDevicesViewController.m +++ b/Riot/ViewController/UsersDevicesViewController.m @@ -116,7 +116,7 @@ [super viewWillAppear:animated]; // Screen tracking - [[AppDelegate theDelegate] trackScreen:@"UnknowDevices"]; + [[Analytics sharedInstance] trackScreen:@"UnknowDevices"]; [self.tableView reloadData]; } From 52b2f03c2f8e5b98c2aeca3abbc5d5808012223f Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 27 Jun 2018 10:43:22 +0200 Subject: [PATCH 28/54] Analytics: clean references to GA as we do not use it anymore --- Riot/ViewController/MasterTabBarController.m | 6 +++--- Riot/ViewController/SettingsViewController.m | 4 ++-- Riot/third_party_licenses.html | 13 ------------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/Riot/ViewController/MasterTabBarController.m b/Riot/ViewController/MasterTabBarController.m index 31d4605ff..fb3458f33 100644 --- a/Riot/ViewController/MasterTabBarController.m +++ b/Riot/ViewController/MasterTabBarController.m @@ -148,7 +148,7 @@ // (Check whether 'enableCrashReport' flag has been set once) if (![[NSUserDefaults standardUserDefaults] objectForKey:@"enableCrashReport"]) { - [self promptUserBeforeUsingGoogleAnalytics]; + [self promptUserBeforeUsingAnalytics]; } [self refreshTabBarBadges]; @@ -771,7 +771,7 @@ #pragma mark - -- (void)promptUserBeforeUsingGoogleAnalytics +- (void)promptUserBeforeUsingAnalytics { NSLog(@"[MasterTabBarController]: Invite the user to send crash reports"); @@ -815,7 +815,7 @@ }]]; - [currentAlert mxk_setAccessibilityIdentifier: @"HomeVCUseGoogleAnalyticsAlert"]; + [currentAlert mxk_setAccessibilityIdentifier: @"HomeVCUseAnalyticsAlert"]; [self presentViewController:currentAlert animated:YES completion:nil]; } diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index ee3685927..7385bb0d2 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -2850,7 +2850,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); BOOL enable = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]; if (enable) { - NSLog(@"[SettingsViewController] disable automatic crash report sending"); + NSLog(@"[SettingsViewController] disable automatic crash report and analytics sending"); [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"enableCrashReport"]; [[NSUserDefaults standardUserDefaults] synchronize]; @@ -2861,7 +2861,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } else { - NSLog(@"[SettingsViewController] enable automatic crash report sending"); + NSLog(@"[SettingsViewController] enable automatic crash report and analytics sending"); [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"enableCrashReport"]; [[NSUserDefaults standardUserDefaults] synchronize]; diff --git a/Riot/third_party_licenses.html b/Riot/third_party_licenses.html index 13163b0d5..b1f0e155b 100644 --- a/Riot/third_party_licenses.html +++ b/Riot/third_party_licenses.html @@ -114,19 +114,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-
  • - GoogleAnalytics (https://www.google.com/analytics) -

    Measure your app performance. -

    Copyright (c) 2011-2016 Google Inc. All rights reserved. -

    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License at: -

    https://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. -

    Google Analytics Terms of Service: https://www.google.com/analytics/terms -

    -
  • GZIP (https://github.com/nicklockwood/GZIP) From c128845bffd489f8b068551e9941119b49fb8755 Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 27 Jun 2018 11:00:26 +0200 Subject: [PATCH 29/54] Analytics: Make sure that Analytics is opt-out Note it was already opt-out because the code elsewhere ensures that but this this is better to ensure it here. --- Riot/Analytics/Analytics.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m index 9fe2d460a..ae84610e5 100644 --- a/Riot/Analytics/Analytics.m +++ b/Riot/Analytics/Analytics.m @@ -73,9 +73,9 @@ [PiwikTracker shared].isOptedOut = YES; #endif } - else if ([[NSUserDefaults standardUserDefaults] objectForKey:@"enableCrashReport"]) + else { - NSLog(@"[AppDelegate] The user decided to not "); + NSLog(@"[AppDelegate] The user decided to not send analytics"); [PiwikTracker shared].isOptedOut = YES; [MXLogger logCrashes:NO]; } From d2fe94d9dc89d6dbd2d672f3d11c290696b28a32 Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 27 Jun 2018 17:57:40 +0200 Subject: [PATCH 30/54] Analytics: Make it implement MXAnalyticsDelegate to track performance stats --- CHANGES.rst | 5 +-- Riot/Analytics/Analytics.h | 11 ++++++- Riot/Analytics/Analytics.m | 63 ++++++++++++++++++++++++++++++++++++++ Riot/AppDelegate.m | 8 +++-- 4 files changed, 82 insertions(+), 5 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index e5c64d9c1..ddc68648a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,8 +4,9 @@ Changes in 0.6.18 () Improvements: * Upgrade MatrixKit version (). * RoomVC: Add a re-request keys button on message unable to decrypt (#1879). - * Analytics: Move code from AppDelegate to a dedicated class: Analytics - + * Analytics: Move code from AppDelegate to a dedicated class: Analytics. + * Analytics: Track Matrix SDK stats (time to startup the app). + Bug fix: Changes in 0.6.17 (2018-06-01) diff --git a/Riot/Analytics/Analytics.h b/Riot/Analytics/Analytics.h index 72f493c0a..d6b29b595 100644 --- a/Riot/Analytics/Analytics.h +++ b/Riot/Analytics/Analytics.h @@ -16,10 +16,12 @@ #import +#import + /** `Analytics` sends analytics to an analytics tool. */ -@interface Analytics : NSObject +@interface Analytics : NSObject /** Returns the shared Analytics manager. @@ -50,4 +52,11 @@ */ - (void)dispatch; +/** + Track how long the launch screen has been displayed to the end user. + + @param seconds the duration in seconds. + */ +- (void)trackLaunchScreenDisplayDuration: (NSTimeInterval)seconds; + @end diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m index ae84610e5..27d82fdb3 100644 --- a/Riot/Analytics/Analytics.m +++ b/Riot/Analytics/Analytics.m @@ -18,6 +18,12 @@ #import "AppDelegate.h" +// All metrics are store under a Piwik category called "Metrics" +// Then, there are 2 (for the moment) Piwik actions: "iOS.startup" and "iOS.stats" +// Then, we use constants defined by the Matrix SDK as Piwik Names (ex:"mountData") +NSString *const kAnalyticsPiwikMetricsCategory = @"Metrics"; +NSString *const kAnalyticsPiwikMetricsActionPattern = @"iOS.%@"; + @import PiwikTracker; @implementation Analytics @@ -102,4 +108,61 @@ [[PiwikTracker shared] dispatch]; } +- (void)trackLaunchScreenDisplayDuration:(NSTimeInterval)seconds +{ + NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory]; + + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + action:action + name:kMXAnalyticsStartupLaunchScreen + number:@(seconds * 1000) + url:nil]; +} + +#pragma mark - MXAnalyticsDelegate + +- (void)trackStartupStorePreloadDuration: (NSTimeInterval)seconds +{ + NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory]; + + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + action:action + name:kMXAnalyticsStartupStorePreload + number:@(seconds * 1000) + url:nil]; +} + +- (void)trackStartupMountDataDuration: (NSTimeInterval)seconds +{ + NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory]; + + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + action:action + name:kMXAnalyticsStartupMountData + number:@(seconds * 1000) + url:nil]; +} + +- (void)trackStartupSyncDuration: (NSTimeInterval)seconds isInitial: (BOOL)isInitial +{ + NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory]; + + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + action:action + name:isInitial ? kMXAnalyticsStartupInititialSync : kMXAnalyticsStartupIncrementalSync + number:@(seconds * 1000) + url:nil]; +} + +- (void)trackRoomCount: (NSUInteger)roomCount +{ + NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStatsCategory]; + + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + action:action + name:kMXAnalyticsStatsRooms + number:@(roomCount) + url:nil]; +} + @end diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 07386ee4b..1bae82da3 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -467,6 +467,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [[NSUserDefaults standardUserDefaults] synchronize]; // Configure our analytics. It will indeed start if the option is enabled + [MXSDKOptions sharedInstance].analyticsDelegate = [Analytics sharedInstance]; [[Analytics sharedInstance] start]; // Prepare Pushkit handling @@ -2849,8 +2850,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN if (launchAnimationContainerView) { - NSTimeInterval durationMs = [[NSDate date] timeIntervalSinceDate:launchAnimationStart] * 1000; - NSLog(@"[AppDelegate] LaunchAnimation was shown for %.3fms", durationMs); + NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:launchAnimationStart]; + NSLog(@"[AppDelegate] LaunchAnimation was shown for %.3fms", duration * 1000); + + // Track it on our analytics + [[Analytics sharedInstance] trackLaunchScreenDisplayDuration:duration]; // TODO: Send durationMs to Piwik // Such information should be the same on all platforms From 8f0efd34da8b04288e66926ba968cdded6fc8c97 Mon Sep 17 00:00:00 2001 From: manuroe Date: Wed, 27 Jun 2018 18:11:04 +0200 Subject: [PATCH 31/54] Analytics: Improve comments --- Riot/Analytics/Analytics.m | 5 +++-- Riot/AppDelegate.m | 4 ---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m index 27d82fdb3..ad8068266 100644 --- a/Riot/Analytics/Analytics.m +++ b/Riot/Analytics/Analytics.m @@ -18,8 +18,9 @@ #import "AppDelegate.h" -// All metrics are store under a Piwik category called "Metrics" -// Then, there are 2 (for the moment) Piwik actions: "iOS.startup" and "iOS.stats" +// All metrics are store under a Piwik category called "Metrics". +// Then, there are 2 Piwik actions: "iOS.startup" and "iOS.stats" (these actions +// are namespaced by plaform to have a nice rendering on the Piwik website). // Then, we use constants defined by the Matrix SDK as Piwik Names (ex:"mountData") NSString *const kAnalyticsPiwikMetricsCategory = @"Metrics"; NSString *const kAnalyticsPiwikMetricsActionPattern = @"iOS.%@"; diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 1bae82da3..1ad79e6fc 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -233,10 +233,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN MXSDKOptions *sdkOptions = [MXSDKOptions sharedInstance]; sdkOptions.applicationGroupIdentifier = @"group.im.vector"; - // Track SDK performance our analytics - // TODO: needs the same tool - //sdkOptions.analyticsDelegate = [[MXGoogleAnalytics alloc] init]; - // Redirect NSLogs to files only if we are not debugging if (!isatty(STDERR_FILENO)) { From fb8fba2e5a66843693d2f6bbba521a6a0bcaea73 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Thu, 28 Jun 2018 10:18:36 +0200 Subject: [PATCH 32/54] Added titles to sound files ID3 tags in order to avoid system exception --- CHANGES.rst | 1 + Riot/Assets/Sounds/busy.mp3 | Bin 24834 -> 26051 bytes Riot/Assets/Sounds/message.mp3 | Bin 12627 -> 13807 bytes Riot/Assets/Sounds/ring.mp3 | Bin 19662 -> 20879 bytes Riot/Assets/Sounds/ringback.mp3 | Bin 18398 -> 19629 bytes 5 files changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index c3260eef6..55072c49e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,7 @@ Improvements: * Analytics: Move code from AppDelegate to a dedicated class: Analytics. * Analytics: Track Matrix SDK stats (time to startup the app). * Added the i18n localisation strings to the accessibility labels (#1842), thanks to @einMarco (PR#1906). + * Added titles to sound files ID3 tags. Bug fix: * RoomVC: Read receipts processing dramatically slows down UI (#1899). diff --git a/Riot/Assets/Sounds/busy.mp3 b/Riot/Assets/Sounds/busy.mp3 index fec27ba4c5952980bf43e83fc52203af300b02a2..0c1e4dedbd1361da571f77456f4023c2f738749e 100644 GIT binary patch delta 1241 zcmZoV#CZ5LW4)(~F$)6_aHNC;2fG3pd<+cCK8a;%rlxu(7J7yT1|gmyMnG{^Aa*J( zt_*SYbA~8mKvfnI5djpJ24W9KKNla@pm;w=UsqH`KuJ_kkIJPxZ`6Le2RVv`qv4Md h9CYWz)7Zv|XCyc3UrxvfadZb29yGR%fnnkq2>=IZBy9iy delta 36 ocmX?nnz88+qo}8gF$)6-D2D_Gy8>x`1_tJdi4vRhSgs}j0HFj3h5!Hn diff --git a/Riot/Assets/Sounds/message.mp3 b/Riot/Assets/Sounds/message.mp3 index b87eeda7c2d720ea6d59bd1743642fba0cced0d2..c857ee7b1612a6fb8a511b110a79ef114f243cd5 100644 GIT binary patch delta 67 zcmcbd^gdh0)5VyD0SGvRLOer^Knx)EO)V}?Oi!J7@WI3j7h!1ahG0Xk5Jz{oWGUl+ E0PkfP_5c6? delta 17 ZcmaE#eL0Ec|L+MY6BQLUJFw^*0svFD2de-8 diff --git a/Riot/Assets/Sounds/ring.mp3 b/Riot/Assets/Sounds/ring.mp3 index 3c3cdde3f9c5695063a0eaaabf1b995ee24702bf..c02e24625f4b468a66aa981302739aea064c90dc 100644 GIT binary patch delta 1241 zcmX>%ld*p>W4)(~F$)6_aHNC;2fG3pd<+cCK8a;%rlxu(7J7yT1|gmyMnG{^AP&mR zOAm4NbA~8mKvfnI5djpJ24W9KKNla@pm;w=UsqH`KuJ_kkIJPxZ`6Le2RVv`qv4Md h9CYWz)7Zv|XCyc3&-cj)adZb29yGR%fnnkq2>^B@BgOy# delta 36 ocmeBQ%y@1lqo}8gF$)6-D2D_Gy8>x`1_tJdi4vRhSQh#K0GMnD1poj5 diff --git a/Riot/Assets/Sounds/ringback.mp3 b/Riot/Assets/Sounds/ringback.mp3 index 6ee34bf3953c5ec94dfecce2fa5bfc6756ed4732..c56252c1f7237691cb0f7a54be39b2172e9f82ac 100644 GIT binary patch delta 1292 zcmccD&$xCbW4)(~F$)6_aAbr82fG3pd<+cCK8a;%rY3r3#(IVZCLx|7MnG{+AP&mR zOHWEn&JJ<)bA~8oKvfzM5djpJ24W9KKNla@pm;w=UsqH`KuH9sM=%G3HEREW1UuZ) k(eQ@{#egsdF#P}jb~wPWQDd8XeTbtwtYjI8Kw$h20ATGXTL1t6 delta 46 xcmZ2Glkr|ZqmrkKF$)6-NQMLly8>x`1_oxI#IiI~6FoCyJwpSN&4ny`+yU}o3Vi?o From 1cd52b0b67f2454f3ddf6bc2bb6698f7288e17e0 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Jun 2018 07:35:31 +0200 Subject: [PATCH 33/54] Crypto: Add telemetry for events unable to decrypt (UTDs) #1894 --- CHANGES.rst | 1 + Riot.xcodeproj/project.pbxproj | 12 ++ Riot/Analytics/Analytics.h | 3 +- Riot/Analytics/Analytics.m | 15 +++ Riot/Analytics/DecryptionFailure.h | 39 ++++++ Riot/Analytics/DecryptionFailure.m | 31 +++++ Riot/Analytics/DecryptionFailureTracker.h | 64 ++++++++++ Riot/Analytics/DecryptionFailureTracker.m | 138 ++++++++++++++++++++++ Riot/AppDelegate.m | 1 + Riot/Utils/EventFormatter.m | 55 +++++---- 10 files changed, 335 insertions(+), 24 deletions(-) create mode 100644 Riot/Analytics/DecryptionFailure.h create mode 100644 Riot/Analytics/DecryptionFailure.m create mode 100644 Riot/Analytics/DecryptionFailureTracker.h create mode 100644 Riot/Analytics/DecryptionFailureTracker.m diff --git a/CHANGES.rst b/CHANGES.rst index 55072c49e..fbbdeb7d1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,6 +6,7 @@ Improvements: * RoomVC: Add a re-request keys button on message unable to decrypt (#1879). * Analytics: Move code from AppDelegate to a dedicated class: Analytics. * Analytics: Track Matrix SDK stats (time to startup the app). + * Crypto: Add telemetry for events unable to decrypt (UTDs). * Added the i18n localisation strings to the accessibility labels (#1842), thanks to @einMarco (PR#1906). * Added titles to sound files ID3 tags. diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 097705c6a..20c828611 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -64,6 +64,8 @@ 3267EFB820E379FE00FF1CAA /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB420E379FD00FF1CAA /* Podfile */; }; 3267EFB920E379FE00FF1CAA /* AUTHORS.rst in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */; }; 3267EFBA20E379FE00FF1CAA /* README.rst in Resources */ = {isa = PBXBuildFile; fileRef = 3267EFB620E379FD00FF1CAA /* README.rst */; }; + 3267EFC020E4A3DD00FF1CAA /* DecryptionFailureTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 3267EFBE20E4A3DD00FF1CAA /* DecryptionFailureTracker.m */; }; + 3267EFC320E5055800FF1CAA /* DecryptionFailure.m in Sources */ = {isa = PBXBuildFile; fileRef = 3267EFC220E5055800FF1CAA /* DecryptionFailure.m */; }; 327382B51F276AD200356143 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382A81F276AD200356143 /* InfoPlist.strings */; }; 327382B61F276AD200356143 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382AA1F276AD200356143 /* Localizable.strings */; }; 327382B71F276AD200356143 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382AC1F276AD200356143 /* Vector.strings */; }; @@ -736,6 +738,10 @@ 3267EFB420E379FD00FF1CAA /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = ""; }; 3267EFB520E379FD00FF1CAA /* AUTHORS.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS.rst; sourceTree = ""; }; 3267EFB620E379FD00FF1CAA /* README.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.rst; sourceTree = ""; }; + 3267EFBE20E4A3DD00FF1CAA /* DecryptionFailureTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DecryptionFailureTracker.m; path = Riot/Analytics/DecryptionFailureTracker.m; sourceTree = SOURCE_ROOT; }; + 3267EFBF20E4A3DD00FF1CAA /* DecryptionFailureTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DecryptionFailureTracker.h; path = Riot/Analytics/DecryptionFailureTracker.h; sourceTree = SOURCE_ROOT; }; + 3267EFC120E5055800FF1CAA /* DecryptionFailure.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DecryptionFailure.h; path = Riot/Analytics/DecryptionFailure.h; sourceTree = SOURCE_ROOT; }; + 3267EFC220E5055800FF1CAA /* DecryptionFailure.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = DecryptionFailure.m; path = Riot/Analytics/DecryptionFailure.m; sourceTree = SOURCE_ROOT; }; 327382A91F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = InfoPlist.strings; sourceTree = ""; }; 327382AB1F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Localizable.strings; sourceTree = ""; }; 327382AD1F276AD200356143 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Vector.strings; sourceTree = ""; }; @@ -1613,6 +1619,10 @@ children = ( 3267EFB020E2A04100FF1CAA /* Analytics.h */, 3267EFB120E2A04100FF1CAA /* Analytics.m */, + 3267EFBF20E4A3DD00FF1CAA /* DecryptionFailureTracker.h */, + 3267EFBE20E4A3DD00FF1CAA /* DecryptionFailureTracker.m */, + 3267EFC120E5055800FF1CAA /* DecryptionFailure.h */, + 3267EFC220E5055800FF1CAA /* DecryptionFailure.m */, ); name = Analytics; path = "New Group"; @@ -3622,6 +3632,7 @@ F083BE2D1E7009ED00A9B29C /* ForgotPasswordInputsView.m in Sources */, F083BE7E1E7009ED00A9B29C /* InviteRecentTableViewCell.m in Sources */, F083BE3C1E7009ED00A9B29C /* RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.m in Sources */, + 3267EFC320E5055800FF1CAA /* DecryptionFailure.m in Sources */, F083BE211E7009ED00A9B29C /* RoomSearchViewController.m in Sources */, 32185B311F20FA2B00752141 /* LanguagePickerViewController.m in Sources */, F083BE3E1E7009ED00A9B29C /* RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.m in Sources */, @@ -3686,6 +3697,7 @@ F083BE101E7009ED00A9B29C /* CountryPickerViewController.m in Sources */, F083BE581E7009ED00A9B29C /* RoomOutgoingEncryptedTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, F083BDF61E7009ED00A9B29C /* Contact.m in Sources */, + 3267EFC020E4A3DD00FF1CAA /* DecryptionFailureTracker.m in Sources */, F083BE961E7009ED00A9B29C /* MessagesSearchResultAttachmentBubbleCell.m in Sources */, F083BE391E7009ED00A9B29C /* RoomEncryptedDataBubbleCell.m in Sources */, F083BDF01E7009ED00A9B29C /* UIViewController+RiotSearch.m in Sources */, diff --git a/Riot/Analytics/Analytics.h b/Riot/Analytics/Analytics.h index d6b29b595..ad8466e74 100644 --- a/Riot/Analytics/Analytics.h +++ b/Riot/Analytics/Analytics.h @@ -17,11 +17,12 @@ #import #import +#import "DecryptionFailureTracker.h" /** `Analytics` sends analytics to an analytics tool. */ -@interface Analytics : NSObject +@interface Analytics : NSObject /** Returns the shared Analytics manager. diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m index ad8068266..06276ce1b 100644 --- a/Riot/Analytics/Analytics.m +++ b/Riot/Analytics/Analytics.m @@ -25,6 +25,10 @@ NSString *const kAnalyticsPiwikMetricsCategory = @"Metrics"; NSString *const kAnalyticsPiwikMetricsActionPattern = @"iOS.%@"; +// E2E telemetry is stored under a Piwik category called "E2E". +NSString *const kAnalyticsPiwikE2eCategory = @"E2E"; +NSString *const kAnalyticsPiwikE2eDecryptionFailure = @"Decryption failure"; + @import PiwikTracker; @implementation Analytics @@ -166,4 +170,15 @@ NSString *const kAnalyticsPiwikMetricsActionPattern = @"iOS.%@"; url:nil]; } +#pragma mark - MXDecryptionFailureDelegate + +- (void)trackFailures:(NSUInteger)failuresCount +{ + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikE2eCategory + action:kAnalyticsPiwikE2eDecryptionFailure + name:kAnalyticsPiwikE2eDecryptionFailure + number:@(failuresCount) + url:nil]; +} + @end diff --git a/Riot/Analytics/DecryptionFailure.h b/Riot/Analytics/DecryptionFailure.h new file mode 100644 index 000000000..df9f1af75 --- /dev/null +++ b/Riot/Analytics/DecryptionFailure.h @@ -0,0 +1,39 @@ +/* + Copyright 2018 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 + +/** + `DecryptionFailure` represents a decryption failure. + */ +@interface DecryptionFailure : NSObject + +/** + The id of the event that was unabled to decrypt. + */ +@property (nonatomic) NSString *failedEventId; + +/** + The time the failure has been reported. + */ +@property (nonatomic, readonly) NSTimeInterval ts; + +/** + Decryption failure reason. + */ +@property (nonatomic) NSString *reason; + +@end diff --git a/Riot/Analytics/DecryptionFailure.m b/Riot/Analytics/DecryptionFailure.m new file mode 100644 index 000000000..7cb470e8c --- /dev/null +++ b/Riot/Analytics/DecryptionFailure.m @@ -0,0 +1,31 @@ +/* + Copyright 2018 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 "DecryptionFailure.h" + +@implementation DecryptionFailure + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _ts = [NSDate date].timeIntervalSince1970; + } + return self; +} + +@end diff --git a/Riot/Analytics/DecryptionFailureTracker.h b/Riot/Analytics/DecryptionFailureTracker.h new file mode 100644 index 000000000..7ddc2482f --- /dev/null +++ b/Riot/Analytics/DecryptionFailureTracker.h @@ -0,0 +1,64 @@ +/* + Copyright 2018 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 + +@import MatrixSDK; + +@protocol MXDecryptionFailureDelegate; + +@interface DecryptionFailureTracker : NSObject + +/** + Returns the shared tracker. + + @return the shared tracker. + */ ++ (instancetype)sharedInstance; + +/** + The delegate object to receive analytics events. + */ +@property (nonatomic) id delegate; + +/** + Report an event unable to decrypt. + + This error can be momentary. The DecryptionFailureTracker will check if it gets + fixed. Else, it will generate a failure (@see `trackFailures`). + + @param event the event. + @param roomState the room state when the event was received. + @param userId my user id. + */ +- (void)reportUnableToDecryptErrorForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState myUser:(NSString*)userId; + +@end + +/** + The `MXDecryptionFailureDelegate` protocol receives some stats computed by + `DecryptionFailureTracker`. + */ +@protocol MXDecryptionFailureDelegate + +/** + Stats for decryption failures. + + @param failuresCount the number of decryption failures. + */ +- (void)trackFailures:(NSUInteger)failuresCount; + +@end diff --git a/Riot/Analytics/DecryptionFailureTracker.m b/Riot/Analytics/DecryptionFailureTracker.m new file mode 100644 index 000000000..424570186 --- /dev/null +++ b/Riot/Analytics/DecryptionFailureTracker.m @@ -0,0 +1,138 @@ +/* + Copyright 2018 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 "DecryptionFailureTracker.h" + +#import "DecryptionFailure.h" + + +// Call `checkFailures` every `CHECK_INTERVAL` +#define CHECK_INTERVAL 5 + +// Give events a chance to be decrypted by waiting `GRACE_PERIOD` before counting +// and reporting them as failures +#define GRACE_PERIOD 60 + + +@interface DecryptionFailureTracker() +{ + // Reported failures + // Every `CHECK_INTERVAL`, this list is checked for failures that happened + // more than`GRACE_PERIOD` ago. Those that did are reported to the delegate. + NSMutableDictionary *reportedFailures; + + // Event ids of failures that were tracked previously + NSMutableSet *trackedEvents; + + // Timer for periodic check + NSTimer *checkFailuresTimer; +} +@end + +@implementation DecryptionFailureTracker + ++ (instancetype)sharedInstance +{ + static DecryptionFailureTracker *sharedInstance = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + sharedInstance = [[DecryptionFailureTracker alloc] init]; + }); + + return sharedInstance; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + reportedFailures = [NSMutableDictionary dictionary]; + trackedEvents = [NSMutableSet set]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(eventDidDecrypt:) name:kMXEventDidDecryptNotification object:nil]; + + checkFailuresTimer = [NSTimer scheduledTimerWithTimeInterval:CHECK_INTERVAL + target:self + selector:@selector(checkFailures) + userInfo:nil + repeats:YES]; + } + return self; +} + +- (void)reportUnableToDecryptErrorForEvent:(MXEvent *)event withRoomState:(MXRoomState *)roomState myUser:(NSString *)userId +{ + if (reportedFailures[event.eventId] || [trackedEvents containsObject:event.eventId]) + { + return; + } + + // Filter out "expected" UTDs + // We cannot decrypt messages sent before the user joined the room + MXRoomMember *myUser = [roomState memberWithUserId:userId]; + if (!myUser || myUser.membership != MXMembershipJoin) + { + return; + } + + DecryptionFailure *decryptionFailure = [[DecryptionFailure alloc] init]; + decryptionFailure.failedEventId = event.eventId; + + // TODO: Need to sync with all platforms + // decryptionFailure.reason =; + + reportedFailures[event.eventId] = decryptionFailure; +} + +#pragma mark - Private methods + +/** + Mark reported failures that occured before tsNow - GRACE_PERIOD as failures that should be + tracked. + */ +- (void)checkFailures +{ + NSTimeInterval tsNow = [NSDate date].timeIntervalSince1970; + + NSMutableArray *failuresToTrack = [NSMutableArray array]; + + for (DecryptionFailure *reportedFailure in reportedFailures.allValues) + { + if (reportedFailure.ts < tsNow - GRACE_PERIOD) + { + [failuresToTrack addObject:reportedFailure]; + [reportedFailures removeObjectForKey:reportedFailure.failedEventId]; + [trackedEvents addObject:reportedFailure.failedEventId]; + } + } + + if (_delegate && failuresToTrack.count) + { + NSLog(@"[DecryptionFailureTracker] trackFailures: %@", @(failuresToTrack.count)); + [_delegate trackFailures:failuresToTrack.count]; + } +} + +- (void)eventDidDecrypt:(NSNotification *)notif +{ + // Could be an event in the reportedFailures, remove it + MXEvent *event = notif.object; + [reportedFailures removeObjectForKey:event.eventId]; +} + +@end diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 1ad79e6fc..4d38c59c0 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -464,6 +464,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Configure our analytics. It will indeed start if the option is enabled [MXSDKOptions sharedInstance].analyticsDelegate = [Analytics sharedInstance]; + [DecryptionFailureTracker sharedInstance].delegate = [Analytics sharedInstance]; [[Analytics sharedInstance] start]; // Prepare Pushkit handling diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index 09f92f344..925259270 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -22,6 +22,7 @@ #import "WidgetManager.h" #import "MXDecryptionResult.h" +#import "DecryptionFailureTracker.h" #pragma mark - Constants definitions @@ -117,34 +118,42 @@ NSString *const kEventFormatterOnReRequestKeysLinkActionSeparator = @"/"; NSAttributedString *attributedString = [super attributedStringFromEvent:event withRoomState:roomState error:error]; if (event.sentState == MXEventSentStateSent - && [event.decryptionError.domain isEqualToString:MXDecryptingErrorDomain] - && event.decryptionError.code == MXDecryptingErrorUnknownInboundSessionIdCode) + && [event.decryptionError.domain isEqualToString:MXDecryptingErrorDomain]) { - // Append to the displayed error an attibuted string with a tappable link - // so that the user can try to fix the UTC - NSMutableAttributedString *attributedStringWithRerequestMessage = [attributedString mutableCopy]; - [attributedStringWithRerequestMessage appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]]; + // Track e2e failures + dispatch_async(dispatch_get_main_queue(), ^{ + [[DecryptionFailureTracker sharedInstance] reportUnableToDecryptErrorForEvent:event withRoomState:roomState myUser:mxSession.myUser.userId]; + }); - NSString *linkActionString = [NSString stringWithFormat:@"%@%@%@", kEventFormatterOnReRequestKeysLinkAction, - kEventFormatterOnReRequestKeysLinkActionSeparator, - event.eventId]; - [attributedStringWithRerequestMessage appendAttributedString: - [[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"event_formatter_rerequest_keys_part1_link", @"Vector", nil) - attributes:@{ - NSLinkAttributeName: linkActionString, - NSForegroundColorAttributeName: self.sendingTextColor, - NSFontAttributeName: self.encryptedMessagesTextFont - }]]; + if (event.decryptionError.code == MXDecryptingErrorUnknownInboundSessionIdCode) + { + // Append to the displayed error an attibuted string with a tappable link + // so that the user can try to fix the UTD + NSMutableAttributedString *attributedStringWithRerequestMessage = [attributedString mutableCopy]; + [attributedStringWithRerequestMessage appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]]; - [attributedStringWithRerequestMessage appendAttributedString: - [[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"event_formatter_rerequest_keys_part2", @"Vector", nil) - attributes:@{ - NSForegroundColorAttributeName: self.sendingTextColor, - NSFontAttributeName: self.encryptedMessagesTextFont - }]]; + NSString *linkActionString = [NSString stringWithFormat:@"%@%@%@", kEventFormatterOnReRequestKeysLinkAction, + kEventFormatterOnReRequestKeysLinkActionSeparator, + event.eventId]; - attributedString = attributedStringWithRerequestMessage; + [attributedStringWithRerequestMessage appendAttributedString: + [[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"event_formatter_rerequest_keys_part1_link", @"Vector", nil) + attributes:@{ + NSLinkAttributeName: linkActionString, + NSForegroundColorAttributeName: self.sendingTextColor, + NSFontAttributeName: self.encryptedMessagesTextFont + }]]; + + [attributedStringWithRerequestMessage appendAttributedString: + [[NSAttributedString alloc] initWithString:NSLocalizedStringFromTable(@"event_formatter_rerequest_keys_part2", @"Vector", nil) + attributes:@{ + NSForegroundColorAttributeName: self.sendingTextColor, + NSFontAttributeName: self.encryptedMessagesTextFont + }]]; + + attributedString = attributedStringWithRerequestMessage; + } } return attributedString; From 4b9e8abc15f8c9c47a8dd758d514ed4b408570d1 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Jun 2018 07:50:06 +0200 Subject: [PATCH 34/54] Crypto: Add telemetry for events unable to decrypt (UTDs) Add a dispatch method --- Riot/Analytics/DecryptionFailureTracker.h | 5 +++++ Riot/Analytics/DecryptionFailureTracker.m | 5 +++++ Riot/AppDelegate.m | 1 + 3 files changed, 11 insertions(+) diff --git a/Riot/Analytics/DecryptionFailureTracker.h b/Riot/Analytics/DecryptionFailureTracker.h index 7ddc2482f..92c7587f1 100644 --- a/Riot/Analytics/DecryptionFailureTracker.h +++ b/Riot/Analytics/DecryptionFailureTracker.h @@ -46,6 +46,11 @@ */ - (void)reportUnableToDecryptErrorForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState myUser:(NSString*)userId; +/** + Flush current data. + */ +- (void)dispatch; + @end /** diff --git a/Riot/Analytics/DecryptionFailureTracker.m b/Riot/Analytics/DecryptionFailureTracker.m index 424570186..240f0ecd2 100644 --- a/Riot/Analytics/DecryptionFailureTracker.m +++ b/Riot/Analytics/DecryptionFailureTracker.m @@ -99,6 +99,11 @@ reportedFailures[event.eventId] = decryptionFailure; } +- (void)dispatch +{ + [self checkFailures]; +} + #pragma mark - Private methods /** diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 4d38c59c0..78db8a2c7 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -559,6 +559,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN _isAppForeground = NO; // Analytics: Force to send the pending actions + [[DecryptionFailureTracker sharedInstance] dispatch]; [[Analytics sharedInstance] dispatch]; } From cfc892cb86aa27b12c9b2cd475b5a3cd428b8c75 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Jun 2018 07:51:09 +0200 Subject: [PATCH 35/54] extra \n --- Riot/Utils/EventFormatter.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index 925259270..bb35137ba 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -125,7 +125,6 @@ NSString *const kEventFormatterOnReRequestKeysLinkActionSeparator = @"/"; [[DecryptionFailureTracker sharedInstance] reportUnableToDecryptErrorForEvent:event withRoomState:roomState myUser:mxSession.myUser.userId]; }); - if (event.decryptionError.code == MXDecryptingErrorUnknownInboundSessionIdCode) { // Append to the displayed error an attibuted string with a tappable link From e657951e0e574a8811e8b341b7640ab0515ec4f5 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Jun 2018 11:45:49 +0200 Subject: [PATCH 36/54] Crypto: Telemetry use "no_reason" name --- Riot/Analytics/Analytics.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m index 06276ce1b..b4d3e9b66 100644 --- a/Riot/Analytics/Analytics.m +++ b/Riot/Analytics/Analytics.m @@ -27,7 +27,9 @@ NSString *const kAnalyticsPiwikMetricsActionPattern = @"iOS.%@"; // E2E telemetry is stored under a Piwik category called "E2E". NSString *const kAnalyticsPiwikE2eCategory = @"E2E"; -NSString *const kAnalyticsPiwikE2eDecryptionFailure = @"Decryption failure"; +NSString *const kAnalyticsPiwikE2eDecryptionFailureAction = @"Decryption failure"; +NSString *const kAnalyticsPiwikE2eDecryptionFailureReasonNoReason = @"no_reason"; + @import PiwikTracker; @@ -175,8 +177,8 @@ NSString *const kAnalyticsPiwikE2eDecryptionFailure = @"Decryption failure"; - (void)trackFailures:(NSUInteger)failuresCount { [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikE2eCategory - action:kAnalyticsPiwikE2eDecryptionFailure - name:kAnalyticsPiwikE2eDecryptionFailure + action:kAnalyticsPiwikE2eDecryptionFailureAction + name:kAnalyticsPiwikE2eDecryptionFailureReasonNoReason number:@(failuresCount) url:nil]; } From 58f02f2b8f0bb3ba920088794c3b3bab00653c8e Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Jun 2018 12:04:49 +0200 Subject: [PATCH 37/54] Analytics: Shorten constants names --- Riot/Analytics/Analytics.m | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m index b4d3e9b66..a376fbef8 100644 --- a/Riot/Analytics/Analytics.m +++ b/Riot/Analytics/Analytics.m @@ -22,13 +22,13 @@ // Then, there are 2 Piwik actions: "iOS.startup" and "iOS.stats" (these actions // are namespaced by plaform to have a nice rendering on the Piwik website). // Then, we use constants defined by the Matrix SDK as Piwik Names (ex:"mountData") -NSString *const kAnalyticsPiwikMetricsCategory = @"Metrics"; -NSString *const kAnalyticsPiwikMetricsActionPattern = @"iOS.%@"; +NSString *const kAnalyticsMetricsCategory = @"Metrics"; +NSString *const kAnalyticsMetricsActionPattern = @"iOS.%@"; // E2E telemetry is stored under a Piwik category called "E2E". -NSString *const kAnalyticsPiwikE2eCategory = @"E2E"; -NSString *const kAnalyticsPiwikE2eDecryptionFailureAction = @"Decryption failure"; -NSString *const kAnalyticsPiwikE2eDecryptionFailureReasonNoReason = @"no_reason"; +NSString *const kAnalyticsE2eCategory = @"E2E"; +NSString *const kAnalyticsE2eDecryptionFailureAction = @"Decryption failure"; +NSString *const kAnalyticsE2eDecryptionFailureReasonNoReason = @"no_reason"; @import PiwikTracker; @@ -117,9 +117,9 @@ NSString *const kAnalyticsPiwikE2eDecryptionFailureReasonNoReason = @"no_reason" - (void)trackLaunchScreenDisplayDuration:(NSTimeInterval)seconds { - NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory]; + NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStartupCategory]; - [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory action:action name:kMXAnalyticsStartupLaunchScreen number:@(seconds * 1000) @@ -130,9 +130,9 @@ NSString *const kAnalyticsPiwikE2eDecryptionFailureReasonNoReason = @"no_reason" - (void)trackStartupStorePreloadDuration: (NSTimeInterval)seconds { - NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory]; + NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStartupCategory]; - [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory action:action name:kMXAnalyticsStartupStorePreload number:@(seconds * 1000) @@ -141,9 +141,9 @@ NSString *const kAnalyticsPiwikE2eDecryptionFailureReasonNoReason = @"no_reason" - (void)trackStartupMountDataDuration: (NSTimeInterval)seconds { - NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory]; + NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStartupCategory]; - [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory action:action name:kMXAnalyticsStartupMountData number:@(seconds * 1000) @@ -152,9 +152,9 @@ NSString *const kAnalyticsPiwikE2eDecryptionFailureReasonNoReason = @"no_reason" - (void)trackStartupSyncDuration: (NSTimeInterval)seconds isInitial: (BOOL)isInitial { - NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStartupCategory]; + NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStartupCategory]; - [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory action:action name:isInitial ? kMXAnalyticsStartupInititialSync : kMXAnalyticsStartupIncrementalSync number:@(seconds * 1000) @@ -163,9 +163,9 @@ NSString *const kAnalyticsPiwikE2eDecryptionFailureReasonNoReason = @"no_reason" - (void)trackRoomCount: (NSUInteger)roomCount { - NSString *action = [NSString stringWithFormat:kAnalyticsPiwikMetricsActionPattern, kMXAnalyticsStatsCategory]; + NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStatsCategory]; - [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikMetricsCategory + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory action:action name:kMXAnalyticsStatsRooms number:@(roomCount) @@ -176,9 +176,9 @@ NSString *const kAnalyticsPiwikE2eDecryptionFailureReasonNoReason = @"no_reason" - (void)trackFailures:(NSUInteger)failuresCount { - [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsPiwikE2eCategory - action:kAnalyticsPiwikE2eDecryptionFailureAction - name:kAnalyticsPiwikE2eDecryptionFailureReasonNoReason + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsE2eCategory + action:kAnalyticsE2eDecryptionFailureAction + name:kAnalyticsE2eDecryptionFailureReasonNoReason number:@(failuresCount) url:nil]; } From 667329252a228c04fb7feb1bb256e79a82bdf9a1 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Jun 2018 15:26:41 +0200 Subject: [PATCH 38/54] RoomVC: Fix regression where read receipts can be duplicated --- Riot/Model/Room/RoomDataSource.m | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Riot/Model/Room/RoomDataSource.m b/Riot/Model/Room/RoomDataSource.m index 4fe9680c0..436405d0d 100644 --- a/Riot/Model/Room/RoomDataSource.m +++ b/Riot/Model/Room/RoomDataSource.m @@ -107,7 +107,7 @@ @synchronized(bubbles) { - NSMutableDictionary *> *updatedCellDataReadReceipts = [NSMutableDictionary dictionary]; + NSMutableDictionary *> *updatedCellDataReadReceipts = [NSMutableDictionary dictionary]; for (RoomBubbleCellData *cellData in bubbles) { for (NSString *eventId in cellData.readReceipts) @@ -124,10 +124,11 @@ if (!updatedCellDataReadReceipts[eventId]) { - updatedCellDataReadReceipts[eventId] = [cellData.readReceipts[eventId] mutableCopy]; + updatedCellDataReadReceipts[eventId] = cellData.readReceipts[eventId]; } - [updatedCellDataReadReceipts[eventId] removeObject:receiptData]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"userId!=%@", receiptData.userId]; + updatedCellDataReadReceipts[eventId] = [updatedCellDataReadReceipts[eventId] filteredArrayUsingPredicate:predicate]; break; } } From 5c05da0cd739b8ea7a9dcf38e8c001022bfa28b9 Mon Sep 17 00:00:00 2001 From: daniel tygel Date: Sun, 17 Jun 2018 17:55:02 +0000 Subject: [PATCH 39/54] Translated using Weblate (Portuguese (Brazil)) Currently translated at 17.0% (86 of 505 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/pt_BR/ --- Riot/Assets/pt_BR.lproj/Vector.strings | 90 +++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings index 8b1378917..3ab493a1e 100644 --- a/Riot/Assets/pt_BR.lproj/Vector.strings +++ b/Riot/Assets/pt_BR.lproj/Vector.strings @@ -1 +1,89 @@ - +// Titles +"title_home" = "Início"; +"title_favourites" = "Favoritos"; +"title_people" = "Pessoas"; +"title_rooms" = "Salas"; +"title_groups" = "Comunidades"; +"warning" = "Atenção"; +// Actions +"view" = "Ver"; +"next" = "Próximo"; +"back" = "Voltar"; +"continue" = "Continuar"; +"create" = "Criar"; +"start" = "Iniciar"; +"leave" = "Sair"; +"remove" = "Remover"; +"invite" = "Convidar"; +"retry" = "Tentar novamente"; +"on" = "Ativado"; +"off" = "Desativado"; +"cancel" = "Cancelar"; +"save" = "Salvar"; +"join" = "Entrar"; +"decline" = "Recusar"; +"accept" = "Aceitar"; +"preview" = "Pré-visualização"; +"camera" = "Câmera"; +"voice" = "Voz"; +"video" = "Vídeo"; +"active_call" = "Chamada em andamento"; +"active_call_details" = "Chamada em andamento (%@)"; +"later" = "Mais tarde"; +"rename" = "Renomear"; +"collapse" = "reduzir"; +"send_to" = "Enviar para %@"; +"sending" = "Enviando"; +// Authentication +"auth_login" = "Fazer login"; +"auth_register" = "Criar nova conta"; +"auth_submit" = "Enviar"; +"auth_skip" = "Ignorar"; +"auth_send_reset_email" = "Enviar e-mail de redefinição de senha"; +"auth_return_to_login" = "Voltar à tela de login"; +"auth_user_id_placeholder" = "E-mail ou nome de usuária/o"; +"auth_password_placeholder" = "Senha"; +"auth_new_password_placeholder" = "Nova senha"; +"auth_user_name_placeholder" = "Nome de usuária/o"; +"auth_optional_email_placeholder" = "Endereço de e-mail (opcional)"; +"auth_email_placeholder" = "Endereço de e-mail"; +"auth_optional_phone_placeholder" = "Número de telefone (opcional)"; +"auth_phone_placeholder" = "Número de telefone"; +"auth_repeat_password_placeholder" = "Repita a senha"; +"auth_repeat_new_password_placeholder" = "Confirme sua nova senha"; +"auth_home_server_placeholder" = "URL (p.ex. https://matrix.org)"; +"auth_identity_server_placeholder" = "URL (p.ex. https://matrix.org)"; +"auth_invalid_login_param" = "Nome de usuária/o e/ou senha incorretos"; +"auth_invalid_user_name" = "Nomes de usuária/o podem apenas conter letras, números, pontos, hífen e linha de sublinhar"; +"auth_invalid_password" = "Senha muito curta (mín. 6 letras)"; +"auth_invalid_email" = "O endereço de e-mail não parece válido"; +"auth_invalid_phone" = "O número de telefone não parece válido"; +"auth_missing_password" = "Falta a senha"; +"auth_add_email_message" = "Adicione um endereço de e-mail para a sua conta para permitir que outras pessoas possam te achar, e também para que você possa redefinir sua senha."; +"auth_add_phone_message" = "Adicione um número de telefone à sua conta para permitir que outras pessoas te encontrem."; +"auth_add_email_phone_message" = "Adicione um endereço de e-mail e/ou um telefone à sua conta para permitir que outras pessoas encontrem você. O endereço de e-mail também permite que você redefina a sua senha."; +"auth_add_email_and_phone_message" = "Adicione um endereço de e-mail e um telefone à sua conta para permitir que outras pessoas encontrem você. O endereço de e-mail também permite que você redefina a sua senha."; +"auth_missing_email" = "Falta o endereço de e-mail"; +"auth_missing_phone" = "Falta o número de telefone"; +"auth_missing_email_or_phone" = "Falta o endereço de e-mail ou o número de telefone"; +"auth_email_in_use" = "Este endereço de e-mail já está sendo usado por outra pessoa"; +"auth_phone_in_use" = "Este número de telefone já está sendo usado por outra pessoa"; +"auth_untrusted_id_server" = "Este servidor de identidades não é confiável"; +"auth_password_dont_match" = "As senhas não são iguais"; +"auth_username_in_use" = "Este nome de usuária/o já está sendo usado por outra pessoa"; +"auth_forgot_password" = "Esqueceu sua senha?"; +"auth_email_not_found" = "Não consegui enviar e-mail: este endereço de e-mail não foi encontrado"; +"auth_use_server_options" = "Usar opções personalizadas de servidor (avançado)"; +"auth_email_validation_message" = "Por favor, verifique o seu e-mail para continuar seu cadastro"; +"auth_msisdn_validation_title" = "Faltando verificação"; +"auth_msisdn_validation_message" = "Nós enviamos um SMS com um código de ativação. Por favor, coloque abaixo este código."; +"auth_msisdn_validation_error" = "Não foi possível verificar o número de telefone."; +"auth_recaptcha_message" = "Este Servidor de Base (Home Server) quer ter certeza que você não é um robô"; +"auth_reset_password_message" = "Para redefinir sua senha, coloque o endereço de e-mail relacionado à sua conta:"; +"auth_reset_password_missing_email" = "O endereço de e-mail relacionado à sua conta tem que ser inserido."; +"auth_reset_password_missing_password" = "Uma nova senha tem que ser inserida."; +"auth_reset_password_email_validation_message" = "Um e-mail foi enviado para %@. Quando você clicar no link do e-mail, clique abaixo."; +"auth_reset_password_next_step_button" = "Eu verifiquei meu endereço de e-mail"; +"auth_reset_password_error_unauthorized" = "Não foi possível verificar o endereço de e-mail: confirme que realmente clicou no link contido na mensagem de e-mail"; +"auth_reset_password_error_not_found" = "O seu endereço de e-mail não parece estar associado a um ID Matrix neste Servidor de Base (Home Server)."; +"auth_reset_password_success_message" = "Sua senha foi redefinida.\n\nVocê foi deslogado de todos os dispositivos e não receberá notificações. Para reativar as notificações, faça login novamente em cada um dos dispositivos."; From 2b073f2be165e0bb60a4558ceac43649b341e81c Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Mon, 2 Jul 2018 14:37:44 +0200 Subject: [PATCH 40/54] Enable Swift support for Riot target. Create first Swift class, RiotSettings for handling specific Riot app settings. --- Riot.xcodeproj/project.pbxproj | 22 ++++++- Riot/Riot-Bridging-Header.h | 4 ++ Riot/Utils/RiotSettings.swift | 101 +++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 Riot/Riot-Bridging-Header.h create mode 100644 Riot/Utils/RiotSettings.swift diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 20c828611..c920ed7a0 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -120,6 +120,7 @@ 9D686B069F967C4D4BBC610F /* Pods_RiotPods_SiriIntents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB50EEBE8214352B9EBD6394 /* Pods_RiotPods_SiriIntents.framework */; }; B19A173920B7F94800DF0BB0 /* DeactivateAccountViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B19A173820B7F94800DF0BB0 /* DeactivateAccountViewController.m */; }; B19A173B20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B19A173A20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard */; }; + B1D818C020EA4C7400D5F36D /* RiotSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D818BF20EA4C7400D5F36D /* RiotSettings.swift */; }; DDDE2AB95F865F2292B1D315 /* Pods_RiotPods_RiotShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23D7292481328A48B8D5D4ED /* Pods_RiotPods_RiotShareExtension.framework */; }; F0131DE51F2200D600CBF707 /* RiotSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */; }; F0173EB51FCF346800B5F6A3 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = F0173EAF1FCF346800B5F6A3 /* Vector.strings */; }; @@ -821,6 +822,8 @@ B19A173720B7F94800DF0BB0 /* DeactivateAccountViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeactivateAccountViewController.h; sourceTree = ""; }; B19A173820B7F94800DF0BB0 /* DeactivateAccountViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeactivateAccountViewController.m; sourceTree = ""; }; B19A173A20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = DeactivateAccountViewController.storyboard; sourceTree = ""; }; + B1D818BC20E66C3300D5F36D /* Riot-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Riot-Bridging-Header.h"; sourceTree = ""; }; + B1D818BF20EA4C7400D5F36D /* RiotSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RiotSettings.swift; sourceTree = ""; }; C195C53961EA28E6900AEB68 /* Pods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.release.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.release.xcconfig"; sourceTree = ""; }; C5258DFF261AA3AB228A3F11 /* Pods-RiotPods-RiotShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-RiotShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RiotPods-RiotShareExtension/Pods-RiotPods-RiotShareExtension.debug.xcconfig"; sourceTree = ""; }; DB50EEBE8214352B9EBD6394 /* Pods_RiotPods_SiriIntents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RiotPods_SiriIntents.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2247,6 +2250,7 @@ F083BC151E7009EC00A9B29C /* Tools.m */, F083BC161E7009EC00A9B29C /* RiotDesignValues.h */, F083BC171E7009EC00A9B29C /* RiotDesignValues.m */, + B1D818BF20EA4C7400D5F36D /* RiotSettings.swift */, ); path = Utils; sourceTree = ""; @@ -2699,6 +2703,7 @@ F083BEA41E700B2800A9B29C /* Supporting Files */ = { isa = PBXGroup; children = ( + B1D818BC20E66C3300D5F36D /* Riot-Bridging-Header.h */, F0DD05CF1F615ECF00CB5292 /* LaunchScreenRiot.png */, F083BBED1E7009EC00A9B29C /* empty.mm */, F083BBEE1E7009EC00A9B29C /* GoogleService-Info.plist */, @@ -2906,6 +2911,7 @@ F094A9A11B78D8F000B1FBBF = { CreatedOnToolsVersion = 6.2; DevelopmentTeam = 7J4U792NQT; + LastSwiftMigration = 0940; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.ApplicationGroups.iOS = { @@ -3674,6 +3680,7 @@ F083BE781E7009ED00A9B29C /* RoomOutgoingTextMsgWithPaginationTitleWithoutSenderNameBubbleCell.m in Sources */, F083BE5E1E7009ED00A9B29C /* RoomIncomingAttachmentWithPaginationTitleBubbleCell.m in Sources */, F083BD1E1E7009ED00A9B29C /* AppDelegate.m in Sources */, + B1D818C020EA4C7400D5F36D /* RiotSettings.swift in Sources */, F083BE8A1E7009ED00A9B29C /* ExpandedRoomTitleView.m in Sources */, F083BE0C1E7009ED00A9B29C /* ContactDetailsViewController.m in Sources */, F083BE821E7009ED00A9B29C /* RecentTableViewCell.m in Sources */, @@ -4125,6 +4132,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + DEFINES_MODULE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -4142,7 +4150,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -4171,6 +4179,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + DEFINES_MODULE = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -4181,7 +4190,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -4194,6 +4203,7 @@ baseConfigurationReference = A5030B7C3C0B6EB83A9257BD /* Pods-RiotPods-Riot.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Riot/Riot.entitlements; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEVELOPMENT_TEAM = 7J4U792NQT; @@ -4220,6 +4230,9 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.vector.app; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/$(PRODUCT_NAME)/Riot-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -4229,6 +4242,7 @@ baseConfigurationReference = F546BCBBB9BBEE67DB28878A /* Pods-RiotPods-Riot.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Riot/Riot.entitlements; DEVELOPMENT_TEAM = 7J4U792NQT; ENABLE_BITCODE = NO; @@ -4254,6 +4268,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.vector.app; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/$(PRODUCT_NAME)/Riot-Bridging-Header.h"; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -4261,6 +4277,7 @@ F094A9CC1B78D8F000B1FBBF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = 7J4U792NQT; FRAMEWORK_SEARCH_PATHS = ( @@ -4282,6 +4299,7 @@ F094A9CD1B78D8F000B1FBBF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; DEVELOPMENT_TEAM = 7J4U792NQT; FRAMEWORK_SEARCH_PATHS = ( diff --git a/Riot/Riot-Bridging-Header.h b/Riot/Riot-Bridging-Header.h new file mode 100644 index 000000000..1b2cb5d6d --- /dev/null +++ b/Riot/Riot-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/Riot/Utils/RiotSettings.swift b/Riot/Utils/RiotSettings.swift new file mode 100644 index 000000000..38c25d1df --- /dev/null +++ b/Riot/Utils/RiotSettings.swift @@ -0,0 +1,101 @@ +/* + Copyright 2018 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 + +@objcMembers +final class RiotSettings: NSObject { + + // MARK: - Constants + + private enum UserDefaultsKeys { + static let enableCrashReport = "enableCrashReport" + static let enableRageShake = "enableRageShake" + static let createConferenceCallsWithJitsi = "createConferenceCallsWithJitsi" + static let userInterfaceTheme = "userInterfaceTheme" + static let notificationsShowDecryptedContent = "showDecryptedContent" + static let pinRoomsWithMissedNotifications = "pinRoomsWithMissedNotif" + static let pinRoomsWithUnreadMessages = "pinRoomsWithUnread" + } + + static let shared = RiotSettings() + + // MARK: - Public + + // MARK: Notifications + + var showDecryptedContentInNotifications: Bool { + get { + return UserDefaults.standard.bool(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) + } set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.notificationsShowDecryptedContent) + } + } + + var pinRoomsWithMissedNotificationsOnHome: Bool { + get { + return UserDefaults.standard.bool(forKey: UserDefaultsKeys.pinRoomsWithMissedNotifications) + } set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.pinRoomsWithMissedNotifications) + } + } + + var pinRoomsWithUnreadMessagesOnHome: Bool { + get { + return UserDefaults.standard.bool(forKey: UserDefaultsKeys.pinRoomsWithUnreadMessages) + } set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.pinRoomsWithUnreadMessages) + } + } + + // MARK: User interface + + var userInterfaceTheme: String? { + get { + return UserDefaults.standard.string(forKey: UserDefaultsKeys.userInterfaceTheme) + } set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.userInterfaceTheme) + } + } + + // MARK: Other + + var enableCrashReport: Bool { + get { + return UserDefaults.standard.bool(forKey: UserDefaultsKeys.enableCrashReport) + } set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.enableCrashReport) + } + } + + var enableRageShake: Bool { + get { + return UserDefaults.standard.bool(forKey: UserDefaultsKeys.enableRageShake) + } set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.enableRageShake) + } + } + + // MARK: Labs + + var createConferenceCallsWithJitsi: Bool { + get { + return UserDefaults.standard.bool(forKey: UserDefaultsKeys.createConferenceCallsWithJitsi) + } set { + UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.createConferenceCallsWithJitsi) + } + } +} From acd626451bb89d3d5811983afd04b089e5b9d6e2 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Mon, 2 Jul 2018 14:41:55 +0200 Subject: [PATCH 41/54] Now store `showDecryptedContentInNotifications` settings option in UserDefaults instead for MXKAccount in order to keep this information when the user logout. Fix issue #1914. --- Riot/AppDelegate.m | 38 ++++++++++---- Riot/ViewController/SettingsViewController.m | 52 ++++++++++---------- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 78db8a2c7..9152a2be9 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -54,6 +54,8 @@ #import "MXSession+Riot.h" #import "MXRoom+Riot.h" +#import "Riot-Swift.h" + //#define MX_CALL_STACK_OPENWEBRTC #ifdef MX_CALL_STACK_OPENWEBRTC #import @@ -455,12 +457,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN _isAppForeground = NO; - // Retrieve custom configuration - NSString* userDefaults = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UserDefaults"]; - NSString *defaultsPathFromApp = [[NSBundle mainBundle] pathForResource:userDefaults ofType:@"plist"]; - NSDictionary *defaults = [NSDictionary dictionaryWithContentsOfFile:defaultsPathFromApp]; - [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; - [[NSUserDefaults standardUserDefaults] synchronize]; + [self setupUserDefaults]; // Configure our analytics. It will indeed start if the option is enabled [MXSDKOptions sharedInstance].analyticsDelegate = [Analytics sharedInstance]; @@ -591,7 +588,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSLog(@"[AppDelegate] applicationDidBecomeActive"); // Check if there is crash log to send - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]) + if (RiotSettings.shared.enableCrashReport) { [self checkExceptionToReport]; } @@ -1405,7 +1402,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN @"user_id": account.mxCredentials.userId }; - BOOL isNotificationContentShown = !event.isEncrypted || account.showDecryptedContentInNotifications; + BOOL isNotificationContentShown = !event.isEncrypted || RiotSettings.shared.showDecryptedContentInNotifications; + if ((event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted) && isNotificationContentShown) { eventNotification.category = @"QUICK_REPLY"; @@ -1493,7 +1491,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSString *msgType = event.content[@"msgtype"]; NSString *content = event.content[@"body"]; - if (event.isEncrypted && !account.showDecryptedContentInNotifications) + if (event.isEncrypted && !RiotSettings.shared.showDecryptedContentInNotifications) { // Hide the content msgType = nil; @@ -4023,4 +4021,26 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [self.gdprConsentViewController dismissViewControllerAnimated:YES completion:nil]; } +#pragma mark - Settings + +- (void)setupUserDefaults +{ + // Retrieve custom configuration + NSString* userDefaults = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UserDefaults"]; + NSString *defaultsPathFromApp = [[NSBundle mainBundle] pathForResource:userDefaults ofType:@"plist"]; + NSDictionary *defaults = [NSDictionary dictionaryWithContentsOfFile:defaultsPathFromApp]; + [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + // Now use RiotSettings and NSUserDefaults to store `showDecryptedContentInNotifications` setting option + // Migrate this information from main MXKAccount to RiotSettings, only if value was set to YES as default value is NO + + MXKAccount *currentAccount = [MXKAccountManager sharedManager].activeAccounts.firstObject; + + if (currentAccount.showDecryptedContentInNotifications) + { + RiotSettings.shared.showDecryptedContentInNotifications = currentAccount.showDecryptedContentInNotifications; + } +} + @end diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index 7385bb0d2..b94074471 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -46,6 +46,8 @@ #import "GBDeviceInfo_iOS.h" +#import "Riot-Swift.h" + NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId"; enum @@ -1681,7 +1683,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_show_decrypted_content", @"Vector", nil); - labelAndSwitchCell.mxkSwitch.on = account.showDecryptedContentInNotifications; + labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.showDecryptedContentInNotifications; labelAndSwitchCell.mxkSwitch.enabled = account.isPushKitNotificationActive; [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleShowDecodedContent:) forControlEvents:UIControlEventTouchUpInside]; @@ -1705,7 +1707,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_pin_rooms_with_missed_notif", @"Vector", nil); - labelAndSwitchCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"pinRoomsWithMissedNotif"]; + labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome; labelAndSwitchCell.mxkSwitch.enabled = YES; [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(togglePinRoomsWithMissedNotif:) forControlEvents:UIControlEventTouchUpInside]; @@ -1716,7 +1718,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_pin_rooms_with_unread", @"Vector", nil); - labelAndSwitchCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"pinRoomsWithUnread"]; + labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.pinRoomsWithUnreadMessagesOnHome; labelAndSwitchCell.mxkSwitch.enabled = YES; [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(togglePinRoomsWithUnread:) forControlEvents:UIControlEventTouchUpInside]; @@ -1782,7 +1784,8 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kSettingsViewControllerPhoneBookCountryCellId]; } - NSString *theme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"]; + NSString *theme = RiotSettings.shared.userInterfaceTheme; + if (!theme) { if (@available(iOS 11.0, *)) @@ -1942,7 +1945,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); MXKTableViewCellWithLabelAndSwitch* sendCrashReportCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; sendCrashReportCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_send_crash_report", @"Vector", nil); - sendCrashReportCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]; + sendCrashReportCell.mxkSwitch.on = RiotSettings.shared.enableCrashReport; sendCrashReportCell.mxkSwitch.enabled = YES; [sendCrashReportCell.mxkSwitch addTarget:self action:@selector(toggleSendCrashReport:) forControlEvents:UIControlEventTouchUpInside]; @@ -1953,7 +1956,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); MXKTableViewCellWithLabelAndSwitch* enableRageShakeCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; enableRageShakeCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_enable_rageshake", @"Vector", nil); - enableRageShakeCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableRageShake"]; + enableRageShakeCell.mxkSwitch.on = RiotSettings.shared.enableRageShake; enableRageShakeCell.mxkSwitch.enabled = YES; [enableRageShakeCell.mxkSwitch addTarget:self action:@selector(toggleEnableRageShake:) forControlEvents:UIControlEventTouchUpInside]; @@ -2042,7 +2045,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_labs_create_conference_with_jitsi", @"Vector", nil); - labelAndSwitchCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"createConferenceCallsWithJitsi"]; + labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.createConferenceCallsWithJitsi; [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleJitsiForConference:) forControlEvents:UIControlEventTouchUpInside]; @@ -2820,8 +2823,8 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); - (void)toggleShowDecodedContent:(id)sender { - MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject; - account.showDecryptedContentInNotifications = !account.showDecryptedContentInNotifications; + UISwitch *switchButton = (UISwitch*)sender; + RiotSettings.shared.showDecryptedContentInNotifications = switchButton.isOn; } - (void)toggleLocalContactsSync:(id)sender @@ -2847,12 +2850,12 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); - (void)toggleSendCrashReport:(id)sender { - BOOL enable = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]; + BOOL enable = RiotSettings.shared.enableCrashReport; if (enable) { NSLog(@"[SettingsViewController] disable automatic crash report and analytics sending"); - [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"enableCrashReport"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + + RiotSettings.shared.enableCrashReport = NO; [[Analytics sharedInstance] stop]; @@ -2862,8 +2865,8 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); else { NSLog(@"[SettingsViewController] enable automatic crash report and analytics sending"); - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"enableCrashReport"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + + RiotSettings.shared.enableCrashReport = YES; [[Analytics sharedInstance] start]; } @@ -2875,8 +2878,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); { UISwitch *switchButton = (UISwitch*)sender; - [[NSUserDefaults standardUserDefaults] setBool:switchButton.isOn forKey:@"enableRageShake"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + RiotSettings.shared.enableRageShake = switchButton.isOn; [self.tableView reloadData]; } @@ -2887,9 +2889,8 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); if (sender && [sender isKindOfClass:UISwitch.class]) { UISwitch *switchButton = (UISwitch*)sender; - - [[NSUserDefaults standardUserDefaults] setBool:switchButton.isOn forKey:@"createConferenceCallsWithJitsi"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + + RiotSettings.shared.createConferenceCallsWithJitsi = switchButton.isOn; [self.tableView reloadData]; } @@ -3012,16 +3013,14 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); { UISwitch *switchButton = (UISwitch*)sender; - [[NSUserDefaults standardUserDefaults] setBool:switchButton.on forKey:@"pinRoomsWithMissedNotif"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome = switchButton.on; } - (void)togglePinRoomsWithUnread:(id)sender { UISwitch *switchButton = (UISwitch*)sender; - - [[NSUserDefaults standardUserDefaults] setBool:switchButton.on forKey:@"pinRoomsWithUnread"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + + RiotSettings.shared.pinRoomsWithUnreadMessagesOnHome = switchButton.on; } - (void)toggleCommunityFlair:(id)sender @@ -3661,15 +3660,14 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); newTheme = @"black"; } - NSString *theme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"]; + NSString *theme = RiotSettings.shared.userInterfaceTheme; if (newTheme && ![newTheme isEqualToString:theme]) { // Clear fake Riot Avatars based on the previous theme. [AvatarGenerator clear]; // The user wants to select this theme - [[NSUserDefaults standardUserDefaults] setObject:newTheme forKey:@"userInterfaceTheme"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + RiotSettings.shared.userInterfaceTheme = newTheme; [self.tableView reloadData]; } From 810aa5815342a7d73a25d560c58f4814cf66e901 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Mon, 2 Jul 2018 14:51:47 +0200 Subject: [PATCH 42/54] Use RiotSettings instead of direct access to UserDefault where needed --- Riot/API/RageShakeManager.m | 7 ++++--- Riot/Analytics/Analytics.m | 3 ++- Riot/Model/RoomList/RecentsDataSource.m | 6 ++++-- Riot/Utils/RiotDesignValues.m | 5 +++-- Riot/ViewController/MasterTabBarController.m | 14 +++++++------- Riot/ViewController/RoomViewController.m | 4 +++- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Riot/API/RageShakeManager.m b/Riot/API/RageShakeManager.m index 5b93e5cee..a402c064c 100644 --- a/Riot/API/RageShakeManager.m +++ b/Riot/API/RageShakeManager.m @@ -24,6 +24,8 @@ #import +#import "Riot-Swift.h" + static RageShakeManager* sharedInstance = nil; @interface RageShakeManager() { @@ -111,7 +113,7 @@ static RageShakeManager* sharedInstance = nil; // Start only if the application is in foreground // And if the rageshake user setting is enabled if ([AppDelegate theDelegate].isAppForeground - && [[NSUserDefaults standardUserDefaults] boolForKey:@"enableRageShake"] + && RiotSettings.shared.enableRageShake && !confirmationAlert) { NSLog(@"[RageShakeManager] Start shaking with [%@]", [responder class]); @@ -163,8 +165,7 @@ static RageShakeManager* sharedInstance = nil; self->confirmationAlert = nil; // Disable rageshake user setting - [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"enableRageShake"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + RiotSettings.shared.enableRageShake = NO; } }]]; diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m index a376fbef8..c9379ea06 100644 --- a/Riot/Analytics/Analytics.m +++ b/Riot/Analytics/Analytics.m @@ -17,6 +17,7 @@ #import "Analytics.h" #import "AppDelegate.h" +#import "Riot-Swift.h" // All metrics are store under a Piwik category called "Metrics". // Then, there are 2 Piwik actions: "iOS.startup" and "iOS.stats" (these actions @@ -55,7 +56,7 @@ NSString *const kAnalyticsE2eDecryptionFailureReasonNoReason = @"no_reason"; userAgent:@"iOSPiwikTracker"]; // Check whether the user has enabled the sending of crash reports. - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]) + if (RiotSettings.shared.enableCrashReport) { [PiwikTracker shared].isOptedOut = NO; diff --git a/Riot/Model/RoomList/RecentsDataSource.m b/Riot/Model/RoomList/RecentsDataSource.m index 83c725b59..86de39869 100644 --- a/Riot/Model/RoomList/RecentsDataSource.m +++ b/Riot/Model/RoomList/RecentsDataSource.m @@ -25,6 +25,8 @@ #import "AppDelegate.h" +#import "Riot-Swift.h" + #define RECENTSDATASOURCE_SECTION_DIRECTORY 0x01 #define RECENTSDATASOURCE_SECTION_INVITES 0x02 #define RECENTSDATASOURCE_SECTION_FAVORITES 0x04 @@ -1193,8 +1195,8 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (_recentsDataSourceMode == RecentsDataSourceModeHome) { - BOOL pinMissedNotif = [[NSUserDefaults standardUserDefaults] boolForKey:@"pinRoomsWithMissedNotif"]; - BOOL pinUnread = [[NSUserDefaults standardUserDefaults] boolForKey:@"pinRoomsWithUnread"]; + BOOL pinMissedNotif = RiotSettings.shared.pinRoomsWithMissedNotificationsOnHome; + BOOL pinUnread = RiotSettings.shared.pinRoomsWithUnreadMessagesOnHome; NSComparator comparator = nil; if (pinMissedNotif) diff --git a/Riot/Utils/RiotDesignValues.m b/Riot/Utils/RiotDesignValues.m index 1f062ceaf..5399444d3 100644 --- a/Riot/Utils/RiotDesignValues.m +++ b/Riot/Utils/RiotDesignValues.m @@ -16,6 +16,7 @@ */ #import "RiotDesignValues.h" +#import "Riot-Swift.h" NSString *const kRiotDesignValuesDidChangeThemeNotification = @"kRiotDesignValuesDidChangeThemeNotification"; @@ -134,7 +135,7 @@ UIKeyboardAppearance kRiotKeyboard; - (void)accessibilityInvertColorsStatusDidChange { // Refresh the theme only for "auto" - NSString *theme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"]; + NSString *theme = RiotSettings.shared.userInterfaceTheme; if (!theme || [theme isEqualToString:@"auto"]) { [self userInterfaceThemeDidChange]; @@ -144,7 +145,7 @@ UIKeyboardAppearance kRiotKeyboard; - (void)userInterfaceThemeDidChange { // Retrieve the current selected theme ("light" if none. "auto" is used as default from iOS 11). - NSString *theme = [[NSUserDefaults standardUserDefaults] stringForKey:@"userInterfaceTheme"]; + NSString *theme = RiotSettings.shared.userInterfaceTheme; if (!theme || [theme isEqualToString:@"auto"]) { diff --git a/Riot/ViewController/MasterTabBarController.m b/Riot/ViewController/MasterTabBarController.m index fb3458f33..036f008a4 100644 --- a/Riot/ViewController/MasterTabBarController.m +++ b/Riot/ViewController/MasterTabBarController.m @@ -26,6 +26,8 @@ #import "MXRoom+Riot.h" #import "MXSession+Riot.h" +#import "Riot-Swift.h" + @interface MasterTabBarController () { // Array of `MXSession` instances. @@ -145,8 +147,8 @@ else { // Check whether the user has been already prompted to send crash reports. - // (Check whether 'enableCrashReport' flag has been set once) - if (![[NSUserDefaults standardUserDefaults] objectForKey:@"enableCrashReport"]) + // (Check whether 'enableCrashReport' flag has been set once) + if (!RiotSettings.shared.enableCrashReport) { [self promptUserBeforeUsingAnalytics]; } @@ -787,8 +789,7 @@ style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"enableCrashReport"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + RiotSettings.shared.enableCrashReport = NO; if (weakSelf) { @@ -801,9 +802,8 @@ [currentAlert addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"yes"] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"enableCrashReport"]; - [[NSUserDefaults standardUserDefaults] synchronize]; + + RiotSettings.shared.enableCrashReport = YES; if (weakSelf) { diff --git a/Riot/ViewController/RoomViewController.m b/Riot/ViewController/RoomViewController.m index eba5abf36..9b821132e 100644 --- a/Riot/ViewController/RoomViewController.m +++ b/Riot/ViewController/RoomViewController.m @@ -119,6 +119,8 @@ #import "EventFormatter.h" +#import "Riot-Swift.h" + @interface RoomViewController () { // The expanded header @@ -3012,7 +3014,7 @@ } // If enabled, create the conf using jitsi widget and open it directly - else if ([[NSUserDefaults standardUserDefaults] boolForKey:@"createConferenceCallsWithJitsi"] + else if (RiotSettings.shared.createConferenceCallsWithJitsi && self.roomDataSource.room.state.joinedMembers.count > 2) { [self startActivityIndicator]; From 7aa6d04d5bdebf136296b7cb16ca4d8127f48b8b Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 2 Jul 2018 15:47:09 +0200 Subject: [PATCH 43/54] RoomVC: Fix regressions on vertical alignment of e2e padlock, read marker, etc. Regression due to read receipt perf improvement. --- Riot/Model/Room/RoomBubbleCellData.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Riot/Model/Room/RoomBubbleCellData.m b/Riot/Model/Room/RoomBubbleCellData.m index d0f7ff4a2..9671f88bf 100644 --- a/Riot/Model/Room/RoomBubbleCellData.m +++ b/Riot/Model/Room/RoomBubbleCellData.m @@ -260,6 +260,8 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; // Check whether there is at least one component. if (bubbleComponents.count) { + BOOL hasReadReceipts = NO; + // Set position of the first component CGFloat positionY = (self.attachment == nil || self.attachment.type == MXKAttachmentTypeFile || self.attachment.type == MXKAttachmentTypeAudio) ? MXKROOMBUBBLECELLDATA_TEXTVIEW_DEFAULT_VERTICAL_INSET : 0; MXKRoomBubbleComponent *component; @@ -273,6 +275,7 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; if (component.attributedTextMessage) { + hasReadReceipts = (self.readReceipts[component.event.eventId].count > 0); break; } } @@ -297,7 +300,7 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; } // Vertical whitespace is added in case of read receipts - if (self.readReceipts.count) + if (hasReadReceipts) { [attributedString appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]]; } @@ -337,7 +340,7 @@ static NSAttributedString *readReceiptVerticalWhitespace = nil; component.position = CGPointMake(0, positionY); // Add vertical whitespace in case of read receipts. - if (self.readReceipts[component.event.eventId]) + if (self.readReceipts[component.event.eventId].count) { [attributedString appendAttributedString:[RoomBubbleCellData readReceiptVerticalWhitespace]]; } From f51ca940fda41c58afdf3671917dc3b253e3b5f4 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Mon, 2 Jul 2018 15:48:11 +0200 Subject: [PATCH 44/54] Update change log --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index fbbdeb7d1..5dd055bf1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -12,6 +12,7 @@ Improvements: Bug fix: * RoomVC: Read receipts processing dramatically slows down UI (#1899). + * E2E messages not decrypted in notifs after logging back in (#1914). Changes in 0.6.17 (2018-06-01) =============================================== From 862668d638fee170170cf3d0272fbeba0e4fc547 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Mon, 2 Jul 2018 16:49:36 +0200 Subject: [PATCH 45/54] Add comments to RiotSettings. --- Riot/Utils/RiotSettings.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Riot/Utils/RiotSettings.swift b/Riot/Utils/RiotSettings.swift index 38c25d1df..52c7a3c92 100644 --- a/Riot/Utils/RiotSettings.swift +++ b/Riot/Utils/RiotSettings.swift @@ -16,6 +16,7 @@ import Foundation +/// Store Riot specific app settings. @objcMembers final class RiotSettings: NSObject { @@ -37,6 +38,7 @@ final class RiotSettings: NSObject { // MARK: Notifications + /// Indicate if encrypted messages content should be displayed in notifications. var showDecryptedContentInNotifications: Bool { get { return UserDefaults.standard.bool(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) @@ -45,6 +47,7 @@ final class RiotSettings: NSObject { } } + /// Indicate if rooms with missed notifications should be displayed first on home screen. var pinRoomsWithMissedNotificationsOnHome: Bool { get { return UserDefaults.standard.bool(forKey: UserDefaultsKeys.pinRoomsWithMissedNotifications) @@ -53,6 +56,7 @@ final class RiotSettings: NSObject { } } + /// Indicate if rooms with unread messages should be displayed first on home screen. var pinRoomsWithUnreadMessagesOnHome: Bool { get { return UserDefaults.standard.bool(forKey: UserDefaultsKeys.pinRoomsWithUnreadMessages) @@ -73,6 +77,11 @@ final class RiotSettings: NSObject { // MARK: Other + /// Indicate if `enableCrashReport` settings has been set once. + var isEnableCrashReportHasBeenSetOnce: Bool { + return UserDefaults.standard.object(forKey: UserDefaultsKeys.enableCrashReport) != nil + } + var enableCrashReport: Bool { get { return UserDefaults.standard.bool(forKey: UserDefaultsKeys.enableCrashReport) From 52fed220efcbca0c16e15fc546db404f112f102d Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 2 Jul 2018 17:14:39 +0200 Subject: [PATCH 46/54] Crypto: Telemetry: Categorise e2e failures #1894 --- Riot/Analytics/Analytics.m | 16 +++++----- Riot/Analytics/DecryptionFailure.h | 12 ++++++++ Riot/Analytics/DecryptionFailure.m | 7 +++++ Riot/Analytics/DecryptionFailureTracker.h | 6 ++-- Riot/Analytics/DecryptionFailureTracker.m | 36 +++++++++++++++++++---- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/Riot/Analytics/Analytics.m b/Riot/Analytics/Analytics.m index a376fbef8..5ba48b694 100644 --- a/Riot/Analytics/Analytics.m +++ b/Riot/Analytics/Analytics.m @@ -28,7 +28,6 @@ NSString *const kAnalyticsMetricsActionPattern = @"iOS.%@"; // E2E telemetry is stored under a Piwik category called "E2E". NSString *const kAnalyticsE2eCategory = @"E2E"; NSString *const kAnalyticsE2eDecryptionFailureAction = @"Decryption failure"; -NSString *const kAnalyticsE2eDecryptionFailureReasonNoReason = @"no_reason"; @import PiwikTracker; @@ -174,13 +173,16 @@ NSString *const kAnalyticsE2eDecryptionFailureReasonNoReason = @"no_reason"; #pragma mark - MXDecryptionFailureDelegate -- (void)trackFailures:(NSUInteger)failuresCount +- (void)trackFailures:(NSDictionary *)failuresCounts { - [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsE2eCategory - action:kAnalyticsE2eDecryptionFailureAction - name:kAnalyticsE2eDecryptionFailureReasonNoReason - number:@(failuresCount) - url:nil]; + for (NSString *reason in failuresCounts) + { + [[PiwikTracker shared] trackWithEventWithCategory:kAnalyticsE2eCategory + action:kAnalyticsE2eDecryptionFailureAction + name:reason + number:failuresCounts[reason] + url:nil]; + } } @end diff --git a/Riot/Analytics/DecryptionFailure.h b/Riot/Analytics/DecryptionFailure.h index df9f1af75..7ea43962c 100644 --- a/Riot/Analytics/DecryptionFailure.h +++ b/Riot/Analytics/DecryptionFailure.h @@ -16,6 +16,18 @@ #import +/** + Failure reasons as defined in https://docs.google.com/document/d/1es7cTCeJEXXfRCTRgZerAM2Wg5ZerHjvlpfTW-gsOfI. + */ +struct DecryptionFailureReasonStruct +{ + __unsafe_unretained NSString * const unspecified; + __unsafe_unretained NSString * const olmKeysNotSent; + __unsafe_unretained NSString * const olmIndexError; + __unsafe_unretained NSString * const unexpected; +}; +extern const struct DecryptionFailureReasonStruct DecryptionFailureReason; + /** `DecryptionFailure` represents a decryption failure. */ diff --git a/Riot/Analytics/DecryptionFailure.m b/Riot/Analytics/DecryptionFailure.m index 7cb470e8c..d43b0ec9f 100644 --- a/Riot/Analytics/DecryptionFailure.m +++ b/Riot/Analytics/DecryptionFailure.m @@ -16,6 +16,13 @@ #import "DecryptionFailure.h" +const struct DecryptionFailureReasonStruct DecryptionFailureReason = { + .unspecified = @"unspecified_error", + .olmKeysNotSent = @"olm_keys_not_sent_error", + .olmIndexError = @"olm_index_error", + .unexpected = @"unexpected_error" +}; + @implementation DecryptionFailure - (instancetype)init diff --git a/Riot/Analytics/DecryptionFailureTracker.h b/Riot/Analytics/DecryptionFailureTracker.h index 92c7587f1..45a8e1cee 100644 --- a/Riot/Analytics/DecryptionFailureTracker.h +++ b/Riot/Analytics/DecryptionFailureTracker.h @@ -16,6 +16,8 @@ #import +#import "DecryptionFailure.h" + @import MatrixSDK; @protocol MXDecryptionFailureDelegate; @@ -62,8 +64,8 @@ /** Stats for decryption failures. - @param failuresCount the number of decryption failures. + @param failuresCounts the number of errors per failure reason. */ -- (void)trackFailures:(NSUInteger)failuresCount; +- (void)trackFailures:(NSDictionary *)failuresCounts; @end diff --git a/Riot/Analytics/DecryptionFailureTracker.m b/Riot/Analytics/DecryptionFailureTracker.m index 240f0ecd2..ed87dd952 100644 --- a/Riot/Analytics/DecryptionFailureTracker.m +++ b/Riot/Analytics/DecryptionFailureTracker.m @@ -16,8 +16,6 @@ #import "DecryptionFailureTracker.h" -#import "DecryptionFailure.h" - // Call `checkFailures` every `CHECK_INTERVAL` #define CHECK_INTERVAL 5 @@ -93,8 +91,26 @@ DecryptionFailure *decryptionFailure = [[DecryptionFailure alloc] init]; decryptionFailure.failedEventId = event.eventId; - // TODO: Need to sync with all platforms - // decryptionFailure.reason =; + // Categorise the error + switch (event.decryptionError.code) + { + case MXDecryptingErrorUnknownInboundSessionIdCode: + decryptionFailure.reason = DecryptionFailureReason.olmKeysNotSent; + break; + + case MXDecryptingErrorOlmCode: + decryptionFailure.reason = DecryptionFailureReason.olmIndexError; + break; + + case MXDecryptingErrorEncryptionNotEnabledCode: + case MXDecryptingErrorUnableToDecryptCode: + decryptionFailure.reason = DecryptionFailureReason.unexpected; + break; + + default: + decryptionFailure.reason = DecryptionFailureReason.unspecified; + break; + } reportedFailures[event.eventId] = decryptionFailure; } @@ -128,8 +144,16 @@ if (_delegate && failuresToTrack.count) { - NSLog(@"[DecryptionFailureTracker] trackFailures: %@", @(failuresToTrack.count)); - [_delegate trackFailures:failuresToTrack.count]; + // Sort failures by error reason + NSMutableDictionary *failuresCounts = [NSMutableDictionary dictionary]; + for (DecryptionFailure *failure in failuresToTrack) + { + failuresCounts[failure.reason] = @(failuresCounts[failure.reason].unsignedIntegerValue + 1); + } + + NSLog(@"[DecryptionFailureTracker] trackFailures: %@", failuresCounts); + + [_delegate trackFailures:failuresCounts]; } } From bac72e440526b2700e2d0c308e161e94c456c841 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Mon, 2 Jul 2018 17:59:35 +0200 Subject: [PATCH 47/54] Enable Swift in share extension. Add RiotSettings to share extension target. --- Riot.xcodeproj/project.pbxproj | 20 +++++++++++++++++++ .../RiotShareExtension-Bridging-Header.h | 4 ++++ 2 files changed, 24 insertions(+) create mode 100644 RiotShareExtension/RiotShareExtension-Bridging-Header.h diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index c920ed7a0..4521654de 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -121,6 +121,7 @@ B19A173920B7F94800DF0BB0 /* DeactivateAccountViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B19A173820B7F94800DF0BB0 /* DeactivateAccountViewController.m */; }; B19A173B20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B19A173A20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard */; }; B1D818C020EA4C7400D5F36D /* RiotSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D818BF20EA4C7400D5F36D /* RiotSettings.swift */; }; + B1D818C120EA794400D5F36D /* RiotSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D818BF20EA4C7400D5F36D /* RiotSettings.swift */; }; DDDE2AB95F865F2292B1D315 /* Pods_RiotPods_RiotShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23D7292481328A48B8D5D4ED /* Pods_RiotPods_RiotShareExtension.framework */; }; F0131DE51F2200D600CBF707 /* RiotSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */; }; F0173EB51FCF346800B5F6A3 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = F0173EAF1FCF346800B5F6A3 /* Vector.strings */; }; @@ -824,6 +825,7 @@ B19A173A20B7F96700DF0BB0 /* DeactivateAccountViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = DeactivateAccountViewController.storyboard; sourceTree = ""; }; B1D818BC20E66C3300D5F36D /* Riot-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Riot-Bridging-Header.h"; sourceTree = ""; }; B1D818BF20EA4C7400D5F36D /* RiotSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RiotSettings.swift; sourceTree = ""; }; + B1D818C220EA7DB500D5F36D /* RiotShareExtension-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "RiotShareExtension-Bridging-Header.h"; path = "RiotShareExtension/RiotShareExtension-Bridging-Header.h"; sourceTree = SOURCE_ROOT; }; C195C53961EA28E6900AEB68 /* Pods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.release.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.release.xcconfig"; sourceTree = ""; }; C5258DFF261AA3AB228A3F11 /* Pods-RiotPods-RiotShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-RiotShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RiotPods-RiotShareExtension/Pods-RiotPods-RiotShareExtension.debug.xcconfig"; sourceTree = ""; }; DB50EEBE8214352B9EBD6394 /* Pods_RiotPods_SiriIntents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RiotPods_SiriIntents.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1509,6 +1511,7 @@ isa = PBXGroup; children = ( 2466B7551F2F80B800AE27B0 /* Info.plist */, + B1D818C220EA7DB500D5F36D /* RiotShareExtension-Bridging-Header.h */, 2466B7561F2F80B800AE27B0 /* RiotShareExtension.entitlements */, 24D6B3441F3C8F8A00FC7A71 /* ViewController */, 2439DD5F1F6BBE390090F42D /* Views */, @@ -3523,6 +3526,7 @@ buildActionMask = 2147483647; files = ( 24EEE5A01F23A08900B3C705 /* RoomTableViewCell.m in Sources */, + B1D818C120EA794400D5F36D /* RiotSettings.swift in Sources */, 24D6B3581F3C90D300FC7A71 /* ShareDataSource.m in Sources */, 245FC3EF1F3DD30800603C6A /* RecentCellData.m in Sources */, 24D6B35C1F3CA03600FC7A71 /* RoomsListViewController.m in Sources */, @@ -4038,12 +4042,19 @@ DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 7J4U792NQT; ENABLE_BITCODE = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "COCOAPODS=1", + "IS_SHARE_EXTENSION=1", + ); INFOPLIST_FILE = RiotShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.shareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/$(PRODUCT_NAME)/RiotShareExtension-Bridging-Header.h"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -4061,12 +4072,19 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 7J4U792NQT; ENABLE_BITCODE = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "COCOAPODS=1", + "IS_SHARE_EXTENSION=1", + ); INFOPLIST_FILE = RiotShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.shareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/$(PRODUCT_NAME)/RiotShareExtension-Bridging-Header.h"; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -4202,6 +4220,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = A5030B7C3C0B6EB83A9257BD /* Pods-RiotPods-Riot.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Riot/Riot.entitlements; @@ -4241,6 +4260,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = F546BCBBB9BBEE67DB28878A /* Pods-RiotPods-Riot.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Riot/Riot.entitlements; diff --git a/RiotShareExtension/RiotShareExtension-Bridging-Header.h b/RiotShareExtension/RiotShareExtension-Bridging-Header.h new file mode 100644 index 000000000..1b2cb5d6d --- /dev/null +++ b/RiotShareExtension/RiotShareExtension-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + From 3d54608b485ee6833f97349079a6b370821bdafc Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Mon, 2 Jul 2018 18:01:33 +0200 Subject: [PATCH 48/54] Handle correct target Swift module import in RiotDesignValues --- Riot/Utils/RiotDesignValues.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Riot/Utils/RiotDesignValues.m b/Riot/Utils/RiotDesignValues.m index 5399444d3..1c381a36e 100644 --- a/Riot/Utils/RiotDesignValues.m +++ b/Riot/Utils/RiotDesignValues.m @@ -16,7 +16,13 @@ */ #import "RiotDesignValues.h" + +#ifdef IS_SHARE_EXTENSION +#import "RiotShareExtension-Swift.h" +#else #import "Riot-Swift.h" +#endif + NSString *const kRiotDesignValuesDidChangeThemeNotification = @"kRiotDesignValuesDidChangeThemeNotification"; From 759008e0220e63a4498f163764e85a72bce7f76e Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Mon, 2 Jul 2018 18:04:52 +0200 Subject: [PATCH 49/54] Fix check for `enableCrashReport` value set in MasterTabBarController --- Riot/ViewController/MasterTabBarController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/ViewController/MasterTabBarController.m b/Riot/ViewController/MasterTabBarController.m index 036f008a4..25da2d2ab 100644 --- a/Riot/ViewController/MasterTabBarController.m +++ b/Riot/ViewController/MasterTabBarController.m @@ -148,7 +148,7 @@ { // Check whether the user has been already prompted to send crash reports. // (Check whether 'enableCrashReport' flag has been set once) - if (!RiotSettings.shared.enableCrashReport) + if (!RiotSettings.shared.isEnableCrashReportHasBeenSetOnce) { [self promptUserBeforeUsingAnalytics]; } From 8c8ef75b108247dffabeb8717704b82c09ce17a2 Mon Sep 17 00:00:00 2001 From: SBiOSoftWhare Date: Tue, 3 Jul 2018 10:31:14 +0200 Subject: [PATCH 50/54] Fix `showDecryptedContentInNotifications` settings option not migrated correctly from MXKAccount --- Riot/AppDelegate.m | 10 ++++------ Riot/Utils/RiotSettings.swift | 5 +++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 9152a2be9..e8a17510b 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -4025,20 +4025,18 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN - (void)setupUserDefaults { - // Retrieve custom configuration + // Register "Riot-Defaults.plist" default values NSString* userDefaults = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UserDefaults"]; NSString *defaultsPathFromApp = [[NSBundle mainBundle] pathForResource:userDefaults ofType:@"plist"]; NSDictionary *defaults = [NSDictionary dictionaryWithContentsOfFile:defaultsPathFromApp]; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; - [[NSUserDefaults standardUserDefaults] synchronize]; // Now use RiotSettings and NSUserDefaults to store `showDecryptedContentInNotifications` setting option - // Migrate this information from main MXKAccount to RiotSettings, only if value was set to YES as default value is NO + // Migrate this information from main MXKAccount to RiotSettings, if value is not in UserDefaults - MXKAccount *currentAccount = [MXKAccountManager sharedManager].activeAccounts.firstObject; - - if (currentAccount.showDecryptedContentInNotifications) + if (!RiotSettings.shared.isShowDecryptedContentInNotificationsHasBeenSetOnce) { + MXKAccount *currentAccount = [MXKAccountManager sharedManager].activeAccounts.firstObject; RiotSettings.shared.showDecryptedContentInNotifications = currentAccount.showDecryptedContentInNotifications; } } diff --git a/Riot/Utils/RiotSettings.swift b/Riot/Utils/RiotSettings.swift index 52c7a3c92..e91b0ab15 100644 --- a/Riot/Utils/RiotSettings.swift +++ b/Riot/Utils/RiotSettings.swift @@ -38,6 +38,11 @@ final class RiotSettings: NSObject { // MARK: Notifications + /// Indicate if `showDecryptedContentInNotifications` settings has been set once. + var isShowDecryptedContentInNotificationsHasBeenSetOnce: Bool { + return UserDefaults.standard.object(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) != nil + } + /// Indicate if encrypted messages content should be displayed in notifications. var showDecryptedContentInNotifications: Bool { get { From fbe0ba8d42bc9e6d08e4bed8cbb41bd0e93d39a7 Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Thu, 21 Jun 2018 09:40:35 +0000 Subject: [PATCH 51/54] Translated using Weblate (Bulgarian) Currently translated at 100.0% (505 of 505 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/bg/ --- Riot/Assets/bg.lproj/Vector.strings | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Riot/Assets/bg.lproj/Vector.strings b/Riot/Assets/bg.lproj/Vector.strings index 7ae92bd2c..7143cae6f 100644 --- a/Riot/Assets/bg.lproj/Vector.strings +++ b/Riot/Assets/bg.lproj/Vector.strings @@ -537,3 +537,8 @@ "deactivate_account_validate_action" = "Деактивирай акаунта"; "deactivate_account_password_alert_title" = "Деактивиране на акаунт"; "deactivate_account_password_alert_message" = "За да продължите, моля въведете паролата си"; +"event_formatter_rerequest_keys_part1_link" = "Изисквай повторно ключове за шифроване"; +"event_formatter_rerequest_keys_part2" = " от другите ми устройства."; +// Re-request confirmation dialog +"rerequest_keys_alert_title" = "Заявката е изпратена"; +"rerequest_keys_alert_message" = "Моля стартирайте Riot на друго устройство можещо да разшифрова съобщението, за да може то да изпрати ключовете до това устройство."; From f84bdd022c56ac37843ba6048c4416dd776f8ea0 Mon Sep 17 00:00:00 2001 From: Mathijs van Gorcum Date: Fri, 29 Jun 2018 11:55:53 +0000 Subject: [PATCH 52/54] Translated using Weblate (Dutch) Currently translated at 100.0% (505 of 505 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/nl/ --- Riot/Assets/nl.lproj/Vector.strings | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Riot/Assets/nl.lproj/Vector.strings b/Riot/Assets/nl.lproj/Vector.strings index aeaa70bd1..8368d71c6 100644 --- a/Riot/Assets/nl.lproj/Vector.strings +++ b/Riot/Assets/nl.lproj/Vector.strings @@ -546,3 +546,26 @@ // GDPR "gdpr_consent_not_given_alert_message" = "Om de %@ thuisserver te blijven gebruiken moet je de algemeen voorwaarden lezen en daarmee akkoord gaan."; "gdpr_consent_not_given_alert_review_now_action" = "Nu doorlezen"; +"room_action_send_photo_or_video" = "Foto of video versturen"; +"room_action_send_sticker" = "Sticker versturen"; +"settings_deactivate_account" = "DEACTIVEER ACCOUNT"; +"deactivate_account_forget_messages_information_part2_emphasize" = "Waarschuwing"; +// Re-request confirmation dialog +"rerequest_keys_alert_title" = "Aanvraag verstuurd"; +"rerequest_keys_alert_message" = "Start Riot alstublieft op een ander apparaat dat het bericht kan ontsleutelen zodat deze de sleutels kan sturen naar dit apparaat."; +"settings_deactivate_my_account" = "Account deactiveren"; +"event_formatter_rerequest_keys_part1_link" = "Vraag beveiligingssleutels opnieuw aan"; +"event_formatter_rerequest_keys_part2" = " van je andere apparaten."; +"widget_sticker_picker_no_stickerpacks_alert" = "Je hebt momenteel geen stickerpakketten aan staan."; +"widget_sticker_picker_no_stickerpacks_alert_add_now" = "Wil je er nu een paar toevoegen?"; +"deactivate_account_title" = "Account deactiveren"; +"deactivate_account_informations_part1" = "Dit zal je account voorgoed onbruikbaar maken. Je zal niet meer in kunnen loggen en niemand anders zal met dezelfde gebruikers ID kunnen registreren. Dit zal er voor zorgen dat je account alle ruimtes verlaat waar het momenteel onderdeel van is en het verwijderd de accountgegevens van de identiteitsserver. "; +"deactivate_account_informations_part2_emphasize" = "Deze actie is onomkeerbaar."; +"deactivate_account_informations_part3" = "\n\nHet deactiveren van je account "; +"deactivate_account_informations_part4_emphasize" = "zal er niet standaard voor zorgen dat de berichten die je verzonden hebt vergeten worden. "; +"deactivate_account_informations_part5" = "Als je wilt dat wij de berichten vergeten, klikt alsjeblieft op het vakje hieronder.\n\nDe zichtbaarheid van berichten in Matrix is hetzelfde als in e-mail. Het vergeten van je berichten betekent dat berichten die je hebt verstuurd niet meer gedeeld worden met nieuwe of ongeregistreerde gebruikers, maar geregistreerde gebruikers die al toegang hebben tot deze berichten zullen alsnog toegang hebben tot hun eigen kopie van het bericht."; +"deactivate_account_forget_messages_information_part1" = "Vergeet alle berichten die ik heb verstuurd wanneer mijn account gedeactiveerd is ("; +"deactivate_account_forget_messages_information_part3" = ": dit zal er voor zorgen dat toekomstige gebruikers een incompleet beeld krijgen van gesprekken)"; +"deactivate_account_validate_action" = "Account deactiveren"; +"deactivate_account_password_alert_title" = "Account deactiveren"; +"deactivate_account_password_alert_message" = "Voer je wachtwoord in om verder te gaan"; From a2358a088d2928e1607a07ce965ebf61f096f4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Jatob=C3=A1?= Date: Sun, 1 Jul 2018 21:38:42 +0000 Subject: [PATCH 53/54] Translated using Weblate (Portuguese (Brazil)) Currently translated at 28.9% (146 of 505 strings) Translation: Riot iOS/Riot iOS Translate-URL: https://translate.riot.im/projects/riot-ios/riot-ios/pt_BR/ --- Riot/Assets/pt_BR.lproj/Vector.strings | 67 ++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings index 3ab493a1e..d45422cc9 100644 --- a/Riot/Assets/pt_BR.lproj/Vector.strings +++ b/Riot/Assets/pt_BR.lproj/Vector.strings @@ -87,3 +87,70 @@ "auth_reset_password_error_unauthorized" = "Não foi possível verificar o endereço de e-mail: confirme que realmente clicou no link contido na mensagem de e-mail"; "auth_reset_password_error_not_found" = "O seu endereço de e-mail não parece estar associado a um ID Matrix neste Servidor de Base (Home Server)."; "auth_reset_password_success_message" = "Sua senha foi redefinida.\n\nVocê foi deslogado de todos os dispositivos e não receberá notificações. Para reativar as notificações, faça login novamente em cada um dos dispositivos."; +"auth_add_email_and_phone_warning" = "Registro com email e número de telefone ainda não é suportado enquanto existir a API. Apenas o número de telefone será associado a sua conta. Você pode adicionar seu email ao seu perfil nas configurações."; +"room_creation_appearance" = "Aparência"; +"room_creation_appearance_name" = "Nome"; +"room_creation_appearance_picture" = "Imagem da Sala (opcional)"; +"room_creation_privacy" = "Privacidade"; +"room_creation_private_room" = "Esta conversa é privada"; +"room_creation_public_room" = "Esta conversa é pública"; +"room_creation_make_public" = "Tornar público"; +"room_creation_make_public_prompt_title" = "Tornar esta conversa pública?"; +"room_creation_make_public_prompt_msg" = "Você tem certeza que deseja tornar esta conversa pública? Qualquer um poderá ler suas mensagens e entrar na conversa."; +"room_creation_keep_private" = "Manter privada"; +"room_creation_make_private" = "Manter privada"; +"room_creation_wait_for_creation" = "A sala já está sendo criada. Por favor aguarde."; +"room_creation_invite_another_user" = "Procurar / convidar por ID da usuária/o, Nome ou email"; +"room_recents_directory_section_network" = "Rede"; +"room_recents_favourites_section" = "FAVORITOS"; +"room_recents_people_section" = "PESSOAS"; +"room_recents_conversations_section" = "SALAS"; +"room_recents_no_conversation" = "Nenhuma sala"; +"room_recents_low_priority_section" = "BAIXA PRIORIDADE"; +"room_recents_invites_section" = "CONVITES"; +"room_recents_start_chat_with" = "Iniciar conversa"; +"room_recents_create_empty_room" = "Criar sala"; +"room_recents_join_room" = "Entrar na sala"; +"room_recents_join_room_title" = "Entrar na sala"; +"room_recents_join_room_prompt" = "Digite o id da sala ou o nome da sala"; +// People tab +"people_invites_section" = "CONVITES"; +"people_conversation_section" = "CONVERSAS"; +"people_no_conversation" = "Nenhuma conversa"; +// Rooms tab +"room_directory_no_public_room" = "Não existem salas públicas disponíveis"; +// Groups tab +"group_invite_section" = "CONVITES"; +"group_section" = "Comunidades"; +// Search +"search_rooms" = "Salas"; +"search_messages" = "Mensagens"; +"search_people" = "Pessoas"; +"search_files" = "Arquivos"; +"search_default_placeholder" = "Procurar"; +"search_people_placeholder" = "Procurar por ID da/o usuária/o, Nome ou email"; +"search_no_result" = "Nenhum resultado"; +"search_in_progress" = "Procurando…"; +// Directory +"directory_cell_title" = "Procurar no diretório"; +"directory_cell_description" = "%tu salas"; +"directory_search_results" = "%tu resultados encontrados para %@"; +"directory_search_results_more_than" = ">%tu resultados encontrados para %@"; +"directory_searching_title" = "Procurando no diretório…"; +// Contacts +"contacts_address_book_section" = "CONTATOS LOCAIS"; +"contacts_address_book_matrix_users_toggle" = "Apenas usuários Matrix"; +"contacts_address_book_no_contact" = "Nenhum contato local"; +"contacts_address_book_permission_required" = "É preciso autorização para acessar contatos locais"; +"contacts_address_book_permission_denied" = "Você não permitiu o Riot acessar seus contatos locais"; +"contacts_user_directory_section" = "DIRETÓRIO DE USUÁRIOS"; +"contacts_user_directory_offline_section" = "DIRETÓRIO DE USUÁRIOS (sem conexão)"; +// Chat participants +"room_participants_title" = "Participantes"; +"room_participants_add_participant" = "Adicionar participantes"; +"room_participants_one_participant" = "1 participante"; +"room_participants_multi_participants" = "%d participantes"; +"room_participants_leave_prompt_title" = "Sair da sala"; +"room_participants_leave_prompt_msg" = "Você tem certeza que deseja sair da sala?"; +"room_participants_remove_prompt_title" = "Confirmação"; +"room_participants_remove_prompt_msg" = "Você tem certeza que deseja remover %@ desta conversa?"; From dc35ba20bfeb2f3470d6dd503d26d4b5613ef933 Mon Sep 17 00:00:00 2001 From: manuroe Date: Tue, 3 Jul 2018 16:04:11 +0200 Subject: [PATCH 54/54] version++ --- CHANGES.rst | 5 ++-- Podfile | 2 +- Podfile.lock | 52 +++++++++++++++++------------------ Riot/Info.plist | 4 +-- RiotShareExtension/Info.plist | 2 +- SiriIntents/Info.plist | 2 +- 6 files changed, 34 insertions(+), 33 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 5dd055bf1..8cdeb7417 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,8 +1,8 @@ -Changes in 0.6.18 () +Changes in 0.6.18 (2018-07-03) =============================================== Improvements: - * Upgrade MatrixKit version (). + * Upgrade MatrixKit version (v0.7.15). * RoomVC: Add a re-request keys button on message unable to decrypt (#1879). * Analytics: Move code from AppDelegate to a dedicated class: Analytics. * Analytics: Track Matrix SDK stats (time to startup the app). @@ -12,6 +12,7 @@ Improvements: Bug fix: * RoomVC: Read receipts processing dramatically slows down UI (#1899). + * Lag in typing (#1820). * E2E messages not decrypted in notifs after logging back in (#1914). Changes in 0.6.17 (2018-06-01) diff --git a/Podfile b/Podfile index 7d537bedb..d9d427d94 100644 --- a/Podfile +++ b/Podfile @@ -9,7 +9,7 @@ source 'https://github.com/CocoaPods/Specs.git' # Different flavours of pods to MatrixKit # The current MatrixKit pod version -$matrixKitVersion = '0.7.14' +$matrixKitVersion = '0.7.15' # The develop branch version #$matrixKitVersion = 'develop' diff --git a/Podfile.lock b/Podfile.lock index 01b0c1cae..bbcc75a9a 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -37,40 +37,40 @@ PODS: - DTFoundation/Core - DTFoundation/UIKit (1.7.13): - DTFoundation/Core - - GBDeviceInfo (5.1.0): - - GBDeviceInfo/Core (= 5.1.0) - - GBDeviceInfo/Core (5.1.0) + - GBDeviceInfo (5.2.0): + - GBDeviceInfo/Core (= 5.2.0) + - GBDeviceInfo/Core (5.2.0) - GZIP (1.2.1) - HPGrowingTextView (1.1) - libPhoneNumber-iOS (0.9.13) - - MatrixKit (0.7.14): + - MatrixKit (0.7.15): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.21) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixKit/Core (= 0.7.14) - - MatrixSDK (= 0.10.11) - - MatrixKit/AppExtension (0.7.14): + - MatrixKit/Core (= 0.7.15) + - MatrixSDK (= 0.10.12) + - MatrixKit/AppExtension (0.7.15): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.21) - DTCoreText/Extension - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.10.11) - - MatrixKit/Core (0.7.14): + - MatrixSDK (= 0.10.12) + - MatrixKit/Core (0.7.15): - cmark (~> 0.24.1) - DTCoreText (~> 1.6.21) - HPGrowingTextView (~> 1.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.10.11) - - MatrixSDK (0.10.11): - - MatrixSDK/Core (= 0.10.11) - - MatrixSDK/Core (0.10.11): + - MatrixSDK (= 0.10.12) + - MatrixSDK (0.10.12): + - MatrixSDK/Core (= 0.10.12) + - MatrixSDK/Core (0.10.12): - AFNetworking (~> 3.2.0) - GZIP (~> 1.2.1) - OLMKit (~> 2.2.2) - - Realm (~> 3.3.2) - - MatrixSDK/JingleCallStack (0.10.11): + - Realm (~> 3.6.0) + - MatrixSDK/JingleCallStack (0.10.12): - MatrixSDK/Core - WebRTC (= 63.11.20455) - OLMKit (2.2.2): @@ -81,17 +81,17 @@ PODS: - PiwikTracker (4.4.2): - PiwikTracker/Core (= 4.4.2) - PiwikTracker/Core (4.4.2) - - Realm (3.3.2): - - Realm/Headers (= 3.3.2) - - Realm/Headers (3.3.2) + - Realm (3.6.0): + - Realm/Headers (= 3.6.0) + - Realm/Headers (3.6.0) - WebRTC (63.11.20455) DEPENDENCIES: - cmark - DTCoreText - - GBDeviceInfo (~> 5.1.0) - - MatrixKit (= 0.7.14) - - MatrixKit/AppExtension (= 0.7.14) + - GBDeviceInfo (~> 5.2.0) + - MatrixKit (= 0.7.15) + - MatrixKit/AppExtension (= 0.7.15) - MatrixSDK/JingleCallStack - OLMKit - PiwikTracker (from `https://github.com/manuroe/matomo-sdk-ios.git`, branch `feature/CustomVariables`) @@ -127,17 +127,17 @@ SPEC CHECKSUMS: cmark: ec0275215b504780287b6fca360224e384368af8 DTCoreText: e5d688cffc9f6a61eddd1a4f94e2046851230de3 DTFoundation: f03be9fd786f11e505bb8fc44e2a3732bf0917df - GBDeviceInfo: 8e43440ae1264d9a79beea81800363cf192ce322 + GBDeviceInfo: 2c65ceb9404f9079264d4c238f5b81916fdfc5e2 GZIP: 7ee835f989fb3c6ea79005fc90b8fa6af710a70d HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19 libPhoneNumber-iOS: e444379ac18bbfbdefad571da735b2cd7e096caa - MatrixKit: ca192403abc03229f5cc5c193bd24a292e302304 - MatrixSDK: abb44d24e0426f3734630362c736d96446a629a3 + MatrixKit: 5668775ddcb36939f22cb5e76dcf617980c52c75 + MatrixSDK: 5d5eae9a9a098ec130022da4a4925332df8df1d9 OLMKit: b9d8c0ffee9ea8c45bc0aaa9afb47f93fba7efbd PiwikTracker: 42862c7b13028065c3dfd36b4dc38db8a5765acf - Realm: d927fbf66df5532cfafc08afb5f7e53ded37b894 + Realm: 08b464b462d4f31bbd4ba5f5a1c8722ef0a700b7 WebRTC: f2a6203584745fe53532633397557876b5d71640 -PODFILE CHECKSUM: f62acabc542b9493f2d704d8c5163a53051b1979 +PODFILE CHECKSUM: 948cd5479b6467245ee83ba82304e73d83c7e4e2 COCOAPODS: 1.5.3 diff --git a/Riot/Info.plist b/Riot/Info.plist index cbd7ee6ea..8377d7276 100644 --- a/Riot/Info.plist +++ b/Riot/Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.6.17 + 0.6.18 CFBundleSignature ???? CFBundleVersion - 0.6.17 + 0.6.18 ITSAppUsesNonExemptEncryption ITSEncryptionExportComplianceCode diff --git a/RiotShareExtension/Info.plist b/RiotShareExtension/Info.plist index 733c119fa..fd320e7e7 100644 --- a/RiotShareExtension/Info.plist +++ b/RiotShareExtension/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 0.6.17 + 0.6.18 CFBundleVersion 1 NSExtension diff --git a/SiriIntents/Info.plist b/SiriIntents/Info.plist index b9785df49..ab1b6d34b 100644 --- a/SiriIntents/Info.plist +++ b/SiriIntents/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 0.6.17 + 0.6.18 CFBundleVersion 1 NSExtension