Merge branch 'gil/SP1_space_creation' into gil/5231_SP3-1_Update_room_settings_for_Spaces

# Conflicts:
#	Podfile.lock
This commit is contained in:
Gil Eluard
2022-02-21 17:57:58 +01:00
687 changed files with 8777 additions and 3697 deletions
@@ -125,7 +125,7 @@
"notice_room_history_visible_to_members_from_joined_point" = "%@ hat den zukünftigen Raumverlauf für alle Raumteilnehmer ab deren Einladung sichtbar gemacht.";
"notice_room_history_visible_to_members_from_joined_point_for_dm" = "%@ hat den zukünftigen Verlauf für alle Raumteilnehmer ab deren Einladung sichtbar gemacht.";
"notice_crypto_unable_to_decrypt" = "** Entschlüsselung nicht möglich: %@ **";
"notice_crypto_error_unknown_inbound_session_id" = "Die Sitzung des Absenders hat uns keine Schlüssel für diese Nachricht gesendet.";
"notice_crypto_error_unknown_inbound_session_id" = "Die absendende Sitzung hat uns keine Schlüssel für diese Nachricht gesendet.";
"notice_sticker" = "Aufkleber";
"notice_in_reply_to" = "Als Antwort auf";
// room display name
@@ -367,7 +367,7 @@
"notice_room_join" = "%@ joined";
"notice_room_leave" = "%@ left";
"notice_room_reject" = "%@ rejected the invitation";
"notice_room_kick" = "%@ kicked %@";
"notice_room_kick" = "%@ removed %@";
"notice_room_unban" = "%@ unbanned %@";
"notice_room_ban" = "%@ banned %@";
"notice_room_withdraw" = "%@ withdrew %@'s invitation";
@@ -399,7 +399,7 @@
"notice_room_join_by_you" = "You joined";
"notice_room_leave_by_you" = "You left";
"notice_room_reject_by_you" = "You rejected the invitation";
"notice_room_kick_by_you" = "You kicked %@";
"notice_room_kick_by_you" = "You removed %@";
"notice_room_unban_by_you" = "You unbanned %@";
"notice_room_ban_by_you" = "You banned %@";
"notice_room_withdraw_by_you" = "You withdrew %@'s invitation";
@@ -479,7 +479,7 @@
"num_members_one" = "%@ user";
"num_members_other" = "%@ users";
"invite" = "Invite";
"kick" = "Kick";
"kick" = "Remove from chat";
"ban" = "Ban";
"unban" = "Un-ban";
"message_unsaved_changes" = "There are unsaved changes. Leaving will discard them.";
@@ -99,7 +99,7 @@
"notice_image_attachment" = "anexo de imagem";
"notice_audio_attachment" = "anexo de áudio";
"notice_video_attachment" = "anexo de vídeo";
"notice_location_attachment" = "anexo de local";
"notice_location_attachment" = "anexo de localização";
"notice_file_attachment" = "anexo de arquivo";
"notice_invalid_attachment" = "anexo inválido";
"notice_unsupported_attachment" = "Anexo insuportado: %@";
@@ -476,3 +476,6 @@
"auth_username_in_use" = "Имя пользователя занято";
"rename" = "Переименовать";
"room_displayname_all_other_members_left" = "%@ (Вышел)";
"attachment_unsupported_preview_message" = "Этот тип файла не поддерживается.";
"attachment_unsupported_preview_title" = "Не удалось показать предварительный просмотр";
"message_reply_to_sender_sent_their_location" = "поделились своим местоположением.";
@@ -119,9 +119,9 @@
// Others
"user_id_title" = "ID používateľa:";
"e2e_passphrase_create" = "Vytvoriť heslo";
"e2e_passphrase_confirm" = "Potvrďte heslo";
"e2e_passphrase_enter" = "Zadajte heslo";
"e2e_passphrase_create" = "Vytvoriť prístupovú frázu";
"e2e_passphrase_confirm" = "Potvrďte prístupovú frázu";
"e2e_passphrase_enter" = "Zadajte prístupovú frázu";
// Search
"search_no_results" = "Žiadne výsledky";
@@ -547,3 +547,4 @@
"account_link_email" = "Prepojený email";
"account_linked_emails" = "Prepojené e-maily";
"room_event_encryption_info_event_fingerprint_key" = "Deklarovaný kľúč odtlačkov prstov Ed25519\n";
"notification_settings_notify_all_other" = "Oznámiť pre všetky ostatné správy/miestnosti";
@@ -259,9 +259,9 @@
"user_id_placeholder" = "t.ex.: @sven:hemserver";
"ssl_homeserver_url" = "Hemserver-URL: %@";
// Permissions
"camera_access_not_granted_for_call" = "Videosamtal kräver åtkomst till kameran men %@ har inte behörighet att använda den";
"microphone_access_not_granted_for_call" = "Samtal kräver åtkomst till mikrofonen men %@ har inte behörighet att använda den";
"local_contacts_access_not_granted" = "Upptäckt av användare från lokala kontakter kräver åtkomst till dina kontakter men %@ har inte behörighet att komma åt dem";
"camera_access_not_granted_for_call" = "Videosamtal kräver åtkomst till kameran men %@ är inte behörig att använda den";
"microphone_access_not_granted_for_call" = "Samtal kräver åtkomst till mikrofonen men %@ är inte behörig att använda den";
"local_contacts_access_not_granted" = "Upptäckt av användare från lokala kontakter kräver åtkomst till dina kontakter men %@ är inte behörig att komma åt dem";
"local_contacts_access_discovery_warning_title" = "Användarupptäckt";
"local_contacts_access_discovery_warning" = "För att upptäcka kontakter som redan använder Matrix kan %@ skicka e-postadresser och telefonnummer i din adressbok till din valda Matrixidentitetsserver. Där det stöds hashas personuppgifter innan de skickas - kontrollera din identitetsservers integritetspolicy för mer information.";
// Country picker
@@ -462,7 +462,7 @@
"call_voice_with_user" = "Röstsamtal med %@";
"call_ringing" = "Ringer…";
"e2e_passphrase_too_short" = "Lösenfras för kort (den måste vara minst %d tecken långt)";
"microphone_access_not_granted_for_voice_message" = "Röstmeddelanden kräver åtkomst till mikrofonen, men %@ har inte behörighet att använda den";
"microphone_access_not_granted_for_voice_message" = "Röstmeddelanden kräver åtkomst till mikrofonen, men %@ är inte behörig att använda den";
"message_reply_to_sender_sent_a_voice_message" = "skickade ett röstmeddelande.";
"attachment_large_with_resolution" = "Stor %@ (~%@)";
"attachment_medium_with_resolution" = "Mellan %@ (~%@)";
@@ -29,6 +29,11 @@
{
[super viewDidLoad];
if ([self providesCustomActivityIndicator]) {
// If a subclass provides custom activity indicator, the default one will not even be initialized.
return;
}
// Add default activity indicator
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityIndicator.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0];
@@ -56,9 +61,13 @@
#pragma mark - Activity indicator
- (BOOL)providesCustomActivityIndicator {
return NO;
}
- (void)startActivityIndicator
{
if (activityIndicator)
if (activityIndicator && ![self providesCustomActivityIndicator])
{
[self.view bringSubviewToFront:activityIndicator];
[activityIndicator startAnimating];
@@ -79,5 +88,4 @@
[activityIndicator stopAnimating];
}
@end
@@ -175,7 +175,11 @@
_attachmentsCollection.hidden = YES;
// Display collection cell in full screen
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
self.automaticallyAdjustsScrollViewInsets = NO;
#pragma clang diagnostic pop
}
- (BOOL)prefersStatusBarHidden
@@ -215,6 +215,8 @@
// and report the inputAccessoryView.superview of the firstResponder in self.keyboardView.
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)setKeyboardHeight:(CGFloat)keyboardHeight
{
// Deduce the bottom inset for the scroll view (Don't forget the potential tabBar)
@@ -229,6 +231,7 @@
insets.bottom = scrollViewInsetBottom;
self.authenticationScrollView.contentInset = insets;
}
#pragma clang diagnostic pop
- (void)destroy
{
@@ -981,7 +984,10 @@
{
// Trigger here a register request in order to associate the filled userId and password to the current session id
// This will check the availability of the userId at the same time
NSDictionary *parameters = @{@"auth": @{},
NSDictionary *parameters = @{@"auth": @{
@"session": self.authInputsView.authSession.session,
@"type": kMXLoginFlowTypeDummy
},
@"username": self.authInputsView.userId,
@"password": self.authInputsView.password,
@"bind_email": @(NO),
@@ -1422,29 +1422,31 @@ static const CGFloat kLocalPreviewMargin = 20;
}
}
- (void)updateProximityAndSleep
{
BOOL inCall = (mxCall.state == MXCallStateConnected || mxCall.state == MXCallStateRinging || mxCall.state == MXCallStateInviteSent || mxCall.state == MXCallStateConnecting || mxCall.state == MXCallStateCreateOffer || mxCall.state == MXCallStateCreateAnswer);
if (inCall)
{
BOOL isBuiltInReceiverUsed = self.isBuiltInReceiverAudioOuput;
// Enable the proximity monitoring when the built in receiver is used as the audio output.
BOOL enableProxMonitoring = isBuiltInReceiverUsed;
[[UIDevice currentDevice] setProximityMonitoringEnabled:enableProxMonitoring];
// Disable the idle timer during a video call, or during a voice call which is performed with the built-in receiver.
// Note: if the device is locked, VoIP calling get dropped if an incoming GSM call is received.
BOOL disableIdleTimer = mxCall.isVideoCall || isBuiltInReceiverUsed;
UIApplication *sharedApplication = [UIApplication performSelector:@selector(sharedApplication)];
if (sharedApplication)
{
sharedApplication.idleTimerDisabled = disableIdleTimer;
}
}
}
- (void)updateProximityAndSleep
{
BOOL inCall = (mxCall.state == MXCallStateConnected || mxCall.state == MXCallStateRinging || mxCall.state == MXCallStateInviteSent || mxCall.state == MXCallStateConnecting || mxCall.state == MXCallStateCreateOffer || mxCall.state == MXCallStateCreateAnswer);
BOOL isBuiltInReceiverUsed = self.isBuiltInReceiverAudioOuput;
// Enable the proximity monitoring when the built in receiver is used as the audio output.
BOOL enableProxMonitoring = inCall && isBuiltInReceiverUsed;
UIDevice *device = [UIDevice currentDevice];
if (device && device.isProximityMonitoringEnabled != enableProxMonitoring)
{
[device setProximityMonitoringEnabled:enableProxMonitoring];
}
// Disable the idle timer during a video call, or during a voice call which is performed with the built-in receiver.
// Note: if the device is locked, VoIP calling get dropped if an incoming GSM call is received.
BOOL disableIdleTimer = inCall && (mxCall.isVideoCall || isBuiltInReceiverUsed);
UIApplication *sharedApplication = [UIApplication performSelector:@selector(sharedApplication)];
if (sharedApplication && sharedApplication.isIdleTimerDisabled != disableIdleTimer)
{
sharedApplication.idleTimerDisabled = disableIdleTimer;
}
}
- (UIView *)createIncomingCallView
{
@@ -152,7 +152,7 @@ NSString* const kMXKCountryPickerViewControllerCountryCellId = @"kMXKCountryPick
{
UISearchController *searchController = [[UISearchController alloc]
initWithSearchResultsController:nil];
searchController.dimsBackgroundDuringPresentation = NO;
searchController.obscuresBackgroundDuringPresentation = NO;
searchController.hidesNavigationBarDuringPresentation = NO;
searchController.searchResultsUpdater = self;
@@ -92,6 +92,8 @@
[[[self class] nib] instantiateWithOwner:self options:nil];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
// Adjust search bar Top constraint to take into account potential navBar.
if (_groupsSearchBarTopConstraint)
{
@@ -123,6 +125,7 @@
[NSLayoutConstraint activateConstraints:@[_groupsTableViewBottomConstraint]];
}
#pragma clang diagnostic pop
// Hide search bar by default
[self hideSearchBar:YES];
@@ -209,6 +212,8 @@
self.keyboardView = _groupsSearchBar.inputAccessoryView.superview;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)setKeyboardHeight:(CGFloat)keyboardHeight
{
// Deduce the bottom constraint for the table view (Don't forget the potential tabBar)
@@ -225,6 +230,7 @@
// Force layout immediately to take into account new constraint
[self.view layoutIfNeeded];
}
#pragma clang diagnostic pop
- (void)destroy
{
@@ -160,7 +160,7 @@ NSString* const kMXKLanguagePickerCellDataKeyLanguage = @"language";
{
UISearchController *searchController = [[UISearchController alloc]
initWithSearchResultsController:nil];
searchController.dimsBackgroundDuringPresentation = NO;
searchController.obscuresBackgroundDuringPresentation = NO;
searchController.hidesNavigationBarDuringPresentation = NO;
searchController.searchResultsUpdater = self;
@@ -97,6 +97,8 @@
[[[self class] nib] instantiateWithOwner:self options:nil];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
// Adjust search bar Top constraint to take into account potential navBar.
if (_recentsSearchBarTopConstraint)
{
@@ -126,6 +128,7 @@
_recentsTableViewBottomConstraint.active = YES;
}
#pragma clang diagnostic pop
// Hide search bar by default
[self hideSearchBar:YES];
@@ -217,7 +220,7 @@
if ([MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession].isServerSyncInProgress)
{
// sync is in progress for at least one data source, keep running the loading wheel
[self.activityIndicator startAnimating];
[self startActivityIndicator];
break;
}
}
@@ -229,6 +232,8 @@
self.keyboardView = _recentsSearchBar.inputAccessoryView.superview;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)setKeyboardHeight:(CGFloat)keyboardHeight
{
// Deduce the bottom constraint for the table view (Don't forget the potential tabBar)
@@ -245,6 +250,7 @@
// Force layout immediately to take into account new constraint
[self.view layoutIfNeeded];
}
#pragma clang diagnostic pop
- (void)destroy
{
@@ -421,7 +427,9 @@
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// Let dataSource provide the section header.
return [dataSource viewForHeaderInSection:section withFrame:[tableView rectForHeaderInSection:section]];
return [dataSource viewForHeaderInSection:section
withFrame:[tableView rectForHeaderInSection:section]
inTableView:tableView];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
@@ -105,6 +105,8 @@
// Adjust Top and Bottom constraints to take into account potential navBar and tabBar.
[NSLayoutConstraint deactivateConstraints:@[_membersSearchBarTopConstraint, _membersTableViewBottomConstraint]];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
_membersSearchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
@@ -120,6 +122,7 @@
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
#pragma clang diagnostic pop
[NSLayoutConstraint activateConstraints:@[_membersSearchBarTopConstraint, _membersTableViewBottomConstraint]];
@@ -225,6 +228,8 @@
self.keyboardView = _membersSearchBar.inputAccessoryView.superview;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)setKeyboardHeight:(CGFloat)keyboardHeight
{
// Deduce the bottom constraint for the table view (Don't forget the potential tabBar)
@@ -241,6 +246,7 @@
// Force layout immediately to take into account new constraint
[self.view layoutIfNeeded];
}
#pragma clang diagnostic pop
- (void)destroy
{
@@ -76,6 +76,8 @@
// Adjust Top and Bottom constraints to take into account potential navBar and tabBar.
[NSLayoutConstraint deactivateConstraints:@[_searchSearchBarTopConstraint, _searchTableViewBottomConstraint]];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
_searchSearchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
@@ -91,6 +93,7 @@
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
#pragma clang diagnostic pop
[NSLayoutConstraint activateConstraints:@[_searchSearchBarTopConstraint, _searchTableViewBottomConstraint]];
@@ -140,6 +143,8 @@
self.keyboardView = _searchSearchBar.inputAccessoryView.superview;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)setKeyboardHeight:(CGFloat)keyboardHeight
{
// Deduce the bottom constraint for the table view (Don't forget the potential tabBar)
@@ -156,6 +161,7 @@
// Force layout immediately to take into account new constraint
[self.view layoutIfNeeded];
}
#pragma clang diagnostic pop
- (void)destroy
{
@@ -35,6 +35,14 @@
*/
@property (nonatomic) UIActivityIndicatorView *activityIndicator;
/**
A view controller may choose to implement a completely custom activity indicator (e.g. shared toast notification),
In this case the default `activityIndicator` will be hidden, and the view controller is responsible for overriding
`startActivityIndicator` and `stopActivityIndicator` methods to show / hide the custom activity indicator.
*/
@property (nonatomic, readonly) BOOL providesCustomActivityIndicator;
/**
Bring the activity indicator to the front and start it.
*/
@@ -133,6 +133,9 @@ NSString *const kMXKWebViewViewControllerJavaScriptEnableLog =
multiplier:1.0
constant:0];
// Force webview in full height
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:webView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
@@ -147,6 +150,7 @@ NSString *const kMXKWebViewViewControllerJavaScriptEnableLog =
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0];
#pragma clang diagnostic pop
[NSLayoutConstraint activateConstraints:@[leftConstraint, rightConstraint, topConstraint, bottomConstraint]];
+140 -136
View File
@@ -104,7 +104,9 @@ public class UTI: RawRepresentable, Equatable {
// UTTypeCreatePreferredIdentifierForTag only returns nil if the tag class is unknwown, which can't happen to us since we use an
// enum of known values. Hence we can force-cast the result.
// swiftlint:disable force_unwrapping
let identifier = (unmanagedIdentifier?.takeRetainedValue() as String?)!
// swiftlint:enable force_unwrapping
self.init(rawValue: identifier)
}
@@ -122,7 +124,7 @@ public class UTI: RawRepresentable, Equatable {
public convenience init(withExtension fileExtension: String, conformingTo conforming: UTI? = nil) {
self.init(withTagClass:.fileExtension, value: fileExtension, conformingTo: conforming)
self.init(withTagClass: .fileExtension, value: fileExtension, conformingTo: conforming)
}
/**
@@ -138,7 +140,7 @@ public class UTI: RawRepresentable, Equatable {
public convenience init(withMimeType mimeType: String, conformingTo conforming: UTI? = nil) {
self.init(withTagClass:.mimeType, value: mimeType, conformingTo: conforming)
self.init(withTagClass: .mimeType, value: mimeType, conformingTo: conforming)
}
#if os(macOS)
@@ -146,7 +148,9 @@ public class UTI: RawRepresentable, Equatable {
/**
Initialize an UTI with a pasteboard type.
- Important: **This function is de-facto deprecated!** The old cocoa pasteboard types ( `NSStringPboardType`, `NSPDFPboardType`, etc) have been deprecated in favour of actual UTIs, and the constants are not available anymore in Swift. This function only works correctly with the values of these old constants, but _not_ with the replacement values (like `NSPasteboardTypeString` etc), since these already are UTIs.
- Important: **This function is de-facto deprecated!** The old cocoa pasteboard types ( `NSStringPboardType`, `NSPDFPboardType`, etc) have been deprecated in favour of actual UTIs, and the
constants are not available anymore in Swift. This function only works correctly with the values of these old constants, but _not_ with the replacement values (like `NSPasteboardTypeString` etc), since these
already are UTIs.
- Parameters:
- pbType: The pasteboard type (e.g. NSPDFPboardType).
- conformingTo: If specified, the returned UTI must conform to this UTI. If nil is specified, this parameter is ignored. The default is nil.
@@ -155,7 +159,7 @@ public class UTI: RawRepresentable, Equatable {
*/
public convenience init(withPBType pbType: String, conformingTo conforming: UTI? = nil) {
self.init(withTagClass:.pbType, value: pbType, conformingTo: conforming)
self.init(withTagClass: .pbType, value: pbType, conformingTo: conforming)
}
/**
@@ -172,7 +176,7 @@ public class UTI: RawRepresentable, Equatable {
public convenience init(withOSType osType: String, conformingTo conforming: UTI? = nil) {
self.init(withTagClass:.osType, value: osType, conformingTo: conforming)
self.init(withTagClass: .osType, value: osType, conformingTo: conforming)
}
#endif
@@ -297,7 +301,7 @@ public class UTI: RawRepresentable, Equatable {
return UTTypeConformsTo(self.rawCFValue, otherUTI.rawCFValue) as Bool
}
public static func ==(lhs: UTI, rhs: UTI) -> Bool {
public static func == (lhs: UTI, rhs: UTI) -> Bool {
return UTTypeEqual(lhs.rawCFValue, rhs.rawCFValue) as Bool
}
@@ -319,11 +323,11 @@ public class UTI: RawRepresentable, Equatable {
/// Returns a uniform types declaration as a Dictionary, or nil if if no declaration for that type can be found.
public var declaration: [AnyHashable:Any]? {
public var declaration: [AnyHashable: Any]? {
let unmanagedDeclaration = UTTypeCopyDeclaration(self.rawCFValue)
guard let declaration = unmanagedDeclaration?.takeRetainedValue() as? [AnyHashable:Any] else {
guard let declaration = unmanagedDeclaration?.takeRetainedValue() as? [AnyHashable: Any] else {
return nil
}
@@ -356,137 +360,137 @@ public class UTI: RawRepresentable, Equatable {
public extension UTI {
static let item = UTI(rawValue: kUTTypeItem as String)
static let content = UTI(rawValue: kUTTypeContent as String)
static let compositeContent = UTI(rawValue: kUTTypeCompositeContent as String)
static let message = UTI(rawValue: kUTTypeMessage as String)
static let contact = UTI(rawValue: kUTTypeContact as String)
static let archive = UTI(rawValue: kUTTypeArchive as String)
static let diskImage = UTI(rawValue: kUTTypeDiskImage as String)
static let data = UTI(rawValue: kUTTypeData as String)
static let directory = UTI(rawValue: kUTTypeDirectory as String)
static let resolvable = UTI(rawValue: kUTTypeResolvable as String)
static let symLink = UTI(rawValue: kUTTypeSymLink as String)
static let executable = UTI(rawValue: kUTTypeExecutable as String)
static let mountPoint = UTI(rawValue: kUTTypeMountPoint as String)
static let aliasFile = UTI(rawValue: kUTTypeAliasFile as String)
static let aliasRecord = UTI(rawValue: kUTTypeAliasRecord as String)
static let urlBookmarkData = UTI(rawValue: kUTTypeURLBookmarkData as String)
static let url = UTI(rawValue: kUTTypeURL as String)
static let fileURL = UTI(rawValue: kUTTypeFileURL as String)
static let text = UTI(rawValue: kUTTypeText as String)
static let plainText = UTI(rawValue: kUTTypePlainText as String)
static let utf8PlainText = UTI(rawValue: kUTTypeUTF8PlainText as String)
static let utf16ExternalPlainText = UTI(rawValue: kUTTypeUTF16ExternalPlainText as String)
static let utf16PlainText = UTI(rawValue: kUTTypeUTF16PlainText as String)
static let delimitedText = UTI(rawValue: kUTTypeDelimitedText as String)
static let commaSeparatedText = UTI(rawValue: kUTTypeCommaSeparatedText as String)
static let tabSeparatedText = UTI(rawValue: kUTTypeTabSeparatedText as String)
static let utf8TabSeparatedText = UTI(rawValue: kUTTypeUTF8TabSeparatedText as String)
static let rtf = UTI(rawValue: kUTTypeRTF as String)
static let html = UTI(rawValue: kUTTypeHTML as String)
static let xml = UTI(rawValue: kUTTypeXML as String)
static let sourceCode = UTI(rawValue: kUTTypeSourceCode as String)
static let assemblyLanguageSource = UTI(rawValue: kUTTypeAssemblyLanguageSource as String)
static let cSource = UTI(rawValue: kUTTypeCSource as String)
static let objectiveCSource = UTI(rawValue: kUTTypeObjectiveCSource as String)
static let item = UTI(rawValue: kUTTypeItem as String)
static let content = UTI(rawValue: kUTTypeContent as String)
static let compositeContent = UTI(rawValue: kUTTypeCompositeContent as String)
static let message = UTI(rawValue: kUTTypeMessage as String)
static let contact = UTI(rawValue: kUTTypeContact as String)
static let archive = UTI(rawValue: kUTTypeArchive as String)
static let diskImage = UTI(rawValue: kUTTypeDiskImage as String)
static let data = UTI(rawValue: kUTTypeData as String)
static let directory = UTI(rawValue: kUTTypeDirectory as String)
static let resolvable = UTI(rawValue: kUTTypeResolvable as String)
static let symLink = UTI(rawValue: kUTTypeSymLink as String)
static let executable = UTI(rawValue: kUTTypeExecutable as String)
static let mountPoint = UTI(rawValue: kUTTypeMountPoint as String)
static let aliasFile = UTI(rawValue: kUTTypeAliasFile as String)
static let aliasRecord = UTI(rawValue: kUTTypeAliasRecord as String)
static let urlBookmarkData = UTI(rawValue: kUTTypeURLBookmarkData as String)
static let url = UTI(rawValue: kUTTypeURL as String)
static let fileURL = UTI(rawValue: kUTTypeFileURL as String)
static let text = UTI(rawValue: kUTTypeText as String)
static let plainText = UTI(rawValue: kUTTypePlainText as String)
static let utf8PlainText = UTI(rawValue: kUTTypeUTF8PlainText as String)
static let utf16ExternalPlainText = UTI(rawValue: kUTTypeUTF16ExternalPlainText as String)
static let utf16PlainText = UTI(rawValue: kUTTypeUTF16PlainText as String)
static let delimitedText = UTI(rawValue: kUTTypeDelimitedText as String)
static let commaSeparatedText = UTI(rawValue: kUTTypeCommaSeparatedText as String)
static let tabSeparatedText = UTI(rawValue: kUTTypeTabSeparatedText as String)
static let utf8TabSeparatedText = UTI(rawValue: kUTTypeUTF8TabSeparatedText as String)
static let rtf = UTI(rawValue: kUTTypeRTF as String)
static let html = UTI(rawValue: kUTTypeHTML as String)
static let xml = UTI(rawValue: kUTTypeXML as String)
static let sourceCode = UTI(rawValue: kUTTypeSourceCode as String)
static let assemblyLanguageSource = UTI(rawValue: kUTTypeAssemblyLanguageSource as String)
static let cSource = UTI(rawValue: kUTTypeCSource as String)
static let objectiveCSource = UTI(rawValue: kUTTypeObjectiveCSource as String)
@available( OSX 10.11, iOS 9.0, * )
static let swiftSource = UTI(rawValue: kUTTypeSwiftSource as String)
static let cPlusPlusSource = UTI(rawValue: kUTTypeCPlusPlusSource as String)
static let objectiveCPlusPlusSource = UTI(rawValue: kUTTypeObjectiveCPlusPlusSource as String)
static let cHeader = UTI(rawValue: kUTTypeCHeader as String)
static let cPlusPlusHeader = UTI(rawValue: kUTTypeCPlusPlusHeader as String)
static let javaSource = UTI(rawValue: kUTTypeJavaSource as String)
static let script = UTI(rawValue: kUTTypeScript as String)
static let appleScript = UTI(rawValue: kUTTypeAppleScript as String)
static let osaScript = UTI(rawValue: kUTTypeOSAScript as String)
static let osaScriptBundle = UTI(rawValue: kUTTypeOSAScriptBundle as String)
static let javaScript = UTI(rawValue: kUTTypeJavaScript as String)
static let shellScript = UTI(rawValue: kUTTypeShellScript as String)
static let perlScript = UTI(rawValue: kUTTypePerlScript as String)
static let pythonScript = UTI(rawValue: kUTTypePythonScript as String)
static let rubyScript = UTI(rawValue: kUTTypeRubyScript as String)
static let phpScript = UTI(rawValue: kUTTypePHPScript as String)
static let json = UTI(rawValue: kUTTypeJSON as String)
static let propertyList = UTI(rawValue: kUTTypePropertyList as String)
static let xmlPropertyList = UTI(rawValue: kUTTypeXMLPropertyList as String)
static let binaryPropertyList = UTI(rawValue: kUTTypeBinaryPropertyList as String)
static let pdf = UTI(rawValue: kUTTypePDF as String)
static let rtfd = UTI(rawValue: kUTTypeRTFD as String)
static let flatRTFD = UTI(rawValue: kUTTypeFlatRTFD as String)
static let txnTextAndMultimediaData = UTI(rawValue: kUTTypeTXNTextAndMultimediaData as String)
static let webArchive = UTI(rawValue: kUTTypeWebArchive as String)
static let image = UTI(rawValue: kUTTypeImage as String)
static let jpeg = UTI(rawValue: kUTTypeJPEG as String)
static let jpeg2000 = UTI(rawValue: kUTTypeJPEG2000 as String)
static let tiff = UTI(rawValue: kUTTypeTIFF as String)
static let pict = UTI(rawValue: kUTTypePICT as String)
static let gif = UTI(rawValue: kUTTypeGIF as String)
static let png = UTI(rawValue: kUTTypePNG as String)
static let quickTimeImage = UTI(rawValue: kUTTypeQuickTimeImage as String)
static let appleICNS = UTI(rawValue: kUTTypeAppleICNS as String)
static let bmp = UTI(rawValue: kUTTypeBMP as String)
static let ico = UTI(rawValue: kUTTypeICO as String)
static let rawImage = UTI(rawValue: kUTTypeRawImage as String)
static let scalableVectorGraphics = UTI(rawValue: kUTTypeScalableVectorGraphics as String)
static let swiftSource = UTI(rawValue: kUTTypeSwiftSource as String)
static let cPlusPlusSource = UTI(rawValue: kUTTypeCPlusPlusSource as String)
static let objectiveCPlusPlusSource = UTI(rawValue: kUTTypeObjectiveCPlusPlusSource as String)
static let cHeader = UTI(rawValue: kUTTypeCHeader as String)
static let cPlusPlusHeader = UTI(rawValue: kUTTypeCPlusPlusHeader as String)
static let javaSource = UTI(rawValue: kUTTypeJavaSource as String)
static let script = UTI(rawValue: kUTTypeScript as String)
static let appleScript = UTI(rawValue: kUTTypeAppleScript as String)
static let osaScript = UTI(rawValue: kUTTypeOSAScript as String)
static let osaScriptBundle = UTI(rawValue: kUTTypeOSAScriptBundle as String)
static let javaScript = UTI(rawValue: kUTTypeJavaScript as String)
static let shellScript = UTI(rawValue: kUTTypeShellScript as String)
static let perlScript = UTI(rawValue: kUTTypePerlScript as String)
static let pythonScript = UTI(rawValue: kUTTypePythonScript as String)
static let rubyScript = UTI(rawValue: kUTTypeRubyScript as String)
static let phpScript = UTI(rawValue: kUTTypePHPScript as String)
static let json = UTI(rawValue: kUTTypeJSON as String)
static let propertyList = UTI(rawValue: kUTTypePropertyList as String)
static let xmlPropertyList = UTI(rawValue: kUTTypeXMLPropertyList as String)
static let binaryPropertyList = UTI(rawValue: kUTTypeBinaryPropertyList as String)
static let pdf = UTI(rawValue: kUTTypePDF as String)
static let rtfd = UTI(rawValue: kUTTypeRTFD as String)
static let flatRTFD = UTI(rawValue: kUTTypeFlatRTFD as String)
static let txnTextAndMultimediaData = UTI(rawValue: kUTTypeTXNTextAndMultimediaData as String)
static let webArchive = UTI(rawValue: kUTTypeWebArchive as String)
static let image = UTI(rawValue: kUTTypeImage as String)
static let jpeg = UTI(rawValue: kUTTypeJPEG as String)
static let jpeg2000 = UTI(rawValue: kUTTypeJPEG2000 as String)
static let tiff = UTI(rawValue: kUTTypeTIFF as String)
static let pict = UTI(rawValue: kUTTypePICT as String)
static let gif = UTI(rawValue: kUTTypeGIF as String)
static let png = UTI(rawValue: kUTTypePNG as String)
static let quickTimeImage = UTI(rawValue: kUTTypeQuickTimeImage as String)
static let appleICNS = UTI(rawValue: kUTTypeAppleICNS as String)
static let bmp = UTI(rawValue: kUTTypeBMP as String)
static let ico = UTI(rawValue: kUTTypeICO as String)
static let rawImage = UTI(rawValue: kUTTypeRawImage as String)
static let scalableVectorGraphics = UTI(rawValue: kUTTypeScalableVectorGraphics as String)
@available(OSX 10.12, iOS 9.1, watchOS 2.1, *)
static let livePhoto = UTI(rawValue: kUTTypeLivePhoto as String)
static let livePhoto = UTI(rawValue: kUTTypeLivePhoto as String)
@available(OSX 10.12, iOS 9.1, *)
static let audiovisualContent = UTI(rawValue: kUTTypeAudiovisualContent as String)
static let movie = UTI(rawValue: kUTTypeMovie as String)
static let video = UTI(rawValue: kUTTypeVideo as String)
static let audio = UTI(rawValue: kUTTypeAudio as String)
static let quickTimeMovie = UTI(rawValue: kUTTypeQuickTimeMovie as String)
static let mpeg = UTI(rawValue: kUTTypeMPEG as String)
static let mpeg2Video = UTI(rawValue: kUTTypeMPEG2Video as String)
static let mpeg2TransportStream = UTI(rawValue: kUTTypeMPEG2TransportStream as String)
static let mp3 = UTI(rawValue: kUTTypeMP3 as String)
static let mpeg4 = UTI(rawValue: kUTTypeMPEG4 as String)
static let mpeg4Audio = UTI(rawValue: kUTTypeMPEG4Audio as String)
static let appleProtectedMPEG4Audio = UTI(rawValue: kUTTypeAppleProtectedMPEG4Audio as String)
static let appleProtectedMPEG4Video = UTI(rawValue: kUTTypeAppleProtectedMPEG4Video as String)
static let aviMovie = UTI(rawValue: kUTTypeAVIMovie as String)
static let audioInterchangeFileFormat = UTI(rawValue: kUTTypeAudioInterchangeFileFormat as String)
static let waveformAudio = UTI(rawValue: kUTTypeWaveformAudio as String)
static let midiAudio = UTI(rawValue: kUTTypeMIDIAudio as String)
static let playlist = UTI(rawValue: kUTTypePlaylist as String)
static let m3UPlaylist = UTI(rawValue: kUTTypeM3UPlaylist as String)
static let folder = UTI(rawValue: kUTTypeFolder as String)
static let volume = UTI(rawValue: kUTTypeVolume as String)
static let package = UTI(rawValue: kUTTypePackage as String)
static let bundle = UTI(rawValue: kUTTypeBundle as String)
static let pluginBundle = UTI(rawValue: kUTTypePluginBundle as String)
static let spotlightImporter = UTI(rawValue: kUTTypeSpotlightImporter as String)
static let quickLookGenerator = UTI(rawValue: kUTTypeQuickLookGenerator as String)
static let xpcService = UTI(rawValue: kUTTypeXPCService as String)
static let framework = UTI(rawValue: kUTTypeFramework as String)
static let application = UTI(rawValue: kUTTypeApplication as String)
static let applicationBundle = UTI(rawValue: kUTTypeApplicationBundle as String)
static let applicationFile = UTI(rawValue: kUTTypeApplicationFile as String)
static let unixExecutable = UTI(rawValue: kUTTypeUnixExecutable as String)
static let windowsExecutable = UTI(rawValue: kUTTypeWindowsExecutable as String)
static let javaClass = UTI(rawValue: kUTTypeJavaClass as String)
static let javaArchive = UTI(rawValue: kUTTypeJavaArchive as String)
static let systemPreferencesPane = UTI(rawValue: kUTTypeSystemPreferencesPane as String)
static let gnuZipArchive = UTI(rawValue: kUTTypeGNUZipArchive as String)
static let bzip2Archive = UTI(rawValue: kUTTypeBzip2Archive as String)
static let zipArchive = UTI(rawValue: kUTTypeZipArchive as String)
static let spreadsheet = UTI(rawValue: kUTTypeSpreadsheet as String)
static let presentation = UTI(rawValue: kUTTypePresentation as String)
static let database = UTI(rawValue: kUTTypeDatabase as String)
static let vCard = UTI(rawValue: kUTTypeVCard as String)
static let toDoItem = UTI(rawValue: kUTTypeToDoItem as String)
static let calendarEvent = UTI(rawValue: kUTTypeCalendarEvent as String)
static let emailMessage = UTI(rawValue: kUTTypeEmailMessage as String)
static let internetLocation = UTI(rawValue: kUTTypeInternetLocation as String)
static let inkText = UTI(rawValue: kUTTypeInkText as String)
static let font = UTI(rawValue: kUTTypeFont as String)
static let bookmark = UTI(rawValue: kUTTypeBookmark as String)
static let _3DContent = UTI(rawValue: kUTType3DContent as String)
static let pkcs12 = UTI(rawValue: kUTTypePKCS12 as String)
static let x509Certificate = UTI(rawValue: kUTTypeX509Certificate as String)
static let electronicPublication = UTI(rawValue: kUTTypeElectronicPublication as String)
static let log = UTI(rawValue: kUTTypeLog as String)
static let audiovisualContent = UTI(rawValue: kUTTypeAudiovisualContent as String)
static let movie = UTI(rawValue: kUTTypeMovie as String)
static let video = UTI(rawValue: kUTTypeVideo as String)
static let audio = UTI(rawValue: kUTTypeAudio as String)
static let quickTimeMovie = UTI(rawValue: kUTTypeQuickTimeMovie as String)
static let mpeg = UTI(rawValue: kUTTypeMPEG as String)
static let mpeg2Video = UTI(rawValue: kUTTypeMPEG2Video as String)
static let mpeg2TransportStream = UTI(rawValue: kUTTypeMPEG2TransportStream as String)
static let mp3 = UTI(rawValue: kUTTypeMP3 as String)
static let mpeg4 = UTI(rawValue: kUTTypeMPEG4 as String)
static let mpeg4Audio = UTI(rawValue: kUTTypeMPEG4Audio as String)
static let appleProtectedMPEG4Audio = UTI(rawValue: kUTTypeAppleProtectedMPEG4Audio as String)
static let appleProtectedMPEG4Video = UTI(rawValue: kUTTypeAppleProtectedMPEG4Video as String)
static let aviMovie = UTI(rawValue: kUTTypeAVIMovie as String)
static let audioInterchangeFileFormat = UTI(rawValue: kUTTypeAudioInterchangeFileFormat as String)
static let waveformAudio = UTI(rawValue: kUTTypeWaveformAudio as String)
static let midiAudio = UTI(rawValue: kUTTypeMIDIAudio as String)
static let playlist = UTI(rawValue: kUTTypePlaylist as String)
static let m3UPlaylist = UTI(rawValue: kUTTypeM3UPlaylist as String)
static let folder = UTI(rawValue: kUTTypeFolder as String)
static let volume = UTI(rawValue: kUTTypeVolume as String)
static let package = UTI(rawValue: kUTTypePackage as String)
static let bundle = UTI(rawValue: kUTTypeBundle as String)
static let pluginBundle = UTI(rawValue: kUTTypePluginBundle as String)
static let spotlightImporter = UTI(rawValue: kUTTypeSpotlightImporter as String)
static let quickLookGenerator = UTI(rawValue: kUTTypeQuickLookGenerator as String)
static let xpcService = UTI(rawValue: kUTTypeXPCService as String)
static let framework = UTI(rawValue: kUTTypeFramework as String)
static let application = UTI(rawValue: kUTTypeApplication as String)
static let applicationBundle = UTI(rawValue: kUTTypeApplicationBundle as String)
static let applicationFile = UTI(rawValue: kUTTypeApplicationFile as String)
static let unixExecutable = UTI(rawValue: kUTTypeUnixExecutable as String)
static let windowsExecutable = UTI(rawValue: kUTTypeWindowsExecutable as String)
static let javaClass = UTI(rawValue: kUTTypeJavaClass as String)
static let javaArchive = UTI(rawValue: kUTTypeJavaArchive as String)
static let systemPreferencesPane = UTI(rawValue: kUTTypeSystemPreferencesPane as String)
static let gnuZipArchive = UTI(rawValue: kUTTypeGNUZipArchive as String)
static let bzip2Archive = UTI(rawValue: kUTTypeBzip2Archive as String)
static let zipArchive = UTI(rawValue: kUTTypeZipArchive as String)
static let spreadsheet = UTI(rawValue: kUTTypeSpreadsheet as String)
static let presentation = UTI(rawValue: kUTTypePresentation as String)
static let database = UTI(rawValue: kUTTypeDatabase as String)
static let vCard = UTI(rawValue: kUTTypeVCard as String)
static let toDoItem = UTI(rawValue: kUTTypeToDoItem as String)
static let calendarEvent = UTI(rawValue: kUTTypeCalendarEvent as String)
static let emailMessage = UTI(rawValue: kUTTypeEmailMessage as String)
static let internetLocation = UTI(rawValue: kUTTypeInternetLocation as String)
static let inkText = UTI(rawValue: kUTTypeInkText as String)
static let font = UTI(rawValue: kUTTypeFont as String)
static let bookmark = UTI(rawValue: kUTTypeBookmark as String)
static let _3DContent = UTI(rawValue: kUTType3DContent as String)
static let pkcs12 = UTI(rawValue: kUTTypePKCS12 as String)
static let x509Certificate = UTI(rawValue: kUTTypeX509Certificate as String)
static let electronicPublication = UTI(rawValue: kUTTypeElectronicPublication as String)
static let log = UTI(rawValue: kUTTypeLog as String)
}
#if os(OSX)
-1
View File
@@ -69,7 +69,6 @@
#import "MXKRoomCreationView.h"
#import "MXKRoomInputToolbarView.h"
#import "MXKRoomInputToolbarViewWithHPGrowingText.h"
#import "MXKRoomDataSourceManager.h"
@@ -75,10 +75,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
// Internal list of ignored rooms
NSMutableArray* ignoredRooms;
// If a server sync is in progress, the pause is delayed at the end of sync (except if resume is called).
BOOL isPauseRequested;
// Background sync management
MXOnBackgroundSyncDone backgroundSyncDone;
MXOnBackgroundSyncFail backgroundSyncFails;
@@ -91,7 +88,9 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
id NSCurrentLocaleDidChangeNotificationObserver;
}
@property (nonatomic, strong) id<MXBackgroundTask> backgroundTask;
/// 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.
@property (nonatomic, assign, getter=isPauseRequested) BOOL pauseRequested;
@property (nonatomic, strong) id<MXBackgroundTask> pauseBackgroundTask;
@property (nonatomic, strong) id<MXBackgroundTask> backgroundSyncBgTask;
@end
@@ -515,6 +514,32 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
return _others;
}
- (void)setPauseRequested:(BOOL)pauseRequested
{
if (_pauseRequested != pauseRequested)
{
_pauseRequested = pauseRequested;
if (_pauseRequested)
{
// Make sure the SDK finish its work before the app goes sleeping in background
id<MXBackgroundModeHandler> handler = [MXSDKOptions sharedInstance].backgroundModeHandler;
if (handler)
{
if (!self.pauseBackgroundTask.isRunning)
{
self.pauseBackgroundTask = [handler startBackgroundTaskWithName:@"[MXKAccount] pauseInBackgroundTask"
expirationHandler:nil];
}
}
}
else
{
[self cancelPauseBackgroundTask];
}
}
}
#pragma mark - Matrix user's profile
- (void)setUserDisplayName:(NSString*)displayname success:(void (^)(void))success failure:(void (^)(NSError *error))failure
@@ -966,38 +991,25 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
- (void)pauseInBackgroundTask
{
// Reset internal flag
isPauseRequested = NO;
if (mxSession && mxSession.isPauseable)
if (mxSession == nil)
{
// no session to pause
return;
}
// mark that we want to pause when possible
self.pauseRequested = YES;
if (mxSession.isPauseable)
{
id<MXBackgroundModeHandler> handler = [MXSDKOptions sharedInstance].backgroundModeHandler;
if (handler)
{
if (!self.backgroundTask.isRunning)
{
self.backgroundTask = [handler startBackgroundTaskWithName:@"[MXKAccount] pauseInBackgroundTask" expirationHandler:nil];
}
}
// Pause SDK
[mxSession pause];
// Update user presence
__weak typeof(self) weakSelf = self;
MXWeakify(self);
[self setUserPresence:MXPresenceUnavailable andStatusMessage:nil completion:^{
if (weakSelf)
{
typeof(self) self = weakSelf;
if (self.backgroundTask.isRunning)
{
[self.backgroundTask stop];
self.backgroundTask = nil;
}
}
MXStrongifyAndReturnIfNil(self);
[self cancelPauseBackgroundTask];
}];
}
else
@@ -1007,65 +1019,61 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
reachabilityObserver = nil;
[initialServerSyncTimer invalidate];
initialServerSyncTimer = nil;
if (mxSession.state == MXSessionStateSyncInProgress || mxSession.state == MXSessionStateInitialised || mxSession.state == MXSessionStateStoreDataReady)
{
// Make sure the SDK finish its work before the app goes sleeping in background
id<MXBackgroundModeHandler> handler = [MXSDKOptions sharedInstance].backgroundModeHandler;
if (handler)
{
if (!self.backgroundTask.isRunning)
{
self.backgroundTask = [handler startBackgroundTaskWithName:@"[MXKAccount] pauseInBackgroundTask" expirationHandler:nil];
}
}
MXLogDebug(@"[MXKAccount] Pause is delayed at the end of sync (current state %tu)", mxSession.state);
isPauseRequested = YES;
}
MXLogDebug(@"[MXKAccount] Pause is delayed due to the session state: %@", [MXTools readableSessionState: mxSession.state]);
}
}
- (void)resume
{
isPauseRequested = NO;
if (mxSession)
if (mxSession == nil)
{
MXLogVerbose(@"[MXKAccount] resume with session state: %tu", mxSession.state);
[self cancelBackgroundSync];
if (mxSession.state == MXSessionStatePaused || mxSession.state == MXSessionStatePauseRequested)
// no session to resume
return;
}
// mark that we don't want to pause anymore
self.pauseRequested = NO;
MXLogVerbose(@"[MXKAccount] resume: with session state: %@", [MXTools readableSessionState:mxSession.state]);
[self cancelBackgroundSync];
switch (mxSession.state)
{
case MXSessionStatePaused:
case MXSessionStatePauseRequested:
{
// Resume SDK and update user presence
[mxSession resume:^{
[self setUserPresence:MXPresenceOnline andStatusMessage:nil completion:nil];
[self refreshAPNSPusher];
[self refreshPushKitPusher];
}];
break;
}
else if (mxSession.state == MXSessionStateStoreDataReady || mxSession.state == MXSessionStateInitialSyncFailed)
case MXSessionStateStoreDataReady:
case MXSessionStateInitialSyncFailed:
{
// The session initialisation was uncompleted, we try to complete it here.
[self launchInitialServerSync];
[self refreshAPNSPusher];
[self refreshPushKitPusher];
break;
}
else if (mxSession.state == MXSessionStateSyncInProgress)
case MXSessionStateSyncInProgress:
{
[self refreshAPNSPusher];
[self refreshPushKitPusher];
break;
}
// Cancel background task
if (self.backgroundTask.isRunning)
{
[self.backgroundTask stop];
self.backgroundTask = nil;
}
default:
break;
}
}
@@ -1616,16 +1624,16 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
- (void)onMatrixSessionStateChange
{
// Check if pause has been requested
if (self.isPauseRequested && mxSession.isPauseable)
{
MXLogDebug(@"[MXKAccount] Apply the pending pause.");
[self pauseInBackgroundTask];
return;
}
if (mxSession.state == MXSessionStateRunning)
{
// Check if pause has been requested
if (isPauseRequested)
{
MXLogDebug(@"[MXKAccount] Apply the pending pause.");
[self pauseInBackgroundTask];
return;
}
// Check whether the session was not already running
if (!userUpdateListener)
{
@@ -1662,7 +1670,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
}
else if (mxSession.state == MXSessionStatePaused)
{
isPauseRequested = NO;
self.pauseRequested = NO;
}
}
@@ -1754,6 +1762,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
dispatch_group_leave(dispatchGroup);
} failure:^(NSError *error) {
MXLogError(@"[MXKAccount] onDateTimeFormatUpdate: event fetch failed: %@", error);
dispatch_group_leave(dispatchGroup);
}];
}
@@ -1774,6 +1783,16 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
}
}
- (void)cancelPauseBackgroundTask
{
// Cancel background task
if (self.pauseBackgroundTask.isRunning)
{
[self.pauseBackgroundTask stop];
self.pauseBackgroundTask = nil;
}
}
#pragma mark - Crypto
- (void)resetDeviceId
{
@@ -1890,7 +1909,7 @@ static NSArray<NSNumber*> *initialSyncSilentErrorsHTTPStatusCodes;
}
else
{
MXLogDebug(@"[MXKAccount] cannot start background Sync (invalid state %tu)", mxSession.state);
MXLogDebug(@"[MXKAccount] cannot start background Sync (invalid state %@)", [MXTools readableSessionState:mxSession.state]);
failure([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:nil]);
}
}
@@ -104,6 +104,8 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa
}
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)saveAccounts
{
NSDate *startDate = [NSDate date];
@@ -123,6 +125,7 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa
MXLogDebug(@"[MXKAccountManager] saveAccounts. Done (result: %@) in %.0fms", @(result), [[NSDate date] timeIntervalSinceDate:startDate] * 1000);
}
#pragma clang diagnostic pop
- (void)addAccount:(MXKAccount *)account andOpenSession:(BOOL)openSession
{
@@ -608,6 +611,8 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa
return [matrixKitCacheFolder stringByAppendingPathComponent:kMXKAccountsKey];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)loadAccounts
{
MXLogDebug(@"[MXKAccountManager] loadAccounts");
@@ -675,6 +680,7 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa
mxAccounts = [NSMutableArray array];
}
}
#pragma clang diagnostic pop
- (NSData*)encryptData:(NSData*)data
{
@@ -708,6 +714,8 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa
return data;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)migrateAccounts
{
NSString *pathOld = [[MXKAppSettings cacheFolder] stringByAppendingPathComponent:kMXKAccountsKeyOld];
@@ -727,6 +735,7 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa
[fileManager removeItemAtPath:pathOld error:nil];
}
}
#pragma clang diagnostic pop
- (void)readAndWriteCredentials:(void (^)(NSArray<MXCredentials*> * _Nullable readData, void (^completion)(BOOL didUpdateCredentials)))readAnWriteHandler
{
@@ -93,6 +93,8 @@ extern NSString *const kMXKContactDefaultContactPrefixId;
*/
- (void)resetMatrixThumbnail;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
/**
The contact ID from native phonebook record
*/
@@ -105,6 +107,7 @@ extern NSString *const kMXKContactDefaultContactPrefixId;
@return MXKContact instance
*/
- (id)initLocalContactWithABRecord:(ABRecordRef)record;
#pragma clang diagnostic pop
/**
Create a matrix contact with the dedicated info
@@ -40,6 +40,8 @@ NSString *const kMXKContactDefaultContactPrefixId = @"Default_";
@implementation MXKContact
@synthesize isMatrixContact, isThirdPartyInvite;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ (NSString*)contactID:(ABRecordRef)record
{
return [NSString stringWithFormat:@"%@%d", kMXKContactLocalContactPrefixId, ABRecordGetRecordID(record)];
@@ -217,6 +219,7 @@ NSString *const kMXKContactDefaultContactPrefixId = @"Default_";
}
return self;
}
#pragma clang diagnostic pop
- (id)initMatrixContactWithDisplayName:(NSString*)displayName andMatrixID:(NSString*)matrixID
{
@@ -537,6 +537,8 @@ NSString *const MXKContactManagerDataType = @"org.matrix.kit.MXKContactManagerDa
}
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (void)refreshLocalContacts
{
MXLogDebug(@"[MXKContactManager] refreshLocalContacts : Started");
@@ -721,6 +723,7 @@ NSString *const MXKContactManagerDataType = @"org.matrix.kit.MXKContactManagerDa
});
}
}
#pragma clang diagnostic pop
- (void)updateMatrixIDsForLocalContact:(MXKContact *)contact
{
@@ -1582,6 +1585,9 @@ static NSString *matrixIDsDictFile = @"matrixIDsDictV2";
static NSString *localContactsFile = @"localContactsV2";
static NSString *contactsBookInfoFile = @"contactsV2";
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (NSString*)dataFilePathForComponent:(NSString*)component
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
@@ -1857,6 +1863,8 @@ static NSString *contactsBookInfoFile = @"contactsV2";
}
}
#pragma clang diagnostic pop
- (BOOL)encryptAndSaveData:(NSData*)data toFile:(NSString*)fileName
{
NSError *error = nil;
@@ -1865,6 +1873,10 @@ static NSString *contactsBookInfoFile = @"contactsV2";
if (error == nil)
{
[cipher writeToFile:[self dataFilePathForComponent:fileName] atomically:YES];
[[NSFileManager defaultManager] excludeItemFromBackupAt:[NSURL fileURLWithPath:fileName] error:&error];
if (error) {
MXLogDebug(@"[MXKContactManager] Cannot exclude item from backup %@", error.localizedDescription);
}
}
else
{
+21 -8
View File
@@ -29,6 +29,10 @@
@property (nonatomic) NSString *sid;
@property (nonatomic) MXIdentityService *identityService;
@property (nonatomic) NSString *submitUrl;
/**
HTTP client dedicated to sending MSISDN token to custom URLs.
*/
@property (nonatomic, strong) MXHTTPClient *msisdnSubmissionHttpClient;
@end
@@ -255,14 +259,23 @@
@"token": token
};
MXHTTPClient *httpClient = [[MXHTTPClient alloc] initWithBaseURL:nil andOnUnrecognizedCertificateBlock:nil];
return [httpClient requestWithMethod:@"POST"
path:url
parameters:parameters
success:^(NSDictionary *JSONResponse) {
success();
}
failure:failure];
self.msisdnSubmissionHttpClient = [[MXHTTPClient alloc] initWithBaseURL:nil andOnUnrecognizedCertificateBlock:nil];
MXWeakify(self);
return [self.msisdnSubmissionHttpClient requestWithMethod:@"POST"
path:url
parameters:parameters
success:^(NSDictionary *JSONResponse) {
success();
MXStrongifyAndReturnIfNil(self);
self.msisdnSubmissionHttpClient = nil;
}
failure:^(NSError *error) {
failure(error);
MXStrongifyAndReturnIfNil(self);
self.msisdnSubmissionHttpClient = nil;
}];
}
- (void)add3PIDToUser:(BOOL)bind
@@ -19,6 +19,7 @@
#import "MXKAppSettings.h"
#import "MXKTools.h"
@import MatrixSDK;
// get ISO country name
@@ -66,11 +67,10 @@ static NSString *const kMXAppGroupID = @"group.org.matrix";
{
NSString *cacheFolder;
// Check for a potential application group id
NSString *applicationGroupIdentifier = [MXSDKOptions sharedInstance].applicationGroupIdentifier;
if (applicationGroupIdentifier)
// Check for a potential application group container
NSURL *sharedContainerURL = [[NSFileManager defaultManager] applicationGroupContainerURL];
if (sharedContainerURL)
{
NSURL *sharedContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:applicationGroupIdentifier];
cacheFolder = [sharedContainerURL path];
}
else
@@ -86,7 +86,7 @@ static NSString *const kMXAppGroupID = @"group.org.matrix";
if (cacheFolder && ![[NSFileManager defaultManager] fileExistsAtPath:cacheFolder])
{
NSError *error;
[[NSFileManager defaultManager] createDirectoryAtPath:cacheFolder withIntermediateDirectories:YES attributes:nil error:&error];
[[NSFileManager defaultManager] createDirectoryExcludedFromBackupAtPath:cacheFolder error:&error];
if (error)
{
MXLogDebug(@"[MXKAppSettings] cacheFolder: Error: Cannot create MatrixKit folder at %@. Error: %@", cacheFolder, error);
@@ -670,6 +670,8 @@ static NSString *const kMXAppGroupID = @"group.org.matrix";
}
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (NSString*)phonebookCountryCode
{
NSString* res = phonebookCountryCode;
@@ -699,6 +701,7 @@ static NSString *const kMXAppGroupID = @"group.org.matrix";
return res;
}
#pragma clang diagnostic pop
- (void)setPhonebookCountryCode:(NSString *)stringValue
{
@@ -46,6 +46,11 @@
*/
NSAttributedString *attributedTextMessage;
/**
Same as attributedTextMessage but without vertical positioning vertical blank space.
*/
NSAttributedString *attributedTextMessageWithoutPositioningSpace;
/**
The optional text pattern to be highlighted in the body of the message.
*/
@@ -28,7 +28,7 @@
@implementation MXKRoomBubbleCellData
@synthesize senderId, targetId, roomId, senderDisplayName, senderAvatarUrl, senderAvatarPlaceholder, targetDisplayName, targetAvatarUrl, targetAvatarPlaceholder, isEncryptedRoom, isPaginationFirstBubble, shouldHideSenderInformation, date, isIncoming, isAttachmentWithThumbnail, isAttachmentWithIcon, attachment, senderFlair;
@synthesize textMessage, attributedTextMessage;
@synthesize textMessage, attributedTextMessage, attributedTextMessageWithoutPositioningSpace;
@synthesize shouldHideSenderName, isTyping, showBubbleDateTime, showBubbleReceipts, useCustomDateTimeLabel, useCustomReceipts, useCustomUnsentButton, hasNoDisplay;
@synthesize tag;
@synthesize collapsable, collapsed, collapsedAttributedTextMessage, prevCollapsableCellData, nextCollapsableCellData, collapseState;
@@ -163,6 +163,10 @@
*/
@property (nonatomic) NSAttributedString *attributedTextMessage;
/**
Same as attributedTextMessage but without vertical positioning blank space
*/
@property (nonatomic) NSAttributedString *attributedTextMessageWithoutPositioningSpace;
/**
The raw text message (without attributes)
*/
@@ -19,7 +19,7 @@
#import "MXKEventFormatter.h"
#import "MXKURLPreviewDataProtocol.h"
@class MXThread;
@protocol MXThreadProtocol;
/**
Flags to indicate if a fix is required at the display time.
@@ -108,7 +108,7 @@ typedef enum : NSUInteger {
/**
Thread for the bubble component. Should only exist for thread root events.
*/
@property (nonatomic, readonly) MXThread *thread;
@property (nonatomic, readonly) id<MXThreadProtocol> thread;
/**
Create a new `MXKRoomBubbleComponent` object based on a `MXEvent` instance.
@@ -22,7 +22,7 @@
@interface MXKRoomBubbleComponent ()
@property (nonatomic, readwrite) MXThread *thread;
@property (nonatomic, readwrite) id<MXThreadProtocol> thread;
@end
@@ -69,8 +69,17 @@
_showEncryptionBadge = [self shouldShowWarningBadgeForEvent:event roomState:(MXRoomState*)roomState session:session];
[self updateLinkWithRoomState:roomState];
self.thread = [session.threadingService threadWithId:event.eventId];
if (event.unsignedData.relations.thread)
{
self.thread = [[MXThreadModel alloc] initWithRootEvent:event
notificationCount:0
highlightCount:0];
}
else
{
self.thread = [session.threadingService threadWithId:event.eventId];
}
}
return self;
}
@@ -1448,6 +1448,16 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
return NO;
}
}
if (!USE_THREAD_TIMELINE && direction == MXTimelineDirectionBackwards && self.threadId)
{
// when not using a thread timeline, data source will desperately fill the screen with events by filtering them locally.
// we can stop when we see the thread root event when paginating backwards
if ([event.eventId isEqualToString:self.threadId])
{
self.shouldStopBackPagination = YES;
}
}
return YES;
}
@@ -56,7 +56,7 @@
#pragma mark - Override MXKRecentsDataSource
- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame
- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView
{
UIView *sectionHeader = nil;
@@ -88,9 +88,10 @@
@param section the section index
@param frame the drawing area for the header of the specified section.
@param tableView the table view
@return the section header.
*/
- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame;
- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView;
/**
Get the data for the cell at the given index path.
@@ -257,7 +257,7 @@
}
}
- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame
- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView
{
UIView *sectionHeader = nil;
@@ -30,8 +30,8 @@ extern NSString *const kMXKRecentCellIdentifier;
/**
The recents data source based on a unique matrix session.
Deprecated: Please see MXSession.roomListDataManager
*/
MXK_DEPRECATED_ATTRIBUTE_WITH_MSG("See MXSession.roomListDataManager")
@interface MXKSessionRecentsDataSource : MXKDataSource {
@protected
@@ -955,7 +955,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=\"(.*?)\">([^<]*)</a>";
}
if (event.content[@"kick"])
{
displayText = [NSString stringWithFormat:@"%@\n\u2022 kick: %@", displayText, event.content[@"kick"]];
displayText = [NSString stringWithFormat:@"%@\n\u2022 remove: %@", displayText, event.content[@"kick"]];
}
if (event.content[@"redact"])
{
@@ -36,7 +36,17 @@ public class MarkdownToHTMLRenderer: NSObject {
extension MarkdownToHTMLRenderer: MarkdownToHTMLRendererProtocol {
public func renderToHTML(markdown: String) -> String? {
return try? Down(markdownString: markdown).toHTML(options)
do {
let ast = try DownASTRenderer.stringToAST(markdown, options: options)
defer {
cmark_node_free(ast)
}
ast.repairLinks()
return try DownHTMLRenderer.astToHTML(ast, options: options)
} catch {
MXLog.error("[MarkdownToHTMLRenderer] renderToHTML failed with string: \(markdown)")
return nil
}
}
}
@@ -50,3 +60,116 @@ public class MarkdownToHTMLRendererHardBreaks: MarkdownToHTMLRenderer {
}
}
// MARK: - AST-handling private extensions
private extension CMarkNode {
/// Formatting symbol associated with given note type
/// Note: this is only defined for node types that are handled in repairLinks
var formattingSymbol: String {
switch self.type {
case CMARK_NODE_EMPH:
return "_"
case CMARK_NODE_STRONG:
return "__"
default:
return ""
}
}
/// Repairs links that were broken down by markdown formatting.
/// Should be used on the first node of libcmark's AST
/// (e.g. the object returned by DownASTRenderer.stringToAST).
func repairLinks() {
let iterator = cmark_iter_new(self)
var text = ""
var isInParagraph = false
var previousNode: CMarkNode?
var orphanNodes: [CMarkNode] = []
var shouldUnlinkFormattingMode = false
var event: cmark_event_type?
while event != CMARK_EVENT_DONE {
event = cmark_iter_next(iterator)
guard let node = cmark_iter_get_node(iterator) else { return }
if node.type == CMARK_NODE_PARAGRAPH {
if event == CMARK_EVENT_ENTER {
isInParagraph = true
} else {
isInParagraph = false
text = ""
}
}
if isInParagraph {
switch node.type {
case CMARK_NODE_SOFTBREAK,
CMARK_NODE_LINEBREAK:
text = ""
case CMARK_NODE_TEXT:
if let literal = node.literal {
text += literal
// Reset text if it ends up with a whitespace.
if text.last?.isWhitespace == true {
text = ""
}
// Only the last part could be a link conflicting with next node.
text = String(text.split(separator: " ").last ?? "")
}
case CMARK_NODE_EMPH where previousNode?.type == CMARK_NODE_TEXT,
CMARK_NODE_STRONG where previousNode?.type == CMARK_NODE_TEXT:
if event == CMARK_EVENT_ENTER {
if !text.containedUrls.isEmpty,
let childLiteral = node.pointee.first_child.literal {
// If current text is a link, the formatted text is reverted back to a
// plain text as a part of the link.
let symbol = node.formattingSymbol
let nonFormattedText = "\(symbol)\(childLiteral)\(symbol)"
let replacementTextNode = cmark_node_new(CMARK_NODE_TEXT)
cmark_node_set_literal(replacementTextNode, nonFormattedText)
cmark_node_insert_after(previousNode, replacementTextNode)
// Set child literal to empty string so we dont read it.
// This avoids having to re-create the main
// iterator in the middle of the process.
cmark_node_set_literal(node.pointee.first_child, "")
let newIterator = cmark_iter_new(node)
_ = cmark_iter_next(newIterator)
cmark_node_unlink(node)
orphanNodes.append(node)
let nextNode = cmark_iter_get_node(newIterator)
cmark_node_insert_after(previousNode, nextNode)
shouldUnlinkFormattingMode = true
}
} else {
if shouldUnlinkFormattingMode {
cmark_node_unlink(node)
orphanNodes.append(node)
shouldUnlinkFormattingMode = false
}
}
default:
break
}
}
previousNode = node
}
// Free all nodes removed from the AST.
// This is done as a last step to avoid messing
// up with the main itertor.
for orphanNode in orphanNodes {
cmark_node_free(orphanNode)
}
}
}
private extension String {
/// Returns array of URLs detected inside the String.
var containedUrls: [NSTextCheckingResult] {
guard let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else {
return []
}
return detector.matches(in: self, options: [], range: NSRange(location: 0, length: self.utf16.count))
}
}
@@ -17,9 +17,6 @@
#import <UIKit/UIKit.h>
#define MXK_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
#define MXK_DEPRECATED_ATTRIBUTE_WITH_MSG(msg) __attribute((deprecated((msg))))
/**
The Matrix iOS Kit version.
*/
@@ -24,7 +24,8 @@ import MobileCoreServices
/// MXKDocumentPickerPresenter presents a controller that provides access to documents or destinations outside the apps sandbox.
/// Internally presents a UIDocumentPickerViewController in UIDocumentPickerMode.import.
/// Note: You must turn on the iCloud Documents capabilities in Xcode (see https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/DocumentPickerProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40014451)
/// Note: You must turn on the iCloud Documents capabilities in Xcode
/// (see https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/DocumentPickerProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40014451)
@objcMembers
public class MXKDocumentPickerPresenter: NSObject {
+1 -1
View File
@@ -1112,7 +1112,7 @@ manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo
// Caution: We need here to escape the non-ASCII characters (like '#' in room alias)
// to convert the link into a legal URL string.
NSString *link = [attributedString.string substringWithRange:match.range];
link = [link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
link = [link stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
[*mutableAttributedString addAttribute:NSLinkAttributeName value:link range:match.range];
}
}];
+9 -1
View File
@@ -20,7 +20,7 @@ import MobileCoreServices
// We do not use the SwiftUTI pod anymore
// The library is embedded in MatrixKit. See Libs/SwiftUTI/README.md for more details
//import SwiftUTI
// import SwiftUTI
/// MXKUTI represents a Universal Type Identifier (e.g. kUTTypePNG).
/// See https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html#//apple_ref/doc/uid/TP40001319-CH202-SW5 for more information.
@@ -134,6 +134,8 @@ extension MXKUTI {
self.init(rawValue: uti as String)
}
// swiftlint:disable unused_optional_binding
/// Initialize with local file URL.
/// This method is currently applicable only to URLs for file system resources.
///
@@ -153,6 +155,8 @@ extension MXKUTI {
}
}
// swiftlint:enable unused_optional_binding
public convenience init?(localFileURL: URL) {
self.init(localFileURL: localFileURL, loadResourceValues: true)
}
@@ -173,6 +177,8 @@ extension MXKUTI {
}
}
// swiftlint:disable force_unwrapping
// MARK: - Some system defined UTIs
extension MXKUTI {
public static let data = MXKUTI(cfRawValue: kUTTypeData)!
@@ -190,6 +196,8 @@ extension MXKUTI {
public static let xml = MXKUTI(cfRawValue: kUTTypeXML)!
}
// swiftlint:enable force_unwrapping
// MARK: - Convenience static methods
extension MXKUTI {
@@ -120,7 +120,7 @@ sendObjectMessage({ \
MXLogDebug(@"[MXKAuthenticationFallbackWebView] URL has js: prefix");
// Listen only to scheme of the JS-WKWebView bridge
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByRemovingPercentEncoding];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
@@ -102,7 +102,7 @@ var onloadCallback = function() { \
if ([urlString hasPrefix:@"js:"])
{
// Listen only to scheme of the JS-WKWebView bridge
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByRemovingPercentEncoding];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
@@ -417,7 +417,7 @@ static NSAttributedString *verticalWhitespace = nil;
[_mxSession.crypto setDeviceVerification:MXDeviceVerified forDevice:_mxDeviceInfo.deviceId ofUser:_mxDeviceInfo.userId success:^{
// Refresh data
_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent];
self->_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent];
if (self->_delegate)
{
[self->_delegate encryptionInfoView:self didDeviceInfoVerifiedChange:self.mxDeviceInfo];
@@ -473,7 +473,7 @@ static NSAttributedString *verticalWhitespace = nil;
[_mxSession.crypto setDeviceVerification:verificationStatus forDevice:_mxDeviceInfo.deviceId ofUser:_mxDeviceInfo.userId success:^{
// Refresh data
_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent];
self->_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent];
if (self->_delegate)
{
@@ -75,11 +75,9 @@
- (MXKCellData*)renderedCellData;
/**
Reset the cell.
Stop processes no more needed when cell is not visible.
The cell is no more displayed. This is time to release resources and removing listeners.
In case of UITableViewCell or UIContentViewCell object, the cell must reset in a state
that it can be reusable.
The cell is no more displayed but still recycled. This is time to stop animation.
*/
- (void)didEndDisplay;
@@ -1,99 +0,0 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
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 <MatrixSDK/MatrixSDK.h>
#import "MXKView.h"
typedef NS_ENUM(NSInteger, ReadReceiptsAlignment)
{
/**
The latest receipt is displayed on left
*/
ReadReceiptAlignmentLeft = 0,
/**
The latest receipt is displayed on right
*/
ReadReceiptAlignmentRight = 1,
};
/**
`MXKReceiptSendersContainer` is a view dedicated to display receipt senders by using their avatars.
This container handles automatically the number of visible avatars. A label is added when avatars are not all visible (see 'moreLabel' property).
*/
@interface MXKReceiptSendersContainer : MXKView
/**
The maximum number of avatars displayed in the container. 3 by default.
*/
@property (nonatomic) NSInteger maxDisplayedAvatars;
/**
The space between avatars. 2.0 points by default.
*/
@property (nonatomic) CGFloat avatarMargin;
/**
The label added beside avatars when avatars are not all visible.
*/
@property (nonatomic) UILabel* moreLabel;
/**
The more label text color (If set to nil `moreLabel.textColor` use `UIColor.blackColor` as default color).
*/
@property (nonatomic) UIColor* moreLabelTextColor;
/*
The read receipt objects for details required in the details view
*/
@property (nonatomic) NSArray <MXReceiptData *> *readReceipts;
/*
The array of the room members that will be displayed in the container
*/
@property (nonatomic, readonly) NSArray <MXRoomMember *> *roomMembers;
/*
The placeholders of the room members that will be shown if the users don't have avatars
*/
@property (nonatomic, readonly) NSArray <UIImage *> *placeholders;
/**
Initializes an `MXKReceiptSendersContainer` object with a frame and a media manager.
This is the designated initializer.
@param frame the container frame. Note that avatar will be displayed in full height in this container.
@param mediaManager the media manager used to download the matrix user's avatar.
@return The newly-initialized MXKReceiptSendersContainer instance
*/
- (instancetype)initWithFrame:(CGRect)frame andMediaManager:(MXMediaManager*)mediaManager;
/**
Refresh the container content by using the provided room members.
@param roomMembers list of room members sorted from the latest receipt to the oldest receipt.
@param placeHolders list of placeholders, one by room member. Used when url is nil, or during avatar download.
@param alignment (see ReadReceiptsAlignment).
*/
- (void)refreshReceiptSenders:(NSArray<MXRoomMember*>*)roomMembers withPlaceHolders:(NSArray<UIImage*>*)placeHolders andAlignment:(ReadReceiptsAlignment)alignment;
@end
@@ -1,174 +0,0 @@
/*
Copyright 2015 OpenMarket Ltd
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 "MXKReceiptSendersContainer.h"
#import "MXKImageView.h"
static UIColor* kMoreLabelDefaultcolor;
@interface MXKReceiptSendersContainer ()
@property (nonatomic, readwrite) NSArray <MXRoomMember *> *roomMembers;
@property (nonatomic, readwrite) NSArray <UIImage *> *placeholders;
@property (nonatomic) MXMediaManager *mediaManager;
@end
@implementation MXKReceiptSendersContainer
+ (void)initialize
{
if (self == [MXKReceiptSendersContainer class])
{
kMoreLabelDefaultcolor = [UIColor blackColor];
}
}
- (instancetype)initWithFrame:(CGRect)frame andMediaManager:(MXMediaManager*)mediaManager
{
self = [super initWithFrame:frame];
if (self)
{
_mediaManager = mediaManager;
_maxDisplayedAvatars = 3;
_avatarMargin = 2.0;
_moreLabel = nil;
_moreLabelTextColor = kMoreLabelDefaultcolor;
}
return self;
}
- (void)refreshReceiptSenders:(NSArray<MXRoomMember*>*)roomMembers withPlaceHolders:(NSArray<UIImage*>*)placeHolders andAlignment:(ReadReceiptsAlignment)alignment
{
// Store the room members and placeholders for showing in the details view controller
self.roomMembers = roomMembers;
self.placeholders = placeHolders;
// Remove all previous content
for (UIView* view in self.subviews)
{
[view removeFromSuperview];
}
if (_moreLabel)
{
[_moreLabel removeFromSuperview];
_moreLabel = nil;
}
CGRect globalFrame = self.frame;
CGFloat side = globalFrame.size.height;
CGFloat defaultMoreLabelWidth = side < 20 ? 20 : side;
unsigned long count;
unsigned long maxDisplayableItems = (int)((globalFrame.size.width - defaultMoreLabelWidth - _avatarMargin) / (side + _avatarMargin));
maxDisplayableItems = MIN(maxDisplayableItems, _maxDisplayedAvatars);
count = MIN(roomMembers.count, maxDisplayableItems);
int index;
CGFloat xOff = 0;
if (alignment == ReadReceiptAlignmentRight)
{
xOff = globalFrame.size.width - (side + _avatarMargin);
}
for (index = 0; index < count; index++)
{
MXRoomMember *roomMember = [roomMembers objectAtIndex:index];
UIImage *preview = index < placeHolders.count ? placeHolders[index] : nil;
MXKImageView *imageView = [[MXKImageView alloc] initWithFrame:CGRectMake(xOff, 0, side, side)];
imageView.defaultBackgroundColor = [UIColor clearColor];
imageView.autoresizingMask = UIViewAutoresizingNone;
if (alignment == ReadReceiptAlignmentRight)
{
xOff -= side + _avatarMargin;
}
else
{
xOff += side + _avatarMargin;
}
[self addSubview:imageView];
imageView.enableInMemoryCache = YES;
[imageView setImageURI:roomMember.avatarUrl
withType:nil
andImageOrientation:UIImageOrientationUp
toFitViewSize:CGSizeMake(side, side)
withMethod:MXThumbnailingMethodCrop
previewImage:preview
mediaManager:_mediaManager];
[imageView.layer setCornerRadius:imageView.frame.size.width / 2];
imageView.clipsToBounds = YES;
}
// Check whether there are more than expected read receipts
if (roomMembers.count > maxDisplayableItems)
{
// Add a more indicator
// In case of right alignment, adjust the current position by considering the default label width
if (alignment == ReadReceiptAlignmentRight && side < defaultMoreLabelWidth)
{
xOff -= (defaultMoreLabelWidth - side);
}
_moreLabel = [[UILabel alloc] initWithFrame:CGRectMake(xOff, 0, defaultMoreLabelWidth, side)];
_moreLabel.text = [NSString stringWithFormat:(alignment == ReadReceiptAlignmentRight) ? @"%tu+" : @"+%tu", roomMembers.count - maxDisplayableItems];
_moreLabel.font = [UIFont systemFontOfSize:11];
_moreLabel.adjustsFontSizeToFitWidth = YES;
_moreLabel.minimumScaleFactor = 0.6;
// In case of right alignment, adjust the horizontal position according to the actual label width
if (alignment == ReadReceiptAlignmentRight)
{
[_moreLabel sizeToFit];
CGRect frame = _moreLabel.frame;
if (frame.size.width < defaultMoreLabelWidth)
{
frame.origin.x += (defaultMoreLabelWidth - frame.size.width);
_moreLabel.frame = frame;
}
}
_moreLabel.textColor = self.moreLabelTextColor ?: kMoreLabelDefaultcolor;
[self addSubview:_moreLabel];
}
}
- (void)dealloc
{
NSArray* subviews = self.subviews;
for (UIView* view in subviews)
{
[view removeFromSuperview];
}
if (_moreLabel)
{
[_moreLabel removeFromSuperview];
_moreLabel = nil;
}
}
@end
@@ -1,33 +0,0 @@
/*
Copyright 2015 OpenMarket 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 "MXKRoomInputToolbarView.h"
#import <HPGrowingTextView/HPGrowingTextView.h>
/**
`MXKRoomInputToolbarViewWithHPGrowingText` is a MXKRoomInputToolbarView-inherited class in which message
composer is based on `HPGrowingTextView`.
Toolbar buttons are not overridden by this class. We keep the default implementation.
*/
@interface MXKRoomInputToolbarViewWithHPGrowingText : MXKRoomInputToolbarView <HPGrowingTextViewDelegate>
{
@protected
HPGrowingTextView *growingTextView;
}
@end
@@ -1,187 +0,0 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations 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 "MXKRoomInputToolbarViewWithHPGrowingText.h"
@interface MXKRoomInputToolbarViewWithHPGrowingText()
{
// HPGrowingTextView triggers growingTextViewDidChange event when it recomposes itself
// Save the last edited text to prevent unexpected typing events
NSString* lastEditedText;
}
/**
Message composer defined in `messageComposerContainer`.
*/
@property (nonatomic) IBOutlet HPGrowingTextView *growingTextView;
@end
@implementation MXKRoomInputToolbarViewWithHPGrowingText
@synthesize growingTextView;
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass([MXKRoomInputToolbarViewWithHPGrowingText class])
bundle:[NSBundle bundleForClass:[MXKRoomInputToolbarViewWithHPGrowingText class]]];
}
- (void)awakeFromNib
{
[super awakeFromNib];
// Handle message composer based on HPGrowingTextView use
growingTextView.delegate = self;
[growingTextView setTranslatesAutoresizingMaskIntoConstraints: NO];
// Add an accessory view to the text view in order to retrieve keyboard view.
inputAccessoryView = [[UIView alloc] initWithFrame:CGRectZero];
growingTextView.internalTextView.inputAccessoryView = self.inputAccessoryView;
// on IOS 8, the growing textview animation could trigger weird UI animations
// indeed, the messages tableView can be refreshed while its height is updated (e.g. when setting a message)
growingTextView.animateHeightChange = NO;
lastEditedText = nil;
}
- (void)dealloc
{
[self destroy];
}
-(void)customizeViewRendering
{
[super customizeViewRendering];
// set text input font
growingTextView.font = [UIFont systemFontOfSize:14];
// draw a rounded border around the textView
growingTextView.layer.cornerRadius = 5;
growingTextView.layer.borderWidth = 1;
growingTextView.layer.borderColor = [UIColor lightGrayColor].CGColor;
growingTextView.clipsToBounds = YES;
growingTextView.backgroundColor = [UIColor whiteColor];
}
- (void)destroy
{
if (growingTextView)
{
growingTextView.delegate = nil;
growingTextView = nil;
}
[super destroy];
}
- (void)setMaxHeight:(CGFloat)maxHeight
{
growingTextView.maxHeight = maxHeight - (self.messageComposerContainerTopConstraint.constant + self.messageComposerContainerBottomConstraint.constant);
[growingTextView refreshHeight];
super.maxHeight = maxHeight;
}
- (NSString*)textMessage
{
return growingTextView.text;
}
- (void)setTextMessage:(NSString *)textMessage
{
growingTextView.text = textMessage;
self.rightInputToolbarButton.enabled = textMessage.length;
}
- (void)pasteText:(NSString *)text
{
self.textMessage = [growingTextView.text stringByReplacingCharactersInRange:growingTextView.selectedRange withString:text];
}
- (void)setPlaceholder:(NSString *)inPlaceholder
{
[super setPlaceholder:inPlaceholder];
growingTextView.placeholder = inPlaceholder;
}
- (BOOL)becomeFirstResponder
{
return [growingTextView becomeFirstResponder];
}
- (void)dismissKeyboard
{
[growingTextView resignFirstResponder];
}
#pragma mark - HPGrowingTextView delegate
- (void)growingTextViewDidEndEditing:(HPGrowingTextView *)sender
{
if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:isTyping:)])
{
[self.delegate roomInputToolbarView:self isTyping:NO];
}
}
- (void)growingTextViewDidChange:(HPGrowingTextView *)sender
{
NSString *msg = growingTextView.text;
// HPGrowingTextView triggers growingTextViewDidChange event when it recomposes itself.
// Save the last edited text to prevent unexpected typing events
if (![lastEditedText isEqualToString:msg])
{
lastEditedText = msg;
if (msg.length)
{
if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:isTyping:)])
{
[self.delegate roomInputToolbarView:self isTyping:YES];
}
self.rightInputToolbarButton.enabled = YES;
}
else
{
if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:isTyping:)])
{
[self.delegate roomInputToolbarView:self isTyping:NO];
}
self.rightInputToolbarButton.enabled = NO;
}
}
}
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height
{
// Update growing text's superview (toolbar view)
CGFloat updatedHeight = height + (self.messageComposerContainerTopConstraint.constant + self.messageComposerContainerBottomConstraint.constant);
if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:heightDidChanged:completion:)])
{
[self.delegate roomInputToolbarView:self heightDidChanged:updatedHeight completion:nil];
}
}
- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return self.isEditable;
}
@end
@@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="MXKRoomInputToolbarViewWithHPGrowingText">
<rect key="frame" x="0.0" y="0.0" width="600" height="41"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="contactAdd" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Hga-l8-Wua" userLabel="left Button">
<rect key="frame" x="8" y="0.0" width="35" height="41"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="35" id="ptO-BQ-NhS"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="onTouchUpInside:" destination="iN0-l3-epB" eventType="touchUpInside" id="jVG-We-DmS"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Owf-M8-qJi" userLabel="right Button">
<rect key="frame" x="552" y="0.0" width="44" height="41"/>
<constraints>
<constraint firstAttribute="width" constant="44" id="9FZ-CI-diT"/>
</constraints>
<state key="normal" title="Send">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="onTouchUpInside:" destination="iN0-l3-epB" eventType="touchUpInside" id="jed-Mz-rxe"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QWp-NV-uh5" userLabel="Message Composer Container">
<rect key="frame" x="51" y="4" width="497" height="33"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pkf-YH-tco" customClass="HPGrowingTextView">
<rect key="frame" x="0.0" y="0.0" width="497" height="33"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</subviews>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="pkf-YH-tco" secondAttribute="bottom" id="L3A-Oo-Ml2"/>
<constraint firstItem="pkf-YH-tco" firstAttribute="top" secondItem="QWp-NV-uh5" secondAttribute="top" id="VPn-k0-0vc"/>
<constraint firstItem="pkf-YH-tco" firstAttribute="leading" secondItem="QWp-NV-uh5" secondAttribute="leading" id="mXj-f3-DcT"/>
<constraint firstAttribute="trailing" secondItem="pkf-YH-tco" secondAttribute="trailing" id="n4K-Do-gHr"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.89720267057418823" green="0.89720267057418823" blue="0.89720267057418823" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Owf-M8-qJi" secondAttribute="trailing" constant="4" id="2M8-Gu-0f6"/>
<constraint firstItem="QWp-NV-uh5" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="4" id="570-8j-VYY"/>
<constraint firstAttribute="bottom" secondItem="QWp-NV-uh5" secondAttribute="bottom" constant="4" id="9Ya-0H-03W"/>
<constraint firstItem="Hga-l8-Wua" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="8" id="Bc8-T7-wmA"/>
<constraint firstItem="Hga-l8-Wua" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Cvk-xZ-ODy"/>
<constraint firstItem="Owf-M8-qJi" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="SV8-U3-8dd"/>
<constraint firstAttribute="bottom" secondItem="Hga-l8-Wua" secondAttribute="bottom" id="Slr-2H-laO"/>
<constraint firstItem="Owf-M8-qJi" firstAttribute="leading" secondItem="QWp-NV-uh5" secondAttribute="trailing" constant="4" id="UEd-gb-jgR"/>
<constraint firstItem="QWp-NV-uh5" firstAttribute="leading" secondItem="Hga-l8-Wua" secondAttribute="trailing" constant="8" id="cCr-Am-M7d"/>
<constraint firstAttribute="bottom" secondItem="Owf-M8-qJi" secondAttribute="bottom" id="ycc-x9-PAv"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="growingTextView" destination="pkf-YH-tco" id="VeP-WI-6Xh"/>
<outlet property="leftInputToolbarButton" destination="Hga-l8-Wua" id="zbm-3b-hoY"/>
<outlet property="messageComposerContainer" destination="QWp-NV-uh5" id="7EX-Un-ZIe"/>
<outlet property="messageComposerContainerBottomConstraint" destination="9Ya-0H-03W" id="226-iu-6tU"/>
<outlet property="messageComposerContainerTopConstraint" destination="570-8j-VYY" id="VKv-Qh-PCs"/>
<outlet property="rightInputToolbarButton" destination="Owf-M8-qJi" id="seO-ly-Bgg"/>
</connections>
</view>
</objects>
</document>