mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-22 01:22:46 +02:00
Merge commit 'aaadcc73674cc8886e363693a7d7c08ac9b4f516' into feature/4260_merge_foss_1_10_2
# Conflicts: # Config/AppVersion.xcconfig # Podfile # Podfile.lock # Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved # Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift # Riot/Modules/Application/LegacyAppDelegate.m # Riot/Modules/Authentication/AuthenticationCoordinator.swift # Riot/Modules/Authentication/Legacy/LegacyAuthenticationCoordinator.swift # Riot/Modules/ContextMenu/ActionProviders/RoomActionProvider.swift # Riot/Modules/Home/AllChats/AllChatsViewController.swift # Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift # Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift # Riot/Modules/Room/Settings/RoomSettingsViewController.m # fastlane/Fastfile
This commit is contained in:
@@ -193,7 +193,7 @@
|
||||
MXPushRule *pushRule = [_mxAccount.mxSession.notificationCenter ruleById:kMXNotificationCenterDisableAllNotificationsRuleID];
|
||||
if (pushRule)
|
||||
{
|
||||
[_mxAccount.mxSession.notificationCenter enableRule:pushRule isEnabled:!areAllDisabled];
|
||||
[_mxAccount.mxSession.notificationCenter enableRule:pushRule isEnabled:!areAllDisabled completion:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,6 +572,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
|
||||
Once complete, this local echo will be replaced by the event saved by the homeserver.
|
||||
|
||||
@param audioFileLocalURL the local filesystem path of the audio file to send.
|
||||
@param additionalContentParams (optional) the additional parameters to the content.
|
||||
@param mimeType (optional) the mime type of the file. Defaults to `audio/ogg`
|
||||
@param duration the length of the voice message in milliseconds
|
||||
@param samples an array of floating point values normalized to [0, 1], boxed within NSNumbers
|
||||
@@ -580,6 +581,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
|
||||
@param failure A block object called when the operation fails.
|
||||
*/
|
||||
- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL
|
||||
additionalContentParams:(NSDictionary*)additionalContentParams
|
||||
mimeType:mimeType
|
||||
duration:(NSUInteger)duration
|
||||
samples:(NSArray<NSNumber *> *)samples
|
||||
|
||||
@@ -1998,6 +1998,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
|
||||
- (void)sendVoiceMessage:(NSURL *)audioFileLocalURL
|
||||
additionalContentParams:(NSDictionary *)additionalContentParams
|
||||
mimeType:mimeType
|
||||
duration:(NSUInteger)duration
|
||||
samples:(NSArray<NSNumber *> *)samples
|
||||
@@ -2006,7 +2007,7 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
{
|
||||
__block MXEvent *localEchoEvent = nil;
|
||||
|
||||
[_room sendVoiceMessage:audioFileLocalURL mimeType:mimeType duration:duration samples:samples threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
|
||||
[_room sendVoiceMessage:audioFileLocalURL additionalContentParams:additionalContentParams mimeType:mimeType duration:duration samples:samples threadId:self.threadId localEcho:&localEchoEvent success:success failure:failure keepActualFilename:YES];
|
||||
|
||||
if (localEchoEvent)
|
||||
{
|
||||
@@ -2149,7 +2150,10 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
else
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendGeneric userInfo:nil]);
|
||||
if (failure)
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendGeneric userInfo:nil]);
|
||||
}
|
||||
MXLogWarning(@"[MXKRoomDataSource][%p] resendEventWithEventId: Warning - Unable to resend room message of type: %@", self, msgType);
|
||||
}
|
||||
}
|
||||
@@ -2176,7 +2180,10 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
NSURL *localFileURL = [NSURL URLWithString:localFilePath];
|
||||
|
||||
if (![NSFileManager.defaultManager fileExistsAtPath:localFilePath]) {
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidLocalFilePath userInfo:nil]);
|
||||
if (failure)
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidLocalFilePath userInfo:nil]);
|
||||
}
|
||||
MXLogWarning(@"[MXKRoomDataSource][%p] resendEventWithEventId: Warning - Unable to resend voice message, invalid file path.", self);
|
||||
return;
|
||||
}
|
||||
@@ -2185,10 +2192,20 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
[self removeEventWithEventId:eventId];
|
||||
|
||||
if (event.isVoiceMessage) {
|
||||
// Voice message
|
||||
NSNumber *duration = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioDuration];
|
||||
NSArray<NSNumber *> *samples = event.content[kMXMessageContentKeyExtensibleAudioMSC1767][kMXMessageContentKeyExtensibleAudioWaveform];
|
||||
|
||||
[self sendVoiceMessage:localFileURL mimeType:mimetype duration:duration.doubleValue samples:samples success:success failure:failure];
|
||||
|
||||
// Additional content params in case it is a voicebroacast chunk
|
||||
NSDictionary* additionalContentParams = nil;
|
||||
if (event.content[kMXEventRelationRelatesToKey] != nil && event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType] != nil) {
|
||||
additionalContentParams = @{
|
||||
kMXEventRelationRelatesToKey: event.content[kMXEventRelationRelatesToKey],
|
||||
VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType: event.content[VoiceBroadcastSettings.voiceBroadcastContentKeyChunkType]
|
||||
};
|
||||
}
|
||||
|
||||
[self sendVoiceMessage:localFileURL additionalContentParams:additionalContentParams mimeType:mimetype duration:duration.doubleValue samples:samples success:success failure:failure];
|
||||
} else {
|
||||
[self sendAudioFile:localFileURL mimeType:mimetype success:success failure:failure];
|
||||
}
|
||||
@@ -2236,7 +2253,10 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
else
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendGeneric userInfo:nil]);
|
||||
if (failure)
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendGeneric userInfo:nil]);
|
||||
}
|
||||
MXLogWarning(@"[MXKRoomDataSource][%p] resendEventWithEventId: Warning - Unable to resend room message of type: %@", self, msgType);
|
||||
}
|
||||
}
|
||||
@@ -2248,13 +2268,19 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
|
||||
}
|
||||
else
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidMessageType userInfo:nil]);
|
||||
if (failure)
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidMessageType userInfo:nil]);
|
||||
}
|
||||
MXLogWarning(@"[MXKRoomDataSource][%p] resendEventWithEventId: Warning - Unable to resend room message of type: %@", self, msgType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidMessageType userInfo:nil]);
|
||||
if (failure)
|
||||
{
|
||||
failure([NSError errorWithDomain:MXKRoomDataSourceErrorDomain code:MXKRoomDataSourceErrorResendInvalidMessageType userInfo:nil]);
|
||||
}
|
||||
MXLogWarning(@"[MXKRoomDataSource][%p] MXKRoomDataSource: Warning - Only resend of MXEventTypeRoomMessage is allowed. Event.type: %@", self, event.type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,34 +18,38 @@ import Foundation
|
||||
|
||||
class MXKSendReplyEventStringLocalizer: NSObject, MXSendReplyEventStringLocalizerProtocol {
|
||||
func senderSentAnImage() -> String {
|
||||
return VectorL10n.messageReplyToSenderSentAnImage
|
||||
VectorL10n.messageReplyToSenderSentAnImage
|
||||
}
|
||||
|
||||
func senderSentAVideo() -> String {
|
||||
return VectorL10n.messageReplyToSenderSentAVideo
|
||||
VectorL10n.messageReplyToSenderSentAVideo
|
||||
}
|
||||
|
||||
func senderSentAnAudioFile() -> String {
|
||||
return VectorL10n.messageReplyToSenderSentAnAudioFile
|
||||
VectorL10n.messageReplyToSenderSentAnAudioFile
|
||||
}
|
||||
|
||||
func senderSentAVoiceMessage() -> String {
|
||||
return VectorL10n.messageReplyToSenderSentAVoiceMessage
|
||||
VectorL10n.messageReplyToSenderSentAVoiceMessage
|
||||
}
|
||||
|
||||
func senderSentAFile() -> String {
|
||||
return VectorL10n.messageReplyToSenderSentAFile
|
||||
VectorL10n.messageReplyToSenderSentAFile
|
||||
}
|
||||
|
||||
func senderSentTheirLocation() -> String {
|
||||
return VectorL10n.messageReplyToSenderSentTheirLocation
|
||||
VectorL10n.messageReplyToSenderSentTheirLocation
|
||||
}
|
||||
|
||||
func senderSentTheirLiveLocation() -> String {
|
||||
return VectorL10n.messageReplyToSenderSentTheirLiveLocation
|
||||
VectorL10n.messageReplyToSenderSentTheirLiveLocation
|
||||
}
|
||||
|
||||
func messageToReplyToPrefix() -> String {
|
||||
return VectorL10n.messageReplyToMessageToReplyToPrefix
|
||||
VectorL10n.messageReplyToMessageToReplyToPrefix
|
||||
}
|
||||
|
||||
func replyToEndedPoll() -> String {
|
||||
VectorL10n.pollTimelineReplyEndedPoll
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,11 @@
|
||||
return (roomSummary.localUnreadEventCount != 0);
|
||||
}
|
||||
|
||||
- (BOOL)isRoomMarkedAsUnread
|
||||
{
|
||||
return [[self mxSession] isRoomMarkedAsUnread:roomSummary.roomId];;
|
||||
}
|
||||
|
||||
- (NSString *)roomIdentifier
|
||||
{
|
||||
if (self.isSuggestedRoom)
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
@property (nonatomic, readonly) NSString *lastEventDate;
|
||||
|
||||
@property (nonatomic, readonly) BOOL hasUnread;
|
||||
@property (nonatomic, readonly) BOOL isRoomMarkedAsUnread;
|
||||
@property (nonatomic, readonly) NSUInteger notificationCount;
|
||||
@property (nonatomic, readonly) NSUInteger highlightCount;
|
||||
@property (nonatomic, readonly) NSString *notificationCountStringValue;
|
||||
|
||||
@@ -366,6 +366,12 @@ typedef enum : NSUInteger {
|
||||
*/
|
||||
@property (nonatomic) UIColor *sendingTextColor;
|
||||
|
||||
/**
|
||||
Color used to display links and hyperlinks contentt.
|
||||
Default is [UIColor linkColor].
|
||||
*/
|
||||
@property (nonatomic) UIColor *linksColor;
|
||||
|
||||
/**
|
||||
Color used to display error text.
|
||||
Default is red.
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#import "GeneratedInterface-Swift.h"
|
||||
|
||||
static NSString *const kHTMLATagRegexPattern = @"<a href=(?:'|\")(.*?)(?:'|\")>([^<]*)</a>";
|
||||
static NSString *const kRepliedTextPattern = @"<mx-reply>.*<blockquote>.*<br>(.*)</blockquote></mx-reply>";
|
||||
|
||||
@interface MXKEventFormatter ()
|
||||
{
|
||||
@@ -89,6 +90,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=(?:'|\")(.*?)(?:'|\")>(
|
||||
_encryptingTextColor = [UIColor lightGrayColor];
|
||||
_sendingTextColor = [UIColor lightGrayColor];
|
||||
_errorTextColor = [UIColor redColor];
|
||||
_linksColor = [UIColor linkColor];
|
||||
_htmlBlockquoteBorderColor = [MXKTools colorWithRGBValue:0xDDDDDD];
|
||||
|
||||
_defaultTextFont = [UIFont systemFontOfSize:14];
|
||||
@@ -1051,8 +1053,22 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=(?:'|\")(.*?)(?:'|\")>(
|
||||
else if ([event.decryptionError.domain isEqualToString:MXDecryptingErrorDomain]
|
||||
&& event.decryptionError.code == MXDecryptingErrorUnknownInboundSessionIdCode)
|
||||
{
|
||||
// Make the unknown inbound session id error description more user friendly
|
||||
errorDescription = [VectorL10n noticeCryptoErrorUnknownInboundSessionId];
|
||||
// Hide the decryption error for VoiceBroadcast chunks
|
||||
BOOL isVoiceBroadcastChunk = NO;
|
||||
if ([event.relatesTo.relationType isEqualToString:MXEventRelationTypeReference]) {
|
||||
MXEvent *startEvent = [mxSession.store eventWithEventId:event.relatesTo.eventId
|
||||
inRoom:event.roomId];
|
||||
|
||||
if (startEvent) {
|
||||
isVoiceBroadcastChunk = (startEvent.eventType == MXEventTypeCustom && [startEvent.type isEqualToString:VoiceBroadcastSettings.voiceBroadcastInfoContentKeyType]);
|
||||
}
|
||||
}
|
||||
if (isVoiceBroadcastChunk) {
|
||||
displayText = nil;
|
||||
} else {
|
||||
// Make the unknown inbound session id error description more user friendly
|
||||
errorDescription = [VectorL10n noticeCryptoErrorUnknownInboundSessionId];
|
||||
}
|
||||
}
|
||||
else if ([event.decryptionError.domain isEqualToString:MXDecryptingErrorDomain]
|
||||
&& event.decryptionError.code == MXDecryptingErrorDuplicateMessageIndexCode)
|
||||
@@ -1749,6 +1765,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=(?:'|\")(.*?)(?:'|\")>(
|
||||
if (url.URL)
|
||||
{
|
||||
[str addAttribute:NSLinkAttributeName value:url.URL range:matchRange];
|
||||
[str addAttribute:NSForegroundColorAttributeName value:self.linksColor range:matchRange];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1806,6 +1823,7 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=(?:'|\")(.*?)(?:'|\")>(
|
||||
}
|
||||
|
||||
html = [self renderReplyTo:html withRoomState:roomState];
|
||||
html = [self renderPollEndedReplyTo:html repliedEvent:repliedEvent];
|
||||
}
|
||||
|
||||
// Apply the css style that corresponds to the event state
|
||||
@@ -1878,6 +1896,12 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=(?:'|\")(.*?)(?:'|\")>(
|
||||
{
|
||||
MXJSONModelSetString(repliedEventContent, repliedEvent.content[kMXMessageBodyKey]);
|
||||
}
|
||||
if (!repliedEventContent && repliedEvent.eventType == MXEventTypePollStart) {
|
||||
repliedEventContent = [MXEventContentPollStart modelFromJSON:repliedEvent.content].question;
|
||||
}
|
||||
if (!repliedEventContent && repliedEvent.eventType == MXEventTypePollEnd) {
|
||||
repliedEventContent = MXSendReplyEventDefaultStringLocalizer.new.replyToEndedPoll;
|
||||
}
|
||||
}
|
||||
|
||||
// No message content in a non-redacted event. Formatter should use fallback.
|
||||
@@ -2012,6 +2036,44 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=(?:'|\")(.*?)(?:'|\")>(
|
||||
return html;
|
||||
}
|
||||
|
||||
- (NSString*)renderPollEndedReplyTo:(NSString*)htmlString repliedEvent:(MXEvent*)repliedEvent {
|
||||
static NSRegularExpression *endedPollRegex;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kRepliedTextPattern options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
});
|
||||
|
||||
NSString* finalString = htmlString;
|
||||
|
||||
if (repliedEvent.eventType != MXEventTypePollEnd) {
|
||||
return finalString;
|
||||
}
|
||||
|
||||
NSTextCheckingResult* match = [endedPollRegex firstMatchInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)];
|
||||
|
||||
if (!(match && match.numberOfRanges > 1)) {
|
||||
// no useful match found
|
||||
return finalString;
|
||||
}
|
||||
|
||||
NSRange groupRange = [match rangeAtIndex:1];
|
||||
NSString* replacementText;
|
||||
|
||||
if (repliedEvent) {
|
||||
MXEvent* pollStartedEvent = [mxSession.store eventWithEventId:repliedEvent.relatesTo.eventId inRoom:repliedEvent.roomId];
|
||||
replacementText = [MXEventContentPollStart modelFromJSON:pollStartedEvent.content].question;
|
||||
}
|
||||
|
||||
if (replacementText == nil) {
|
||||
replacementText = VectorL10n.pollTimelineReplyEndedPoll;
|
||||
}
|
||||
|
||||
finalString = [htmlString stringByReplacingCharactersInRange:groupRange withString:replacementText];
|
||||
|
||||
return finalString;
|
||||
}
|
||||
|
||||
- (void)postFormatMutableAttributedString:(NSMutableAttributedString*)mutableAttributedString
|
||||
forEvent:(MXEvent*)event
|
||||
andRepliedEvent:(MXEvent*)repliedEvent
|
||||
|
||||
@@ -46,6 +46,7 @@ static NSRegularExpression *eventIdRegex;
|
||||
static NSRegularExpression *httpLinksRegex;
|
||||
// A regex to find all HTML tags
|
||||
static NSRegularExpression *htmlTagsRegex;
|
||||
static NSDataDetector *linkDetector;
|
||||
|
||||
@implementation MXKTools
|
||||
|
||||
@@ -60,7 +61,8 @@ static NSRegularExpression *htmlTagsRegex;
|
||||
eventIdRegex = [NSRegularExpression regularExpressionWithPattern:kMXToolsRegexStringForMatrixEventIdentifier options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
|
||||
httpLinksRegex = [NSRegularExpression regularExpressionWithPattern:@"(?i)\\b(https?://\\S*)\\b" options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
htmlTagsRegex = [NSRegularExpression regularExpressionWithPattern:@"<(\\w+)[^>]*>" options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
htmlTagsRegex = [NSRegularExpression regularExpressionWithPattern:@"<(\\w+)[^>]*>" options:NSRegularExpressionCaseInsensitive error:nil];
|
||||
linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1037,6 +1039,23 @@ manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo
|
||||
{
|
||||
[MXKTools createLinksInMutableAttributedString:mutableAttributedString matchingRegex:eventIdRegex];
|
||||
}
|
||||
|
||||
// This allows to check for normal url based links (like https://element.io)
|
||||
// And set back the default link color
|
||||
NSArray *matches = [linkDetector matchesInString: [mutableAttributedString string] options:0 range: NSMakeRange(0,mutableAttributedString.length)];
|
||||
if (matches)
|
||||
{
|
||||
for (NSTextCheckingResult *match in matches)
|
||||
{
|
||||
NSRange matchRange = [match range];
|
||||
NSURL *matchUrl = [match URL];
|
||||
NSURLComponents *url = [[NSURLComponents new] initWithURL:matchUrl resolvingAgainstBaseURL:NO];
|
||||
if (url.URL)
|
||||
{
|
||||
[mutableAttributedString addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.colors.links range:matchRange];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)createLinksInMutableAttributedString:(NSMutableAttributedString*)mutableAttributedString matchingRegex:(NSRegularExpression*)regex
|
||||
@@ -1083,6 +1102,8 @@ manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo
|
||||
// If the match is fully in the link, skip it
|
||||
if (NSIntersectionRange(match.range, linkMatch.range).length == match.range.length)
|
||||
{
|
||||
// but before we set the right color
|
||||
[mutableAttributedString addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.colors.links range:linkMatch.range];
|
||||
hasAlreadyLink = YES;
|
||||
break;
|
||||
}
|
||||
@@ -1097,6 +1118,7 @@ manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo
|
||||
NSString *link = [mutableAttributedString.string substringWithRange:match.range];
|
||||
link = [link stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
||||
[mutableAttributedString addAttribute:NSLinkAttributeName value:link range:match.range];
|
||||
[mutableAttributedString addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.colors.links range:match.range];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
|
||||
- (void)setAttributedText:(NSAttributedString *)attributedText
|
||||
{
|
||||
self.linkTextAttributes = @{};
|
||||
if (@available(iOS 15.0, *)) {
|
||||
[self flushPills];
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
if (sender == _controlButton)
|
||||
{
|
||||
// Swap enable state
|
||||
[_mxSession.notificationCenter enableRule:_mxPushRule isEnabled:!_mxPushRule.enabled];
|
||||
[_mxSession.notificationCenter enableRule:_mxPushRule isEnabled:!_mxPushRule.enabled completion:nil];
|
||||
}
|
||||
else if (sender == _deleteButton)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user