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,97 @@
//
// 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 DTCoreText
public extension DTHTMLElement {
typealias ImageHandler = (_ sourceURL: String, _ width: CGFloat, _ height: CGFloat) -> URL?
/// Sanitize the element using the given parameters.
/// - Parameters:
/// - allowedHTMLTags: An array of tags that are allowed. All other tags will be removed.
/// - font: The default font to use when resetting the content of any unsupported tags.
/// - imageHandler: An optional image handler to be run on `img` tags (if allowed) to update the `src` attribute.
@objc func sanitize(with allowedHTMLTags: [String], bodyFont font: UIFont, imageHandler: ImageHandler?) {
if let name = name, !allowedHTMLTags.contains(name) {
// This is an unsupported tag.
// Remove any attachments to fix rendering.
textAttachment = nil
// If the element has plain text content show that,
// otherwise prevent the tag from displaying.
if let stringContent = attributedString()?.string,
!stringContent.isEmpty,
let element = DTTextHTMLElement(name: nil, attributes: nil) {
element.setText(stringContent)
removeAllChildNodes()
addChildNode(element)
if let parent = parent() {
element.inheritAttributes(from: parent)
} else {
fontDescriptor = DTCoreTextFontDescriptor()
fontDescriptor.fontFamily = font.familyName
fontDescriptor.fontName = font.fontName
fontDescriptor.pointSize = font.pointSize
paragraphStyle = DTCoreTextParagraphStyle.default()
element.inheritAttributes(from: self)
}
element.interpretAttributes()
} else if let parent = parent() {
parent.removeChildNode(self)
} else {
didOutput = true
}
} else {
// Process images with the handler when self is an image tag.
if name == "img", let imageHandler = imageHandler {
process(with: imageHandler)
}
// This element is a supported tag, but it may contain children that aren't,
// so santize all child nodes to ensure correct tags.
if let childNodes = childNodes as? [DTHTMLElement] {
childNodes.forEach { $0.sanitize(with: allowedHTMLTags, bodyFont: font, imageHandler: imageHandler) }
}
}
}
/// Process the element with the supplied image handler.
private func process(with imageHandler: ImageHandler) {
// Get the values required to pass to the image handler
guard let sourceURL = attributes["src"] as? String else { return }
var width: CGFloat = -1
if let widthString = attributes["width"] as? String,
let widthDouble = Double(widthString) {
width = CGFloat(widthDouble)
}
var height: CGFloat = -1
if let heightString = attributes["height"] as? String,
let heightDouble = Double(heightString) {
height = CGFloat(heightDouble)
}
// If the handler returns an updated URL, update the text attachment.
guard let localSourceURL = imageHandler(sourceURL, width, height) else { return }
textAttachment.contentURL = localSourceURL
}
}
@@ -0,0 +1,30 @@
/*
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 "MXKEventFormatter.h"
NS_ASSUME_NONNULL_BEGIN
/**
Define a `MXEvent` category at matrixKit level to store data related to UI handling.
*/
@interface MXAggregatedReactions (MatrixKit)
- (nullable MXAggregatedReactions *)aggregatedReactionsWithSingleEmoji;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,44 @@
/*
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 "MXAggregatedReactions+MatrixKit.h"
#import "MXKTools.h"
@implementation MXAggregatedReactions (MatrixKit)
- (nullable MXAggregatedReactions *)aggregatedReactionsWithSingleEmoji
{
NSMutableArray *reactions = [NSMutableArray arrayWithCapacity:self.reactions.count];
for (MXReactionCount *reactionCount in self.reactions)
{
if ([MXKTools isSingleEmojiString:reactionCount.reaction])
{
[reactions addObject:reactionCount];
}
}
MXAggregatedReactions *aggregatedReactionsWithSingleEmoji;
if (reactions.count)
{
aggregatedReactionsWithSingleEmoji = [MXAggregatedReactions new];
aggregatedReactionsWithSingleEmoji.reactions = reactions;
}
return aggregatedReactionsWithSingleEmoji;
}
@end
@@ -0,0 +1,34 @@
/*
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 "MXKEventFormatter.h"
/**
Define a `MXEvent` category at matrixKit level to store data related to UI handling.
*/
@interface MXEvent (MatrixKit)
/**
The potential error observed when the event formatter tried to stringify the event (MXKEventFormatterErrorNone by default).
*/
@property (nonatomic) MXKEventFormatterError mxkEventFormatterError;
/**
Tell whether the event is highlighted or not (NO by default).
*/
@property (nonatomic) BOOL mxkIsHighlighted;
@end
@@ -0,0 +1,52 @@
/*
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 "MXEvent+MatrixKit.h"
#import <objc/runtime.h>
@implementation MXEvent (MatrixKit)
- (MXKEventFormatterError)mxkEventFormatterError
{
NSNumber *associatedError = objc_getAssociatedObject(self, @selector(mxkEventFormatterError));
if (associatedError)
{
return [associatedError unsignedIntegerValue];
}
return MXKEventFormatterErrorNone;
}
- (void)setMxkEventFormatterError:(MXKEventFormatterError)mxkEventFormatterError
{
objc_setAssociatedObject(self, @selector(mxkEventFormatterError), [NSNumber numberWithUnsignedInteger:mxkEventFormatterError], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)mxkIsHighlighted
{
NSNumber *associatedIsHighlighted = objc_getAssociatedObject(self, @selector(mxkIsHighlighted));
if (associatedIsHighlighted)
{
return [associatedIsHighlighted boolValue];
}
return NO;
}
- (void)setMxkIsHighlighted:(BOOL)mxkIsHighlighted
{
objc_setAssociatedObject(self, @selector(mxkIsHighlighted), [NSNumber numberWithBool:mxkIsHighlighted], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
@@ -0,0 +1,34 @@
/*
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/Foundation.h>
#import <MatrixSDK/MatrixSDK.h>
/**
Temporary category to help in the transition from synchronous access to room.state
to asynchronous access.
*/
@interface MXRoom (Sync)
/**
Get the room state if it has been already loaded else return nil.
Use this method only where you are sure the room state is already mounted.
*/
@property (nonatomic, readonly) MXRoomState *dangerousSyncState;
@end
@@ -0,0 +1,36 @@
/*
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 "MXRoom+Sync.h"
@implementation MXRoom (Sync)
- (MXRoomState *)dangerousSyncState
{
__block MXRoomState *syncState;
// If syncState is called from the right place, the following call will be
// synchronous and every thing will be fine
[self state:^(MXRoomState *roomState) {
syncState = roomState;
}];
NSAssert(syncState, @"[MXRoom+Sync] syncState failed. Are you sure the state of the room has been already loaded?");
return syncState;
}
@end
@@ -0,0 +1,28 @@
//
// 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 <MatrixSDK/MatrixSDK.h>
NS_ASSUME_NONNULL_BEGIN
@interface MXSession (MatrixKit)
/// Flag to indicate whether the session is in a suitable state to show some activity indicators on UI.
@property (nonatomic, readonly) BOOL shouldShowActivityIndicator;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,34 @@
//
// 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 "MXSession+MatrixKit.h"
@implementation MXSession (MatrixKit)
- (BOOL)shouldShowActivityIndicator
{
switch (self.state)
{
case MXSessionStateInitialised:
case MXSessionStateProcessingBackgroundSyncCache:
case MXSessionStateSyncInProgress:
return YES;
default:
return NO;
}
}
@end
@@ -0,0 +1,32 @@
//
// 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
public extension NSAttributedString {
/// Returns a string created by joining all ranges of the attributed string that don't have
/// the `kMXKToolsBlockquoteMarkAttribute` attribute.
@objc func mxk_unquotedString() -> NSString? {
var unquotedSubstrings = [String]()
enumerateAttributes(in: NSRange(location: 0, length: self.length), options: []) { attributes, range, stop in
guard !attributes.keys.contains(where: { $0.rawValue == kMXKToolsBlockquoteMarkAttribute }) else { return }
unquotedSubstrings.append(self.attributedSubstring(from: range).string)
}
return unquotedSubstrings.joined(separator: " ") as NSString
}
}
@@ -0,0 +1,54 @@
/*
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>
@interface NSBundle (MXKLanguage)
/**
Set the application language independently from the device language.
The language can be changed at runtime but the app display must be reloaded.
@param language the ISO language code. nil lets the OS choose it according to the device language
and languages available in the app bundle.
*/
+ (void)mxk_setLanguage:(NSString *)language;
/**
The language set by mxk_setLanguage.
@return the ISO language code of the current language.
*/
+ (NSString *)mxk_language;
/**
Some strings may lack a translation in a language.
Use mxk_setFallbackLanguage to define a fallback language where all the
translation is complete.
@param language the ISO language code.
*/
+ (void)mxk_setFallbackLanguage:(NSString*)language;
/**
The fallback language set by mxk_setFallbackLanguage.
@return the ISO language code of the current fallback language.
*/
+ (NSString *)mxk_fallbackLanguage;
@end
@@ -0,0 +1,103 @@
/*
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 "NSBundle+MXKLanguage.h"
#import <objc/runtime.h>
static const char _bundle = 0;
static const char _fallbackBundle = 0;
static const char _language = 0;
static const char _fallbackLanguage = 0;
@interface MXKLanguageBundle : NSBundle
@end
@implementation MXKLanguageBundle
- (NSString*)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
NSBundle* bundle = objc_getAssociatedObject(self, &_bundle);
// Check if the translation is available in the selected or default language.
// Use "_", a string that does not worth to be translated, as default value to mark
// a key that does not have a translation.
NSString *localizedString = bundle ? [bundle localizedStringForKey:key value:@"_" table:tableName] : [super localizedStringForKey:key value:@"_" table:tableName];
if (!localizedString || (localizedString.length == 1 && [localizedString isEqualToString:@"_"]))
{
// Use the string in the fallback language
NSBundle *fallbackBundle = objc_getAssociatedObject(self, &_fallbackBundle);
localizedString = [fallbackBundle localizedStringForKey:key value:value table:tableName];
}
return localizedString;
}
@end
@implementation NSBundle (MXKLanguage)
+ (void)mxk_setLanguage:(NSString *)language
{
[self setupMXKLanguageBundle];
// [NSBundle localizedStringForKey] calls will be redirected to the bundle corresponding
// to "language"
objc_setAssociatedObject([NSBundle mainBundle],
&_bundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject([NSBundle mainBundle],
&_language, language,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
+ (NSString *)mxk_language
{
return objc_getAssociatedObject([NSBundle mainBundle], &_language);
}
+ (void)mxk_setFallbackLanguage:(NSString *)language
{
[self setupMXKLanguageBundle];
objc_setAssociatedObject([NSBundle mainBundle],
&_fallbackBundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject([NSBundle mainBundle],
&_fallbackLanguage, language,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
+ (NSString *)mxk_fallbackLanguage
{
return objc_getAssociatedObject([NSBundle mainBundle], &_fallbackLanguage);
}
#pragma mark - Private methods
+ (void)setupMXKLanguageBundle
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Use MXKLanguageBundle as the [NSBundle mainBundle] class
object_setClass([NSBundle mainBundle], [MXKLanguageBundle class]);
});
}
@end
@@ -0,0 +1,61 @@
/*
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>
/**
Define a `NSBundle` category at MatrixKit level to retrieve images and sounds from MatrixKit Assets bundle.
*/
@interface NSBundle (MatrixKit)
/**
Retrieve an image from MatrixKit Assets bundle.
@param name image file name without extension.
@return a UIImage instance (nil if the file does not exist).
*/
+ (UIImage *)mxk_imageFromMXKAssetsBundleWithName:(NSString *)name;
/**
Retrieve an audio file url from MatrixKit Assets bundle.
@param name audio file name without extension.
@return a NSURL instance.
*/
+ (NSURL *)mxk_audioURLFromMXKAssetsBundleWithName:(NSString *)name;
/**
Customize the table used to retrieve the localized version of a string during [mxk_localizedStringForKey:] call.
If the key is not defined in this table, the localized string is retrieved from the default table "MatrixKit.strings".
@param tableName the name of the table containing the key-value pairs. Also, the suffix for the strings file (a file with the .strings extension) to store the localized string.
*/
+ (void)mxk_customizeLocalizedStringTableName:(NSString*)tableName;
/**
Retrieve localized string from the customized table. If none, MatrixKit Assets bundle is used.
@param key The string key.
@return The localized string.
*/
+ (NSString *)mxk_localizedStringForKey:(NSString *)key;
/**
An AppExtension-compatible wrapper for bundleForClass.
*/
+ (NSBundle *)mxk_bundleForClass:(Class)aClass;
@end
@@ -0,0 +1,150 @@
/*
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 "NSBundle+MatrixKit.h"
#import "NSBundle+MXKLanguage.h"
#import "MXKViewController.h"
@implementation NSBundle (MatrixKit)
static NSString *customLocalizedStringTableName = nil;
+ (NSBundle*)mxk_assetsBundle
{
// Get the bundle within MatrixKit
NSBundle *bundle = [NSBundle mxk_bundleForClass:[MXKViewController class]];
NSURL *assetsBundleURL = [bundle URLForResource:@"MatrixKitAssets" withExtension:@"bundle"];
return [NSBundle bundleWithURL:assetsBundleURL];
}
+ (NSBundle*)mxk_languageBundle
{
NSString *language = [NSBundle mxk_language];
NSBundle *bundle = [NSBundle mxk_assetsBundle];
// If there is a runtime language (different from the legacy language chose by the OS),
// return the sub bundle for this language
if (language)
{
bundle = [NSBundle bundleWithPath:[bundle pathForResource:[NSBundle mxk_language] ofType:@"lproj"]];
}
return bundle;
}
+ (NSBundle*)mxk_fallbackLanguageBundle
{
NSString *fallbackLanguage = [NSBundle mxk_fallbackLanguage];
NSBundle *bundle = [NSBundle mxk_assetsBundle];
// Return the sub bundle of the fallback language if any
if (fallbackLanguage)
{
bundle = [NSBundle bundleWithPath:[bundle pathForResource:fallbackLanguage ofType:@"lproj"]];
}
return bundle;
}
// use a cache to avoid loading images from file system.
// It often triggers an UI lag.
static MXLRUCache *imagesResourceCache = nil;
+ (UIImage *)mxk_imageFromMXKAssetsBundleWithName:(NSString *)name
{
// use a cache to avoid loading the image at each call
if (!imagesResourceCache)
{
imagesResourceCache = [[MXLRUCache alloc] initWithCapacity:20];
}
NSString *imagePath = [[NSBundle mxk_assetsBundle] pathForResource:name ofType:@"png" inDirectory:@"Images"];
UIImage* image = (UIImage*)[imagesResourceCache get:imagePath];
// the image does not exist
if (!image)
{
// retrieve it
image = [UIImage imageWithContentsOfFile:imagePath];
// and store it in the cache.
[imagesResourceCache put:imagePath object:image];
}
return image;
}
+ (NSURL*)mxk_audioURLFromMXKAssetsBundleWithName:(NSString *)name
{
return [NSURL fileURLWithPath:[[NSBundle mxk_assetsBundle] pathForResource:name ofType:@"mp3" inDirectory:@"Sounds"]];
}
+ (void)mxk_customizeLocalizedStringTableName:(NSString*)tableName
{
customLocalizedStringTableName = tableName;
}
+ (NSString *)mxk_localizedStringForKey:(NSString *)key
{
NSString *localizedString;
// Check first customized table
// Use "_", a string that does not worth to be translated, as default value to mark
// a key that does not have a value in the customized table.
if (customLocalizedStringTableName)
{
localizedString = NSLocalizedStringWithDefaultValue(key, customLocalizedStringTableName, [NSBundle mainBundle], @"_", nil);
}
if (!localizedString || (localizedString.length == 1 && [localizedString isEqualToString:@"_"]))
{
// Check if we need to manage a fallback language
// as we do in NSBundle+MXKLanguage
NSString *language = [NSBundle mxk_language];
NSString *fallbackLanguage = [NSBundle mxk_fallbackLanguage];
BOOL manageFallbackLanguage = fallbackLanguage && ![fallbackLanguage isEqualToString:language];
localizedString = NSLocalizedStringWithDefaultValue(key, @"MatrixKit",
[NSBundle mxk_languageBundle],
manageFallbackLanguage ? @"_" : nil,
nil);
if (manageFallbackLanguage
&& (!localizedString || (localizedString.length == 1 && [localizedString isEqualToString:@"_"])))
{
// The translation is not available, use the fallback language
localizedString = NSLocalizedStringFromTableInBundle(key, @"MatrixKit",
[NSBundle mxk_fallbackLanguageBundle],
nil);
}
}
return localizedString;
}
+ (NSBundle *)mxk_bundleForClass:(Class)aClass
{
NSBundle *bundle = [NSBundle bundleForClass:aClass];
if ([[bundle.bundleURL pathExtension] isEqualToString:@"appex"])
{
// For App extensions, peel off two levels
bundle = [NSBundle bundleWithURL:[[bundle.bundleURL URLByDeletingLastPathComponent] URLByDeletingLastPathComponent]];
}
return bundle;
}
@end
@@ -0,0 +1,66 @@
//
// 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 MatrixSDK.MXLog
public extension NSString {
/// Gets the first URL contained in the string ignoring any links to hosts defined in
/// the `firstURLDetectionIgnoredHosts` property of `MXKAppSettings`.
/// - Returns: A URL if detected, otherwise nil.
@objc func mxk_firstURLDetected() -> NSURL? {
let hosts = MXKAppSettings.standard().firstURLDetectionIgnoredHosts ?? []
return mxk_firstURLDetected(ignoring: hosts)
}
/// Gets the first URL contained in the string ignoring any links to the specified hosts.
/// - Returns: A URL if detected, otherwise nil.
@objc func mxk_firstURLDetected(ignoring ignoredHosts: [String]) -> NSURL? {
guard let linkDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else {
MXLog.debug("[NSString+URLDetector]: Unable to create link detector.")
return nil
}
var detectedURL: NSURL?
// enumerate all urls that were found in the string to ensure
// detection of a valid link if there are invalid links preceding it
linkDetector.enumerateMatches(in: self as String,
options: [],
range: NSRange(location: 0, length: self.length)) { match, flags, stop in
guard let match = match else { return }
// check if the match is a valid url
let urlString = self.substring(with: match.range)
guard let url = NSURL(string: urlString) else { return }
// ensure the match is a web link
guard let scheme = url.scheme?.lowercased(),
scheme == "https" || scheme == "http"
else { return }
// discard any links to ignored hosts
guard let host = url.host?.lowercased(),
!ignoredHosts.contains(host)
else { return }
detectedURL = url
stop.pointee = true
}
return detectedURL
}
}
@@ -0,0 +1,31 @@
/*
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 <UIKit/UIKit.h>
/**
Define a `UIAlertController` category at MatrixKit level to handle accessibility identifiers.
*/
@interface UIAlertController (MatrixKit)
/**
Apply an accessibility on the alert view and its items (actions and text fields).
@param accessibilityIdentifier the identifier.
*/
- (void)mxk_setAccessibilityIdentifier:(NSString *)accessibilityIdentifier;
@end
@@ -0,0 +1,38 @@
/*
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 "UIAlertController+MatrixKit.h"
@implementation UIAlertController (MatrixKit)
- (void)mxk_setAccessibilityIdentifier:(NSString *)accessibilityIdentifier
{
self.view.accessibilityIdentifier = accessibilityIdentifier;
for (UIAlertAction *action in self.actions)
{
action.accessibilityLabel = [NSString stringWithFormat:@"%@Action%@", accessibilityIdentifier, action.title];
}
NSArray *textFieldArray = self.textFields;
for (NSUInteger index = 0; index < textFieldArray.count; index++)
{
UITextField *textField = textFieldArray[index];
textField.accessibilityIdentifier = [NSString stringWithFormat:@"%@TextField%tu", accessibilityIdentifier, index];
}
}
@end
@@ -0,0 +1,33 @@
/*
Copyright 2019 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;
NS_ASSUME_NONNULL_BEGIN
@interface UITextView(MatrixKit)
/**
Determine if there is a link near a location point in UITextView bounds.
@param point The point inside the UITextView bounds
@return YES to indicate that a link has been detected near the location point.
*/
- (BOOL)isThereALinkNearPoint:(CGPoint)point;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,54 @@
/*
Copyright 2019 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 "UITextView+MatrixKit.h"
@implementation UITextView(MatrixKit)
- (BOOL)isThereALinkNearPoint:(CGPoint)point
{
if (!CGRectContainsPoint(self.bounds, point))
{
return NO;
}
UITextPosition *textPosition = [self closestPositionToPoint:point];
if (!textPosition)
{
return NO;
}
UITextRange *textRange = [self.tokenizer rangeEnclosingPosition:textPosition
withGranularity:UITextGranularityCharacter
inDirection:UITextLayoutDirectionLeft];
if (!textRange)
{
return NO;
}
NSInteger startIndex = [self offsetFromPosition:self.beginningOfDocument toPosition:textRange.start];
if (startIndex < 0)
{
return NO;
}
return [self.attributedText attribute:NSLinkAttributeName atIndex:startIndex effectiveRange:NULL] != nil;
}
@end
@@ -0,0 +1,30 @@
/*
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>
NS_ASSUME_NONNULL_BEGIN
@interface UIViewController (MatrixKit)
/**
The main navigation controller if the view controller is embedded inside a split view controller.
*/
@property (nullable, nonatomic, readonly) UINavigationController *mxk_mainNavigationController;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,45 @@
/*
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 "UIViewController+MatrixKit.h"
@implementation UIViewController (MatrixKit)
- (UINavigationController *)mxk_mainNavigationController
{
UINavigationController *mainNavigationController;
if (self.splitViewController)
{
mainNavigationController = self.navigationController;
UIViewController *parentViewController = self.parentViewController;
while (parentViewController)
{
if (parentViewController.navigationController)
{
mainNavigationController = parentViewController.navigationController;
parentViewController = parentViewController.parentViewController;
}
else
{
break;
}
}
}
return mainNavigationController;
}
@end