Merge MatrixKit develop with commit hash: b85b736313bec0592bd1cabc68035d97f5331137

This commit is contained in:
SBiOSoftWhare
2021-12-03 11:47:24 +01:00
parent 475fe5552f
commit 1d9f01b5e3
475 changed files with 87437 additions and 0 deletions
@@ -0,0 +1,26 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
@import Foundation;
#import "MXKErrorPresentation.h"
/**
`MXKErrorAlertPresentation` is a concrete implementation of `MXKErrorPresentation` using UIAlertViewController. Display error alert from a view controller.
*/
@interface MXKErrorAlertPresentation : NSObject<MXKErrorPresentation>
@end
@@ -0,0 +1,108 @@
/*
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 "MXKErrorAlertPresentation.h"
#import "MXKErrorPresentableBuilder.h"
#import "NSBundle+MatrixKit.h"
#import "MXKSwiftHeader.h"
@interface MXKErrorAlertPresentation()
@property (nonatomic, strong) MXKErrorPresentableBuilder *errorPresentableBuidler;
@end
#pragma mark - Implementation
@implementation MXKErrorAlertPresentation
#pragma mark - Setup & Teardown
- (instancetype)init
{
self = [super init];
if (self) {
_errorPresentableBuidler = [[MXKErrorPresentableBuilder alloc] init];
}
return self;
}
#pragma mark - MXKErrorPresentation
- (void)presentErrorFromViewController:(UIViewController*)viewController
title:(NSString*)title
message:(NSString*)message
animated:(BOOL)animated
handler:(void (^)(void))handler
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n ok]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
if (handler)
{
handler();
}
}]];
[viewController presentViewController:alert animated:animated completion:nil];
}
- (void)presentErrorFromViewController:(UIViewController*)viewController
forError:(NSError*)error
animated:(BOOL)animated
handler:(void (^)(void))handler
{
id <MXKErrorPresentable> errorPresentable = [self.errorPresentableBuidler errorPresentableFromError:error];
if (errorPresentable)
{
[self presentErrorFromViewController:viewController
forErrorPresentable:errorPresentable
animated:animated
handler:handler];
}
}
- (void)presentGenericErrorFromViewController:(UIViewController*)viewController
animated:(BOOL)animated
handler:(void (^)(void))handler
{
id <MXKErrorPresentable> errorPresentable = [self.errorPresentableBuidler commonErrorPresentable];
[self presentErrorFromViewController:viewController
forErrorPresentable:errorPresentable
animated:animated
handler:handler];
}
- (void)presentErrorFromViewController:(UIViewController*)viewController
forErrorPresentable:(id<MXKErrorPresentable>)errorPresentable
animated:(BOOL)animated
handler:(void (^)(void))handler
{
[self presentErrorFromViewController:viewController
title:errorPresentable.title
message:errorPresentable.message
animated:animated
handler:handler];
}
@end
@@ -0,0 +1,29 @@
/*
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.
*/
/**
`MXKErrorPresentable` describe an error to display on screen.
*/
@protocol MXKErrorPresentable
@required
@property (strong, nonatomic, readonly) NSString *title;
@property (strong, nonatomic, readonly) NSString *message;
- (id)initWithTitle:(NSString*)title message:(NSString*)message;
@end
@@ -0,0 +1,41 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
@import Foundation;
#import "MXKErrorPresentable.h"
/**
`MXKErrorPresentableBuilder` enable to create error to present on screen.
*/
@interface MXKErrorPresentableBuilder : NSObject
/**
Build a displayable error from a NSError.
@param error an NSError.
@return Return nil in case of network request cancellation error otherwise return a presentable error from NSError informations.
*/
- (id <MXKErrorPresentable>)errorPresentableFromError:(NSError*)error;
/**
Build a common displayable error. Generic error message to present as fallback when error explanation can't be user friendly.
@return Common default error.
*/
- (id <MXKErrorPresentable>)commonErrorPresentable;
@end
@@ -0,0 +1,56 @@
/*
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 "MXKErrorPresentableBuilder.h"
#import "NSBundle+MatrixKit.h"
#import "MXKErrorViewModel.h"
#import "MXKSwiftHeader.h"
@implementation MXKErrorPresentableBuilder
- (id <MXKErrorPresentable>)errorPresentableFromError:(NSError*)error
{
// Ignore nil error or connection cancellation error
if (!error || ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorCancelled))
{
return nil;
}
NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey];
NSString *message = [error.userInfo valueForKey:NSLocalizedDescriptionKey];
if (!title)
{
title = [MatrixKitL10n error];
}
if (!message)
{
message = [MatrixKitL10n errorCommonMessage];
}
return [[MXKErrorViewModel alloc] initWithTitle:title message:message];
}
- (id <MXKErrorPresentable>)commonErrorPresentable
{
return [[MXKErrorViewModel alloc] initWithTitle:[MatrixKitL10n error]
message:[MatrixKitL10n errorCommonMessage]];
}
@end
@@ -0,0 +1,49 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
@import Foundation;
@import UIKit;
#import "MXKErrorPresentable.h"
/**
`MXKErrorPresentation` describe an error display handler for presenting error from a view controller.
*/
@protocol MXKErrorPresentation
- (void)presentErrorFromViewController:(UIViewController*)viewController
title:(NSString*)title
message:(NSString*)message
animated:(BOOL)animated
handler:(void (^)(void))handler;
- (void)presentErrorFromViewController:(UIViewController*)viewController
forError:(NSError*)error
animated:(BOOL)animated
handler:(void (^)(void))handler;
- (void)presentGenericErrorFromViewController:(UIViewController*)viewController
animated:(BOOL)animated
handler:(void (^)(void))handler;
@required
- (void)presentErrorFromViewController:(UIViewController*)viewController
forErrorPresentable:(id<MXKErrorPresentable>)errorPresentable
animated:(BOOL)animated
handler:(void (^)(void))handler;
@end
@@ -0,0 +1,26 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
@import Foundation;
#import "MXKErrorPresentable.h"
/**
`MXKErrorViewModel` is a concrete implementation of `MXKErrorPresentable`
*/
@interface MXKErrorViewModel : NSObject<MXKErrorPresentable>
@end
@@ -0,0 +1,41 @@
/*
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 "MXKErrorViewModel.h"
@interface MXKErrorViewModel()
@property (strong, nonatomic) NSString *title;
@property (strong, nonatomic) NSString *message;
@end
@implementation MXKErrorViewModel
- (id)initWithTitle:(NSString*)title message:(NSString*)message
{
self = [super init];
if (self)
{
_title = title;
_message = message;
}
return self;
}
@end
@@ -0,0 +1,409 @@
/*
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 <Foundation/Foundation.h>
#import <MatrixSDK/MatrixSDK.h>
#import "MXKAppSettings.h"
@protocol MarkdownToHTMLRendererProtocol;
/**
Formatting result codes.
*/
typedef enum : NSUInteger {
/**
The formatting was successful.
*/
MXKEventFormatterErrorNone = 0,
/**
The formatter knows the event type but it encountered data that it does not support.
*/
MXKEventFormatterErrorUnsupported,
/**
The formatter encountered unexpected data in the event.
*/
MXKEventFormatterErrorUnexpected,
/**
The formatter does not support the type of the passed event.
*/
MXKEventFormatterErrorUnknownEventType
} MXKEventFormatterError;
/**
`MXKEventFormatter` is an utility class for formating Matrix events into strings which
will be displayed to the end user.
*/
@interface MXKEventFormatter : NSObject <MXRoomSummaryUpdating>
{
@protected
/**
The matrix session. Used to get contextual data.
*/
MXSession *mxSession;
/**
The date formatter used to build date string without time information.
*/
NSDateFormatter *dateFormatter;
/**
The time formatter used to build time string without date information.
*/
NSDateFormatter *timeFormatter;
/**
The default room summary updater from the MXSession.
*/
MXRoomSummaryUpdater *defaultRoomSummaryUpdater;
}
/**
The settings used to handle room events.
By default the shared application settings are considered.
*/
@property (nonatomic) MXKAppSettings *settings;
/**
Flag indicating if the formatter must build strings that will be displayed as subtitle.
Default is NO.
*/
@property (nonatomic) BOOL isForSubtitle;
/**
Flags indicating if the formatter must create clickable links for Matrix user ids,
room ids, room aliases or event ids.
Default is NO.
*/
@property (nonatomic) BOOL treatMatrixUserIdAsLink;
@property (nonatomic) BOOL treatMatrixRoomIdAsLink;
@property (nonatomic) BOOL treatMatrixRoomAliasAsLink;
@property (nonatomic) BOOL treatMatrixEventIdAsLink;
@property (nonatomic) BOOL treatMatrixGroupIdAsLink;
/**
Initialise the event formatter.
@param mxSession the Matrix to retrieve contextual data.
@return the newly created instance.
*/
- (instancetype)initWithMatrixSession:(MXSession*)mxSession;
/**
Initialise the date and time formatters.
This formatter could require to be updated after updating the device settings.
e.g the time format switches from 24H format to AM/PM.
*/
- (void)initDateTimeFormatters;
/**
The types of events allowed to be displayed in the room history.
No string will be returned by the formatter for the events whose the type doesn't belong to this array.
Default is nil. All messages types are displayed.
*/
@property (nonatomic) NSArray<NSString*> *eventTypesFilterForMessages;
@property (nonatomic, strong) id<MarkdownToHTMLRendererProtocol> markdownToHTMLRenderer;
/**
Checks whether the event is related to an attachment and if it is supported.
@param event an event.
@return YES if the provided event is related to a supported attachment type.
*/
- (BOOL)isSupportedAttachment:(MXEvent*)event;
#pragma mark - Events to strings conversion methods
/**
Compose the event sender display name according to the current room state.
@param event the event to format.
@param roomState the room state right before the event.
@return the sender display name
*/
- (NSString*)senderDisplayNameForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
/**
Compose the event target display name according to the current room state.
@discussion "target" refers to the room member who is the target of this event (if any), e.g.
the invitee, the person being banned, etc.
@param event the event to format.
@param roomState the room state right before the event.
@return the target display name (if any)
*/
- (NSString*)targetDisplayNameForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
/**
Retrieve the avatar url of the event sender from the current room state.
@param event the event to format.
@param roomState the room state right before the event.
@return the sender avatar url
*/
- (NSString*)senderAvatarUrlForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
/**
Retrieve the avatar url of the event target from the current room state.
@discussion "target" refers to the room member who is the target of this event (if any), e.g.
the invitee, the person being banned, etc.
@param event the event to format.
@param roomState the room state right before the event.
@return the target avatar url (if any)
*/
- (NSString*)targetAvatarUrlForEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
/**
Generate a displayable string representating the event.
@param event the event to format.
@param roomState the room state right before the event.
@param error the error code. In case of formatting error, the formatter may return non nil string as a proposal.
@return the display text for the event.
*/
- (NSString*)stringFromEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState error:(MXKEventFormatterError*)error;
/**
Generate a displayable attributed string representating the event.
@param event the event to format.
@param roomState the room state right before the event.
@param error the error code. In case of formatting error, the formatter may return non nil string as a proposal.
@return the attributed string for the event.
*/
- (NSAttributedString*)attributedStringFromEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState error:(MXKEventFormatterError*)error;
/**
Generate a displayable attributed string representating a summary for the provided events.
@param events the series of events to format.
@param roomState the room state right before the first event in the series.
@param error the error code. In case of formatting error, the formatter may return non nil string as a proposal.
@return the attributed string.
*/
- (NSAttributedString*)attributedStringFromEvents:(NSArray<MXEvent*>*)events withRoomState:(MXRoomState*)roomState error:(MXKEventFormatterError*)error;
/**
Render a random string into an attributed string with the font and the text color
that correspond to the passed event.
@param string the string to render.
@param event the event associated to the string.
@return an attributed string.
*/
- (NSAttributedString*)renderString:(NSString*)string forEvent:(MXEvent*)event;
/**
Render a random html string into an attributed string with the font and the text color
that correspond to the passed event.
@param htmlString the HTLM string to render.
@param event the event associated to the string.
@param roomState the room state right before the event.
@return an attributed string.
*/
- (NSAttributedString*)renderHTMLString:(NSString*)htmlString forEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
/**
Same as [self renderString:forEvent:] but add a prefix.
The prefix will be rendered with 'prefixTextFont' and 'prefixTextColor'.
@param string the string to render.
@param prefix the prefix to add.
@param event the event associated to the string.
@return an attributed string.
*/
- (NSAttributedString*)renderString:(NSString*)string withPrefix:(NSString*)prefix forEvent:(MXEvent*)event;
#pragma mark - Conversion tools
/**
Convert a Markdown string to HTML.
@param markdownString the string to convert.
@return an HTML formatted string.
*/
- (NSString*)htmlStringFromMarkdownString:(NSString*)markdownString;
#pragma mark - Timestamp formatting
/**
Generate the date in string format corresponding to the date.
@param date The date.
@param time The flag used to know if the returned string must include time information or not.
@return the string representation of the date.
*/
- (NSString*)dateStringFromDate:(NSDate *)date withTime:(BOOL)time;
/**
Generate the date in string format corresponding to the timestamp.
The returned string is localised according to the current device settings.
@param timestamp The timestamp in milliseconds since Epoch.
@param time The flag used to know if the returned string must include time information or not.
@return the string representation of the date.
*/
- (NSString*)dateStringFromTimestamp:(uint64_t)timestamp withTime:(BOOL)time;
/**
Generate the date in string format corresponding to the event.
The returned string is localised according to the current device settings.
@param event The event to format.
@param time The flag used to know if the returned string must include time information or not.
@return the string representation of the event date.
*/
- (NSString*)dateStringFromEvent:(MXEvent*)event withTime:(BOOL)time;
/**
Generate the time string of the provided date by considered the current system time formatting.
@param date The date.
@return the string representation of the time component of the date.
*/
- (NSString*)timeStringFromDate:(NSDate *)date;
# pragma mark - Customisation
/**
The list of allowed HTML tags in rendered attributed strings.
*/
@property (nonatomic) NSArray<NSString*> *allowedHTMLTags;
/**
A block to run on HTML `img` tags when calling `renderHTMLString:forEvent:withRoomState:`.
This block provides the original URL for the image and can be used to download the image locally
and return a local file URL for the image to attach to the rendered attributed string.
*/
@property (nonatomic, copy) NSURL* (^htmlImageHandler)(NSString *sourceURL, CGFloat width, CGFloat height);
/**
The style sheet used by the 'renderHTMLString' method.
*/
@property (nonatomic) NSString *defaultCSS;
/**
Default color used to display text content of event.
Default is [UIColor blackColor].
*/
@property (nonatomic) UIColor *defaultTextColor;
/**
Default color used to display text content of event when it is displayed as subtitle (related to 'isForSubtitle' property).
Default is [UIColor blackColor].
*/
@property (nonatomic) UIColor *subTitleTextColor;
/**
Color applied on the event description prefix used to display for example the message sender name.
Default is [UIColor blackColor].
*/
@property (nonatomic) UIColor *prefixTextColor;
/**
Color used when the event must be bing to the end user. This happens when the event
matches the user's push rules.
Default is [UIColor blueColor].
*/
@property (nonatomic) UIColor *bingTextColor;
/**
Color used to display text content of an event being encrypted.
Default is [UIColor lightGrayColor].
*/
@property (nonatomic) UIColor *encryptingTextColor;
/**
Color used to display text content of an event being sent.
Default is [UIColor lightGrayColor].
*/
@property (nonatomic) UIColor *sendingTextColor;
/**
Color used to display error text.
Default is red.
*/
@property (nonatomic) UIColor *errorTextColor;
/**
Color used to display the side border of HTML blockquotes.
Default is a grey.
*/
@property (nonatomic) UIColor *htmlBlockquoteBorderColor;
/**
Default text font used to display text content of event.
Default is SFUIText-Regular 14.
*/
@property (nonatomic) UIFont *defaultTextFont;
/**
Font applied on the event description prefix used to display for example the message sender name.
Default is SFUIText-Regular 14.
*/
@property (nonatomic) UIFont *prefixTextFont;
/**
Text font used when the event must be bing to the end user. This happens when the event
matches the user's push rules.
Default is SFUIText-Regular 14.
*/
@property (nonatomic) UIFont *bingTextFont;
/**
Text font used when the event is a state event.
Default is italic SFUIText-Regular 14.
*/
@property (nonatomic) UIFont *stateEventTextFont;
/**
Text font used to display call notices (invite, answer, hangup).
Default is SFUIText-Regular 14.
*/
@property (nonatomic) UIFont *callNoticesTextFont;
/**
Text font used to display encrypted messages.
Default is SFUIText-Regular 14.
*/
@property (nonatomic) UIFont *encryptedMessagesTextFont;
/**
Text font used to display message containing a single emoji.
Default is nil (same font as self.emojiOnlyTextFont).
*/
@property (nonatomic) UIFont *singleEmojiTextFont;
/**
Text font used to display message containing only emojis.
Default is nil (same font as self.defaultTextFont).
*/
@property (nonatomic) UIFont *emojiOnlyTextFont;
@end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
@import Foundation;
#import <MatrixSDK/MXRoomNameStringLocalizerProtocol.h>
/**
The `MXKRoomNameStringLocalizer` implements localization strings for `MXRoomNameStringLocalizerProtocol`.
*/
@interface MXKRoomNameStringLocalizer : NSObject <MXRoomNameStringLocalizerProtocol>
@end
@@ -0,0 +1,42 @@
/*
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 "MXKRoomNameStringLocalizer.h"
#import "MXKSwiftHeader.h"
@implementation MXKRoomNameStringLocalizer
- (NSString *)emptyRoom
{
return [MatrixKitL10n roomDisplaynameEmptyRoom];
}
- (NSString *)twoMembers:(NSString *)firstMember second:(NSString *)secondMember
{
return [MatrixKitL10n roomDisplaynameTwoMembers:firstMember :secondMember];
}
- (NSString *)moreThanTwoMembers:(NSString *)firstMember count:(NSNumber *)memberCount
{
return [MatrixKitL10n roomDisplaynameMoreThanTwoMembers:firstMember :memberCount.stringValue];
}
- (NSString *)allOtherMembersLeft:(NSString *)member
{
return [MatrixKitL10n roomDisplaynameAllOtherMembersLeft:member];
}
@end
@@ -0,0 +1,52 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
import Down
import libcmark
@objc public protocol MarkdownToHTMLRendererProtocol: NSObjectProtocol {
func renderToHTML(markdown: String) -> String?
}
@objcMembers
public class MarkdownToHTMLRenderer: NSObject {
fileprivate var options: DownOptions = []
// Do not expose an initializer with options, because `DownOptions` is not ObjC compatible.
public override init() {
super.init()
}
}
extension MarkdownToHTMLRenderer: MarkdownToHTMLRendererProtocol {
public func renderToHTML(markdown: String) -> String? {
return try? Down(markdownString: markdown).toHTML(options)
}
}
@objcMembers
public class MarkdownToHTMLRendererHardBreaks: MarkdownToHTMLRenderer {
public override init() {
super.init()
options = .hardBreaks
}
}
@@ -0,0 +1,33 @@
//
// Copyright 2020 The Matrix.org Foundation C.I.C
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <Foundation/Foundation.h>
typedef NSString *const MXKAnalyticsCategory NS_TYPED_EXTENSIBLE_ENUM;
/**
The analytics category for local contacts.
*/
static MXKAnalyticsCategory const MXKAnalyticsCategoryContacts = @"localContacts";
typedef NSString *const MXKAnalyticsName NS_TYPED_EXTENSIBLE_ENUM;
/**
The analytics value for accept/decline of local contacts access.
*/
static MXKAnalyticsName const MXKAnalyticsNameContactsAccessGranted = @"accessGranted";
@@ -0,0 +1,41 @@
/*
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 <UIKit/UIKit.h>
#define MXK_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
#define MXK_DEPRECATED_ATTRIBUTE_WITH_MSG(msg) __attribute((deprecated((msg))))
/**
The Matrix iOS Kit version.
*/
FOUNDATION_EXPORT NSString *const MatrixKitVersion;
/**
Posted when an error is observed at Matrix Kit level.
This notification may be used to inform user by showing the error as an alert.
The notification object is the NSError instance.
The passed userInfo dictionary may contain:
- `kMXKErrorUserIdKey` the matrix identifier of the account concerned by this error.
*/
FOUNDATION_EXPORT NSString *const kMXKErrorNotification;
/**
The key in notification userInfo dictionary representating the account userId.
*/
FOUNDATION_EXPORT NSString *const kMXKErrorUserIdKey;
@@ -0,0 +1,23 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C
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 "MXKConstants.h"
NSString *const kMXKErrorNotification = @"kMXKErrorNotification";
NSString *const kMXKErrorUserIdKey = @"kMXKErrorUserIdKey";
@@ -0,0 +1,80 @@
/*
Copyright 2019 The Matrix.org Foundation C.I.C
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 UIKit
import MobileCoreServices
@objc public protocol MXKDocumentPickerPresenterDelegate {
func documentPickerPresenter(_ presenter: MXKDocumentPickerPresenter, didPickDocumentsAt url: URL)
func documentPickerPresenterWasCancelled(_ presenter: MXKDocumentPickerPresenter)
}
/// 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)
@objcMembers
public class MXKDocumentPickerPresenter: NSObject {
// MARK: - Properties
// MARK: Private
private weak var presentingViewController: UIViewController?
// MARK: Public
public weak var delegate: MXKDocumentPickerPresenterDelegate?
public var isPresenting: Bool {
return self.presentingViewController?.parent != nil
}
// MARK: - Public
/// Presents a document picker view controller modally.
///
/// - Parameters:
/// - allowedUTIs: Allowed pickable file UTIs.
/// - viewController: The view controller on which to present the document picker.
/// - animated: Indicate true to animate.
/// - completion: Animation completion.
public func presentDocumentPicker(with allowedUTIs: [MXKUTI], from viewController: UIViewController, animated: Bool, completion: (() -> Void)?) {
let documentTypes = allowedUTIs.map { return $0.rawValue }
let documentPicker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
documentPicker.delegate = self
viewController.present(documentPicker, animated: animated, completion: completion)
self.presentingViewController = viewController
}
}
// MARK - UIDocumentPickerDelegate
extension MXKDocumentPickerPresenter: UIDocumentPickerDelegate {
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard let url = urls.first else {
return
}
self.delegate?.documentPickerPresenter(self, didPickDocumentsAt: url)
}
public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
self.delegate?.documentPickerPresenterWasCancelled(self)
}
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
self.delegate?.documentPickerPresenter(self, didPickDocumentsAt: url)
}
}
@@ -0,0 +1,47 @@
/*
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 <Foundation/Foundation.h>
/**
`MXKResponderRageShaking` defines a protocol an object must conform to handle rage shake
on view controllers or other kinds of `UIResponder`.
*/
@protocol MXKResponderRageShaking <NSObject>
/**
Tells the receiver that a motion event has begun.
@param responder the view controller (or another kind of `UIResponder`) which observed the motion.
*/
- (void)startShaking:(UIResponder*)responder;
/**
Tells the receiver that a motion event has ended.
@param responder the view controller (or another kind of `UIResponder`) which observed the motion.
*/
- (void)stopShaking:(UIResponder*)responder;
/**
Ignore pending rage shake related to the provided responder.
@param responder a view controller (or another kind of `UIResponder`).
*/
- (void)cancel:(UIResponder*)responder;
@end
@@ -0,0 +1,36 @@
/*
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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MXKSoundPlayer : NSObject
+ (instancetype)sharedInstance;
+ (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
- (void)playSoundAt:(NSURL *)url repeat:(BOOL)repeat vibrate:(BOOL)vibrate routeToBuiltInReceiver:(BOOL)useBuiltInReceiver;
- (void)stopPlayingWithAudioSessionDeactivation:(BOOL)deactivateAudioSession;
- (void)vibrateWithRepeat:(BOOL)repeat;
- (void)stopVibrating;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,145 @@
/*
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 "MXKSoundPlayer.h"
#import <AVFoundation/AVFAudio.h>
#import <AudioToolbox/AudioServices.h>
static const NSTimeInterval kVibrationInterval = 1.24875;
@interface MXKSoundPlayer () <AVAudioPlayerDelegate>
@property (nonatomic, nullable) AVAudioPlayer *audioPlayer;
@property (nonatomic, getter=isVibrating) BOOL vibrating;
@end
@implementation MXKSoundPlayer
+ (instancetype)sharedInstance
{
static MXKSoundPlayer *soundPlayer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
soundPlayer = [MXKSoundPlayer alloc];
});
return soundPlayer;
}
- (void)playSoundAt:(NSURL *)url repeat:(BOOL)repeat vibrate:(BOOL)vibrate routeToBuiltInReceiver:(BOOL)useBuiltInReceiver
{
if (self.audioPlayer)
{
[self stopPlayingWithAudioSessionDeactivation:NO];
}
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
if (!self.audioPlayer)
return;
self.audioPlayer.delegate = self;
self.audioPlayer.numberOfLoops = repeat ? -1 : 0;
[self.audioPlayer prepareToPlay];
// Setup AVAudioSession
// We use SoloAmbient instead of Playback category to respect silent mode
NSString *audioSessionCategory = useBuiltInReceiver ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategorySoloAmbient;
[[AVAudioSession sharedInstance] setCategory:audioSessionCategory error:nil];
if (vibrate)
[self vibrateWithRepeat:repeat];
[self.audioPlayer play];
}
- (void)stopPlayingWithAudioSessionDeactivation:(BOOL)deactivateAudioSession;
{
if (self.audioPlayer)
{
[self.audioPlayer stop];
self.audioPlayer = nil;
if (deactivateAudioSession)
{
// Release the audio session to allow resuming of background music app
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}
}
if (self.isVibrating)
{
[self stopVibrating];
}
}
- (void)vibrateWithRepeat:(BOOL)repeat
{
self.vibrating = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kVibrationInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
NSNumber *objRepeat = @(repeat);
AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate,
NULL,
kCFRunLoopCommonModes,
vibrationCompleted,
(__bridge_retained void * _Nullable)(objRepeat));
});
}
- (void)stopVibrating
{
self.vibrating = NO;
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
}
void vibrationCompleted(SystemSoundID ssID, void* __nullable clientData)
{
NSNumber *objRepeat = (__bridge NSNumber *)clientData;
BOOL repeat = [objRepeat boolValue];
CFRelease(clientData);
MXKSoundPlayer *soundPlayer = [MXKSoundPlayer sharedInstance];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kVibrationInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (repeat && soundPlayer.isVibrating)
{
[soundPlayer vibrateWithRepeat:repeat];
}
else
{
[soundPlayer stopVibrating];
}
});
}
#pragma mark - AVAudioPlayerDelegate
// This method is called only when the end of the player's track is reached.
// If you call `stop` or `pause` on player this method won't be called
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
self.audioPlayer = nil;
// Release the audio session to allow resuming of background music app
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}
@end
+426
View File
@@ -0,0 +1,426 @@
/*
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 <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#define MXKTOOLS_LARGE_IMAGE_SIZE 1024
#define MXKTOOLS_MEDIUM_IMAGE_SIZE 768
#define MXKTOOLS_SMALL_IMAGE_SIZE 512
#define MXKTOOLS_USER_IDENTIFIER_BITWISE 0x01
#define MXKTOOLS_ROOM_IDENTIFIER_BITWISE 0x02
#define MXKTOOLS_ROOM_ALIAS_BITWISE 0x04
#define MXKTOOLS_EVENT_IDENTIFIER_BITWISE 0x08
#define MXKTOOLS_GROUP_IDENTIFIER_BITWISE 0x10
// Attribute in an NSAttributeString that marks a blockquote block that was in the original HTML string.
extern NSString *const kMXKToolsBlockquoteMarkAttribute;
/**
Structure representing an the size of an image and its file size.
*/
typedef struct
{
CGSize imageSize;
NSUInteger fileSize;
} MXKImageCompressionSize;
/**
Structure representing the sizes of image (image size and file size) according to
different level of compression.
*/
typedef struct
{
MXKImageCompressionSize small;
MXKImageCompressionSize medium;
MXKImageCompressionSize large;
MXKImageCompressionSize original;
CGFloat actualLargeSize;
} MXKImageCompressionSizes;
@interface MXKTools : NSObject
#pragma mark - Strings
/**
Determine if a string contains one emoji and only one.
@param string the string to check.
@return YES if YES.
*/
+ (BOOL)isSingleEmojiString:(NSString*)string;
/**
Determine if a string contains only emojis.
@param string the string to check.
@return YES if YES.
*/
+ (BOOL)isEmojiOnlyString:(NSString*)string;
#pragma mark - Time
/**
Format time interval.
ex: "5m 31s".
@param secondsInterval time interval in seconds.
@return formatted string
*/
+ (NSString*)formatSecondsInterval:(CGFloat)secondsInterval;
/**
Format time interval but rounded to the nearest time unit below.
ex: "5s", "1m", "2h" or "3d".
@param secondsInterval time interval in seconds.
@return formatted string
*/
+ (NSString*)formatSecondsIntervalFloored:(CGFloat)secondsInterval;
#pragma mark - Phone number
/**
Return the number used to identify a mobile phone number internationally.
The provided country code is ignored when the phone number is already internationalized, or when it
is a valid msisdn.
@param phoneNumber the phone number.
@param countryCode the ISO 3166-1 country code representation (required when the phone number is in national format).
@return a valid msisdn or nil if the provided phone number is invalid.
*/
+ (NSString*)msisdnWithPhoneNumber:(NSString *)phoneNumber andCountryCode:(NSString *)countryCode;
/**
Format an MSISDN to a human readable international phone number.
@param msisdn The MSISDN to format.
@return Human readable international phone number.
*/
+ (NSString*)readableMSISDN:(NSString*)msisdn;
#pragma mark - Hex color to UIColor conversion
/**
Build a UIColor from an hexadecimal color value
@param rgbValue the color expressed in hexa (0xRRGGBB)
@return the UIColor
*/
+ (UIColor*)colorWithRGBValue:(NSUInteger)rgbValue;
/**
Build a UIColor from an hexadecimal color value with transparency
@param argbValue the color expressed in hexa (0xAARRGGBB)
@return the UIColor
*/
+ (UIColor*)colorWithARGBValue:(NSUInteger)argbValue;
/**
Return an hexadecimal color value from UIColor
@param color the UIColor
@return rgbValue the color expressed in hexa (0xRRGGBB)
*/
+ (NSUInteger)rgbValueWithColor:(UIColor*)color;
/**
Return an hexadecimal color value with transparency from UIColor
@param color the UIColor
@return argbValue the color expressed in hexa (0xAARRGGBB)
*/
+ (NSUInteger)argbValueWithColor:(UIColor*)color;
#pragma mark - Image processing
/**
Force image orientation to up
@param imageSrc the original image.
@return image with `UIImageOrientationUp` orientation.
*/
+ (UIImage*)forceImageOrientationUp:(UIImage*)imageSrc;
/**
Return struct MXKImageCompressionSizes representing the available compression sizes for the image
@param image the image to get available sizes for
@param originalFileSize the size in bytes of the original image file or the image data (0 if this value is unknown).
*/
+ (MXKImageCompressionSizes)availableCompressionSizesForImage:(UIImage*)image originalFileSize:(NSUInteger)originalFileSize;
/**
Compute image size to fit in specific box size (in aspect fit mode)
@param originalSize the original size
@param maxSize the box size
@param canExpand tell whether the image can be expand or not
@return the resized size.
*/
+ (CGSize)resizeImageSize:(CGSize)originalSize toFitInSize:(CGSize)maxSize canExpand:(BOOL)canExpand;
/**
Compute image size to fill specific box size (in aspect fill mode)
@param originalSize the original size
@param maxSize the box size
@param canExpand tell whether the image can be expand or not
@return the resized size.
*/
+ (CGSize)resizeImageSize:(CGSize)originalSize toFillWithSize:(CGSize)maxSize canExpand:(BOOL)canExpand;
/**
Reduce image to fit in the provided size.
The aspect ratio is kept.
If the image is smaller than the provided size, the image is not recomputed.
@discussion This method call `+ [reduceImage:toFitInSize:useMainScreenScale:]` with `useMainScreenScale` value to `NO`.
@param image the image to modify.
@param size to fit in.
@return resized image.
@see reduceImage:toFitInSize:useMainScreenScale:
*/
+ (UIImage *)reduceImage:(UIImage *)image toFitInSize:(CGSize)size;
/**
Reduce image to fit in the provided size.
The aspect ratio is kept.
If the image is smaller than the provided size, the image is not recomputed.
@param image the image to modify.
@param size to fit in.
@param useMainScreenScale Indicate true to use main screen scale.
@return resized image.
*/
+ (UIImage *)reduceImage:(UIImage *)image toFitInSize:(CGSize)size useMainScreenScale:(BOOL)useMainScreenScale;
/**
Reduce image to fit in the provided size.
The aspect ratio is kept.
@discussion This method use less memory than `+ [reduceImage:toFitInSize:useMainScreenScale:]`.
@param imageData The image data.
@param size Size to fit in.
@return Resized image or nil if the data is not interpreted.
*/
+ (UIImage*)resizeImageWithData:(NSData*)imageData toFitInSize:(CGSize)size;
/**
Resize image to a provided size.
@param image the image to modify.
@param size the new size.
@return resized image.
*/
+ (UIImage*)resizeImage:(UIImage *)image toSize:(CGSize)size;
/**
Resize image with rounded corners to a provided size.
@param image the image to modify.
@param size the new size.
@return resized image.
*/
+ (UIImage*)resizeImageWithRoundedCorners:(UIImage *)image toSize:(CGSize)size;
/**
Paint an image with a color.
@discussion
All non fully transparent (alpha = 0) will be painted with the provided color.
@param image the image to paint.
@param color the color to use.
@result a new UIImage object.
*/
+ (UIImage*)paintImage:(UIImage*)image withColor:(UIColor*)color;
/**
Convert a rotation angle to the most suitable image orientation.
@param angle rotation angle in degree.
@return image orientation.
*/
+ (UIImageOrientation)imageOrientationForRotationAngleInDegree:(NSInteger)angle;
/**
Draw the image resource in a view and transforms it to a pattern color.
The view size is defined by patternSize and will have a "backgroundColor" backgroundColor.
The resource image is drawn with the resourceSize size and is centered into its parent view.
@param reourceName the image resource name.
@param backgroundColor the pattern background color.
@param patternSize the pattern size.
@param resourceSize the resource size in the pattern.
@return the pattern color which can be used to define the background color of a view in order to display the provided image as its background.
*/
+ (UIColor*)convertImageToPatternColor:(NSString*)reourceName backgroundColor:(UIColor*)backgroundColor patternSize:(CGSize)patternSize resourceSize:(CGSize)resourceSize;
#pragma mark - Video conversion
/**
Creates a `UIAlertController` with appropriate `AVAssetExportPreset` choices for the video passed in.
@param videoAsset The video to generate the choices for.
@param completion The block called when a preset has been chosen. `presetName` will contain the preset name or `nil` if cancelled.
*/
+ (UIAlertController*)videoConversionPromptForVideoAsset:(AVAsset *)videoAsset
withCompletion:(void (^)(NSString * _Nullable presetName))completion;
#pragma mark - App permissions
/**
Check permission to access a media.
@discussion
If the access was not yet granted, a dialog will be shown to the user.
If it is the first attempt to access the media, the dialog is the classic iOS one.
Else, the dialog will ask the user to manually change the permission in the app settings.
@param mediaType the media type, either AVMediaTypeVideo or AVMediaTypeAudio.
@param manualChangeMessage the message to display if the end user must change the app settings manually.
@param viewController the view controller to attach the dialog displaying manualChangeMessage.
@param handler the block called with the result of requesting access
*/
+ (void)checkAccessForMediaType:(NSString *)mediaType
manualChangeMessage:(NSString*)manualChangeMessage
showPopUpInViewController:(UIViewController*)viewController
completionHandler:(void (^)(BOOL granted))handler;
/**
Check required permission for the provided call.
@param isVideoCall flag set to YES in case of video call.
@param manualChangeMessageForAudio the message to display if the end user must change the app settings manually for audio.
@param manualChangeMessageForVideo the message to display if the end user must change the app settings manually for video
@param viewController the view controller to attach the dialog displaying manualChangeMessage.
@param handler the block called with the result of requesting access
*/
+ (void)checkAccessForCall:(BOOL)isVideoCall
manualChangeMessageForAudio:(NSString*)manualChangeMessageForAudio
manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo
showPopUpInViewController:(UIViewController*)viewController
completionHandler:(void (^)(BOOL granted))handler;
/**
Check permission to access Contacts.
@discussion
If the access was not yet granted, a dialog will be shown to the user.
If it is the first attempt to access the media, the dialog is the classic iOS one.
Else, the dialog will ask the user to manually change the permission in the app settings.
@param manualChangeMessage the message to display if the end user must change the app settings manually.
If nil, the dialog for displaying manualChangeMessage will not be shown.
@param viewController the view controller to attach the dialog displaying manualChangeMessage.
@param handler the block called with the result of requesting access
*/
+ (void)checkAccessForContacts:(NSString*)manualChangeMessage
showPopUpInViewController:(UIViewController*)viewController
completionHandler:(void (^)(BOOL granted))handler;
/**
Check permission to access Contacts.
@discussion
If the access was not yet granted, a dialog will be shown to the user.
If it is the first attempt to access the media, the dialog is the classic iOS one.
Else, the dialog will ask the user to manually change the permission in the app settings.
@param manualChangeTitle the title to display if the end user must change the app settings manually.
@param manualChangeMessage the message to display if the end user must change the app settings manually.
If nil, the dialog for displaying manualChangeMessage will not be shown.
@param viewController the view controller to attach the dialog displaying manualChangeMessage.
@param handler the block called with the result of requesting access
*/
+ (void)checkAccessForContacts:(NSString *)manualChangeTitle
withManualChangeMessage:(NSString *)manualChangeMessage
showPopUpInViewController:(UIViewController *)viewController
completionHandler:(void (^)(BOOL granted))handler;
#pragma mark - HTML processing
/**
Removing DTCoreText artifacts:
- Trim trailing whitespace and newlines in the string content.
- Replace DTImageTextAttachments with a simple NSTextAttachment subclass.
@param attributedString an attributed string.
@return the resulting string.
*/
+ (NSAttributedString*)removeDTCoreTextArtifacts:(NSAttributedString*)attributedString;
/**
Make some matrix identifiers clickable in the string content.
@param attributedString an attributed string.
@param enabledMatrixIdsBitMask the bitmask used to list the types of matrix id to process (see MXKTOOLS_XXX__BITWISE).
@return the resulting string.
*/
+ (NSAttributedString*)createLinksInAttributedString:(NSAttributedString*)attributedString forEnabledMatrixIds:(NSInteger)enabledMatrixIdsBitMask;
#pragma mark - HTML processing - blockquote display handling
/**
Return a CSS to make DTCoreText mark blockquote blocks in the `NSAttributedString` output.
These blocks output will have a `DTTextBlocksAttribute` attribute in the `NSAttributedString`
that can be used for later computation (in `removeMarkedBlockquotesArtifacts`).
@return a CSS string.
*/
+ (NSString*)cssToMarkBlockquotes;
/**
Removing DTCoreText artifacts used to mark blockquote blocks.
@param attributedString an attributed string.
@return the resulting string.
*/
+ (NSAttributedString*)removeMarkedBlockquotesArtifacts:(NSAttributedString*)attributedString;
/**
Enumerate all sections of the attributed string that refer to an HTML blockquote block.
Must be used with `cssToMarkBlockquotes` and `removeMarkedBlockquotesArtifacts`.
@param attributedString the attributed string.
@param block a block called for each HTML blockquote blocks.
*/
+ (void)enumerateMarkedBlockquotesInAttributedString:(NSAttributedString*)attributedString usingBlock:(void (^)(NSRange range, BOOL *stop))block;
#pragma mark - Push
/**
Trim push token in order to log it.
@param pushToken the token to trim.
@return a trimmed description.
*/
+ (NSString*)logForPushToken:(NSData*)pushToken;
@end
File diff suppressed because it is too large Load Diff
+203
View File
@@ -0,0 +1,203 @@
/*
Copyright 2019 The Matrix.org Foundation C.I.C
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
import ImageIO
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
/// 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.
/// MXKUTI wraps UTI class from SwiftUTI library (https://github.com/mkeiser/SwiftUTI) to make it available for Objective-C.
@objcMembers
open class MXKUTI: NSObject, RawRepresentable {
public typealias RawValue = String
// MARK: - Properties
// MARK: Private
private let utiWrapper: UTI
// MARK: Public
/// UTI string
public var rawValue: String {
return utiWrapper.rawValue
}
/// Return associated prefered file extension (e.g. "png").
public var fileExtension: String? {
return utiWrapper.fileExtension
}
/// Return associated prefered mime-type (e.g. "image/png").
public var mimeType: String? {
return utiWrapper.mimeType
}
// MARK: - Setup
// MARK: Private
private init(utiWrapper: UTI) {
self.utiWrapper = utiWrapper
super.init()
}
// MARK: Public
/// Initialize with UTI String.
/// Note: Although this initializer is marked as failable, due to RawRepresentable conformity, it cannot fail.
///
/// - Parameter rawValue: UTI String (e.g. "public.png").
public required init?(rawValue: String) {
let utiWrapper = UTI(rawValue: rawValue)
self.utiWrapper = utiWrapper
super.init()
}
/// Initialize with UTI CFString.
///
/// - Parameter cfRawValue: UTI CFString (e.g. kUTTypePNG).
public convenience init?(cfRawValue: CFString) {
self.init(rawValue: cfRawValue as String)
}
/// Initialize with file extension.
///
/// - Parameter fileExtension: A file extesion (e.g. "png").
public convenience init(fileExtension: String) {
let utiWrapper = UTI(withExtension: fileExtension)
self.init(utiWrapper: utiWrapper)
}
/// Initialize with MIME type.
///
/// - Parameter mimeType: A MIME type (e.g. "image/png").
public convenience init?(mimeType: String) {
let utiWrapper = UTI(withMimeType: mimeType)
self.init(utiWrapper: utiWrapper)
}
/// Check current UTI conformance with another UTI.
///
/// - Parameter otherUTI: UTI which to conform with.
/// - Returns: true if self conforms to other UTI.
public func conforms(to otherUTI: MXKUTI) -> Bool {
return self.utiWrapper.conforms(to: otherUTI.utiWrapper)
}
/// Check whether the current UTI conforms to any UTIs within an array.
///
/// - Parameter otherUTIs: UTI which to conform with.
/// - Returns: true if self conforms to any of the other UTIs.
public func conformsToAny(of otherUTIs: [MXKUTI]) -> Bool {
for uti in otherUTIs {
if conforms(to: uti) {
return true
}
}
return false
}
}
// MARK: - Other convenients initializers
extension MXKUTI {
/// Initialize with image data.
///
/// - Parameter imageData: Image data.
convenience init?(imageData: Data) {
guard let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil),
let uti = CGImageSourceGetType(imageSource) else {
return nil
}
self.init(rawValue: uti as String)
}
/// Initialize with local file URL.
/// This method is currently applicable only to URLs for file system resources.
///
/// - Parameters:
/// - localFileURL: Local file URL.
/// - loadResourceValues: Indicate true to prefetch `typeIdentifierKey` URLResourceKey
convenience init?(localFileURL: URL, loadResourceValues: Bool = true) {
if loadResourceValues,
let _ = try? FileManager.default.contentsOfDirectory(at: localFileURL.deletingLastPathComponent(), includingPropertiesForKeys: [.typeIdentifierKey], options: []),
let uti = try? localFileURL.resourceValues(forKeys: [.typeIdentifierKey]).typeIdentifier {
self.init(rawValue: uti)
} else if localFileURL.pathExtension.isEmpty == false {
let fileExtension = localFileURL.pathExtension
self.init(fileExtension: fileExtension)
} else {
return nil
}
}
public convenience init?(localFileURL: URL) {
self.init(localFileURL: localFileURL, loadResourceValues: true)
}
}
// MARK: - Convenients conformance UTIs methods
extension MXKUTI {
public var isImage: Bool {
return self.conforms(to: MXKUTI.image)
}
public var isVideo: Bool {
return self.conforms(to: MXKUTI.movie)
}
public var isFile: Bool {
return self.conforms(to: MXKUTI.data)
}
}
// MARK: - Some system defined UTIs
extension MXKUTI {
public static let data = MXKUTI(cfRawValue: kUTTypeData)!
public static let text = MXKUTI(cfRawValue: kUTTypeText)!
public static let audio = MXKUTI(cfRawValue: kUTTypeAudio)!
public static let video = MXKUTI(cfRawValue: kUTTypeVideo)!
public static let movie = MXKUTI(cfRawValue: kUTTypeMovie)!
public static let image = MXKUTI(cfRawValue: kUTTypeImage)!
public static let png = MXKUTI(cfRawValue: kUTTypePNG)!
public static let jpeg = MXKUTI(cfRawValue: kUTTypeJPEG)!
public static let svg = MXKUTI(cfRawValue: kUTTypeScalableVectorGraphics)!
public static let url = MXKUTI(cfRawValue: kUTTypeURL)!
public static let fileUrl = MXKUTI(cfRawValue: kUTTypeFileURL)!
public static let html = MXKUTI(cfRawValue: kUTTypeHTML)!
public static let xml = MXKUTI(cfRawValue: kUTTypeXML)!
}
// MARK: - Convenience static methods
extension MXKUTI {
public static func mimeType(from fileExtension: String) -> String? {
return MXKUTI(fileExtension: fileExtension).mimeType
}
public static func fileExtension(from mimeType: String) -> String? {
return MXKUTI(mimeType: mimeType)?.fileExtension
}
}
@@ -0,0 +1,76 @@
/*
Copyright 2019 The Matrix.org Foundation C.I.C
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 UIKit
import AVFoundation
/// MXKVideoThumbnailGenerator is a utility class to generate a thumbnail image from a video file.
@objcMembers
public class MXKVideoThumbnailGenerator: NSObject {
public static let shared = MXKVideoThumbnailGenerator()
// MARK - Public
/// Generate thumbnail image from a video URL.
/// Note: Do not make `maximumSize` optional with default nil value for Objective-C compatibility.
///
/// - Parameters:
/// - url: Video URL.
/// - maximumSize: Maximum dimension for generated thumbnail image.
/// - Returns: Thumbnail image or nil.
public func generateThumbnail(from url: URL, with maximumSize: CGSize) -> UIImage? {
let finalSize: CGSize? = maximumSize != .zero ? maximumSize : nil
return self.generateThumbnail(from: url, with: finalSize)
}
/// Generate thumbnail image from a video URL.
///
/// - Parameter url: Video URL.
/// - Returns: Thumbnail image or nil.
public func generateThumbnail(from url: URL) -> UIImage? {
return generateThumbnail(from: url, with: nil)
}
// MARK - Private
/// Generate thumbnail image from a video URL.
///
/// - Parameters:
/// - url: Video URL.
/// - maximumSize: Maximum dimension for generated thumbnail image or nil to keep video dimension.
/// - Returns: Thumbnail image or nil.
private func generateThumbnail(from url: URL, with maximumSize: CGSize?) -> UIImage? {
let thumbnailImage: UIImage?
let asset = AVAsset(url: url)
let assetImageGenerator = AVAssetImageGenerator(asset: asset)
assetImageGenerator.appliesPreferredTrackTransform = true
if let maximumSize = maximumSize {
assetImageGenerator.maximumSize = maximumSize
}
do {
// Generate thumbnail from first video image
let image = try assetImageGenerator.copyCGImage(at: .zero, actualTime: nil)
thumbnailImage = UIImage(cgImage: image)
} catch {
MXLog.error(error.localizedDescription)
thumbnailImage = nil
}
return thumbnailImage
}
}