Release 2.0.0

This commit is contained in:
Frank Rotermund
2022-11-27 13:18:53 +00:00
parent bf57719009
commit 0dc8ec0982
570 changed files with 20366 additions and 4410 deletions
@@ -321,6 +321,15 @@ typedef BOOL (^MXKAccountOnCertificateChange)(MXKAccount *mxAccount, NSData *cer
*/
- (void)load3PIDs:(void (^)(void))success failure:(void (^)(NSError *error))failure;
/**
Loads the pusher instance linked to this account.
This method must be called to refresh self.pushNotificationServiceIsActive
@param success A block object called when the operation succeeds.
@param failure A block object called when the operation fails.
*/
- (void)loadCurrentPusher:(nullable void (^)(void))success failure:(nullable void (^)(NSError *error))failure;
/**
Load the current device information for this account.
This method must be called to refresh self.device.
@@ -86,6 +86,8 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
// Observe NSCurrentLocaleDidChangeNotification to refresh MXRoomSummaries on time formatting change.
id NSCurrentLocaleDidChangeNotificationObserver;
MXPusher *currentPusher;
}
/// Will be true if the session is not in a pauseable state or we requested for the session to pause but not finished yet. Will be reverted to false again after `resume` called.
@@ -148,6 +150,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
userPresence = MXPresenceUnknown;
// Refresh device information
[self loadDeviceInformation:nil failure:nil];
[self loadCurrentPusher:nil failure:nil];
[self registerAccountDataDidChangeIdentityServerNotification];
[self registerIdentityServiceDidChangeAccessTokenNotification];
@@ -182,6 +185,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
userPresence = MXPresenceUnknown;
// Refresh device information
[self loadDeviceInformation:nil failure:nil];
[self loadCurrentPusher:nil failure:nil];
}
return self;
@@ -310,6 +314,12 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
- (BOOL)pushNotificationServiceIsActive
{
if (currentPusher && currentPusher.enabled)
{
MXLogDebug(@"[MXKAccount][Push] pushNotificationServiceIsActive: currentPusher.enabled %@", currentPusher.enabled);
return currentPusher.enabled.boolValue;
}
BOOL pushNotificationServiceIsActive = ([[MXKAccountManager sharedManager] isAPNSAvailable] && self.hasPusherForPushNotifications && mxSession);
MXLogDebug(@"[MXKAccount][Push] pushNotificationServiceIsActive: %@", @(pushNotificationServiceIsActive));
@@ -324,7 +334,44 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
if (enable)
{
if ([[MXKAccountManager sharedManager] isAPNSAvailable])
if (currentPusher && currentPusher.enabled && !currentPusher.enabled.boolValue)
{
[self.mxSession.matrixRestClient setPusherWithPushkey:currentPusher.pushkey
kind:currentPusher.kind
appId:currentPusher.appId
appDisplayName:currentPusher.appDisplayName
deviceDisplayName:currentPusher.deviceDisplayName
profileTag:currentPusher.profileTag
lang:currentPusher.lang
data:currentPusher.data.JSONDictionary
append:NO
enabled:enable
success:^{
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: remotely enabled Push: Success");
[self loadCurrentPusher:^{
if (success)
{
success();
}
} failure:^(NSError *error) {
MXLogWarning(@"[MXKAccount][Push] enablePushNotifications: load current pusher failed with error: %@", error);
if (failure)
{
failure(error);
}
}];
} failure:^(NSError *error) {
MXLogWarning(@"[MXKAccount][Push] enablePushNotifications: remotely enable push failed with error: %@", error);
if (failure)
{
failure(error);
}
}];
}
else if ([[MXKAccountManager sharedManager] isAPNSAvailable])
{
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Enable Push for %@ account", self.mxCredentials.userId);
@@ -361,7 +408,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
}
}
}
else if (self.hasPusherForPushNotifications)
else if (self.hasPusherForPushNotifications || currentPusher)
{
MXLogDebug(@"[MXKAccount][Push] enablePushNotifications: Disable APNS for %@ account", self.mxCredentials.userId);
@@ -633,6 +680,65 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
}];
}
- (void)loadCurrentPusher:(void (^)(void))success failure:(void (^)(NSError *error))failure
{
if (!self.mxSession.myDeviceId)
{
MXLogWarning(@"[MXKAccount] loadPusher: device ID not found");
if (failure)
{
failure([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:nil]);
}
return;
}
[self.mxSession supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) {
if (!matrixVersions.supportsRemotelyTogglingPushNotifications)
{
MXLogDebug(@"[MXKAccount] loadPusher: remotely toggling push notifications not supported");
if (success)
{
success();
}
return;
}
[self.mxSession.matrixRestClient pushers:^(NSArray<MXPusher *> *pushers) {
MXPusher *ownPusher;
for (MXPusher *pusher in pushers)
{
if ([pusher.deviceId isEqualToString:self.mxSession.myDeviceId])
{
ownPusher = pusher;
}
}
self->currentPusher = ownPusher;
if (success)
{
success();
}
} failure:^(NSError *error) {
MXLogWarning(@"[MXKAccount] loadPusher: get pushers failed due to error %@", error);
if (failure)
{
failure(error);
}
}];
} failure:^(NSError *error) {
MXLogWarning(@"[MXKAccount] loadPusher: supportedMatrixVersions failed due to error %@", error);
if (failure)
{
failure(error);
}
}];
}
- (void)loadDeviceInformation:(void (^)(void))success failure:(void (^)(NSError *error))failure
{
if (self.mxCredentials.deviceId)
@@ -672,7 +778,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
{
userPresence = presence;
if (mxSession && (!hideUserPresence || BuildSettings.bwiPersonalState))
if (mxSession && (!hideUserPresence || BWIBuildSettings.shared.bwiPersonalState))
{
// Update user presence on server side
[mxSession.myUser setPresence:userPresence
@@ -780,7 +886,9 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
[MXKContactManager.sharedManager validateSyncLocalContactsStateForSession:self.mxSession];
// Refresh pusher state
[self refreshAPNSPusher];
[self loadCurrentPusher:^{
[self refreshAPNSPusher];
} failure:nil];
[self refreshPushKitPusher];
// Launch server sync
@@ -851,7 +959,10 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
{
// Force a reload of device keys at the next session start.
// This will fix potential UISIs other peoples receive for our messages.
[mxSession.crypto resetDeviceKeys];
if ([mxSession.crypto isKindOfClass:[MXLegacyCrypto class]])
{
[(MXLegacyCrypto *)mxSession.crypto resetDeviceKeys];
}
// Clean other stores
[mxSession.scanManager deleteAllAntivirusScans];
@@ -1113,6 +1224,12 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
- (void)refreshAPNSPusher
{
MXLogDebug(@"[MXKAccount][Push] refreshAPNSPusher");
if (currentPusher)
{
MXLogDebug(@"[MXKAccount][Push] refreshAPNSPusher aborted as a pusher has been found");
return;
}
// Check the conditions required to run the pusher
if (self.pushNotificationServiceIsActive)
@@ -1172,12 +1289,35 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
self->_hasPusherForPushNotifications = enabled;
[[MXKAccountManager sharedManager] saveAccounts];
if (success)
if (enabled)
{
success();
[self loadCurrentPusher:^{
if (success)
{
success();
}
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId];
} failure:^(NSError *error) {
if (success)
{
success();
}
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId];
}];
}
else
{
self->currentPusher = nil;
if (success)
{
success();
}
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId];
}
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKAccountAPNSActivityDidChangeNotification object:self.mxCredentials.userId];
} failure:^(NSError *error) {
@@ -1422,7 +1562,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
MXRestClient *restCli = self.mxRestClient;
[restCli setPusherWithPushkey:b64Token kind:kind appId:appId appDisplayName:appDisplayName deviceDisplayName:[[UIDevice currentDevice] name] profileTag:profileTag lang:deviceLang data:pushData append:append success:success failure:failure];
[restCli setPusherWithPushkey:b64Token kind:kind appId:appId appDisplayName:appDisplayName deviceDisplayName:[[UIDevice currentDevice] name] profileTag:profileTag lang:deviceLang data:pushData append:append enabled:enabled success:success failure:failure];
}
#pragma mark - InApp notifications
@@ -1613,8 +1753,18 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
return;
}
if (![mxSession.crypto.crossSigning isKindOfClass:[MXLegacyCrossSigning class]]) {
MXLogFailure(@"Device dehydratation is currently only supported by legacy cross signing, add support to all implementations");
if (failure)
{
failure(nil);
}
return;
}
MXLegacyCrossSigning *crossSigning = (MXLegacyCrossSigning *)mxSession.crypto.crossSigning;;
MXLogDebug(@"[MXKAccount] attemptDeviceDehydrationWithRetry: starting device dehydration");
[[MXKAccountManager sharedManager].dehydrationService dehydrateDeviceWithMatrixRestClient:mxRestClient crypto:mxSession.crypto dehydrationKey:keyData success:^(NSString *deviceId) {
[[MXKAccountManager sharedManager].dehydrationService dehydrateDeviceWithMatrixRestClient:mxRestClient crossSigning:crossSigning dehydrationKey:keyData success:^(NSString *deviceId) {
MXLogDebug(@"[MXKAccount] attemptDeviceDehydrationWithRetry: device successfully dehydrated");
if (success)
@@ -1270,7 +1270,7 @@ NSString *const MXKContactManagerDataType = @"org.matrix.kit.MXKContactManagerDa
- (void)refreshMatrixContacts
{
// bwi: only refresh contacts when file can be encrypted (SecureFileStore is only unlocked after Pin/pasphrase
if ( BwiBuildSettings.forcedPinProtection && !EncryptionKeyManager.shared.isInitFinished ) {
if ( BWIBuildSettings.shared.forcedPinProtection && !EncryptionKeyManager.shared.isInitFinished ) {
return;
};
@@ -518,52 +518,48 @@
- (CGSize)textContentSize:(NSAttributedString*)attributedText removeVerticalInset:(BOOL)removeVerticalInset
{
if (attributedText.length == 0) {
return CGSizeZero;
}
// Grab the default textContainer insets and lineFragmentPadding from a dummy text view.
// This has no business being here but the refactoring effort would be too great (sceriu 05.09.2022)
static UITextView* measurementTextView = nil;
if (!measurementTextView)
static UITextView* measurementTextViewWithoutInset = nil;
if (attributedText.length)
{
measurementTextView = [[UITextView alloc] init];
if (!measurementTextView)
{
measurementTextView = [[UITextView alloc] init];
measurementTextViewWithoutInset = [[UITextView alloc] init];
// Remove the container inset: this operation impacts only the vertical margin.
// Note: consider textContainer.lineFragmentPadding to remove horizontal margin
measurementTextViewWithoutInset.textContainerInset = UIEdgeInsetsZero;
}
// Select the right text view for measurement
UITextView *selectedTextView = (removeVerticalInset ? measurementTextViewWithoutInset : measurementTextView);
selectedTextView.frame = CGRectMake(0, 0, _maxTextViewWidth, 0);
selectedTextView.attributedText = attributedText;
// Force the layout manager to layout the text, fixes problems starting iOS 16
[selectedTextView.layoutManager ensureLayoutForTextContainer:selectedTextView.textContainer];
CGSize size = [selectedTextView sizeThatFits:selectedTextView.frame.size];
// Manage the case where a string attribute has a single paragraph with a left indent
// In this case, [UITextView sizeThatFits] ignores the indent and return the width
// of the text only.
// So, add this indent afterwards
NSRange textRange = NSMakeRange(0, attributedText.length);
NSRange longestEffectiveRange;
NSParagraphStyle *paragraphStyle = [attributedText attribute:NSParagraphStyleAttributeName atIndex:0 longestEffectiveRange:&longestEffectiveRange inRange:textRange];
if (NSEqualRanges(textRange, longestEffectiveRange))
{
size.width = size.width + paragraphStyle.headIndent;
}
return size;
}
CGFloat verticalInset = measurementTextView.textContainerInset.top + measurementTextView.textContainerInset.bottom;
CGFloat horizontalInset = measurementTextView.textContainer.lineFragmentPadding * 2;
CGSize size = [self sizeForAttributedString:attributedText fittingWidth:_maxTextViewWidth - horizontalInset];
// The result is expected to contain the textView textContainer's paddings. Add them back if necessary
if (removeVerticalInset == NO) {
size.height += verticalInset;
}
size.width += horizontalInset;
return size;
}
// https://stackoverflow.com/questions/54497598/nsattributedstring-boundingrect-returns-wrong-height
- (CGSize)sizeForAttributedString:(NSAttributedString *)attributedString fittingWidth:(CGFloat)width
{
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
CGRect boundingRect = CGRectMake(0.0, 0.0, width, CGFLOAT_MAX);
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:boundingRect.size];
textContainer.lineFragmentPadding = 0;
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[layoutManager addTextContainer: textContainer];
[textStorage addLayoutManager:layoutManager];
[layoutManager glyphRangeForBoundingRect:boundingRect inTextContainer:textContainer];
CGRect rect = [layoutManager usedRectForTextContainer:textContainer];
return CGRectIntegral(rect).size;
return CGSizeZero;
}
#pragma mark - Properties
@@ -65,9 +65,12 @@
_event = event;
_displayFix = MXKRoomBubbleComponentDisplayFixNone;
if ([event.content[@"format"] isEqualToString:kMXRoomMessageFormatHTML])
NSString *format = event.content[@"format"];
if ([format isKindOfClass:[NSString class]] && [format isEqualToString:kMXRoomMessageFormatHTML])
{
if ([((NSString*)event.content[@"formatted_body"]) containsString:@"<blockquote"])
NSString *formattedBody = (NSString*)event.content[@"formatted_body"];
if ([formattedBody isKindOfClass:[NSString class]] && [formattedBody containsString:@"<blockquote"])
{
_displayFix |= MXKRoomBubbleComponentDisplayFixHtmlBlockquote;
}