Signed-off-by: Ivan Sein <ivan@nextcloud.com>
This commit is contained in:
Ivan Sein 2022-04-01 20:52:44 +02:00
Родитель b1671e9a6a
Коммит 894b87355c
13 изменённых файлов: 362 добавлений и 26 удалений

Просмотреть файл

@ -246,6 +246,12 @@
2CC007CA20E125C20096D91F /* NewRoomTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC007C820E125C20096D91F /* NewRoomTableViewController.m */; };
2CC007CB20E125C20096D91F /* NewRoomTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CC007C920E125C20096D91F /* NewRoomTableViewController.xib */; };
2CC007CE20E50B0A0096D91F /* MessageBodyTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC007CD20E50B0A0096D91F /* MessageBodyTextView.m */; };
2CC32E8D27F4540E00BB8C39 /* ReactionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC32E8C27F4540E00BB8C39 /* ReactionsView.swift */; };
2CC32E9227F45AE000BB8C39 /* ReactionsViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC32E9027F45AE000BB8C39 /* ReactionsViewCell.swift */; };
2CC32E9327F45AE000BB8C39 /* ReactionsViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CC32E9127F45AE000BB8C39 /* ReactionsViewCell.xib */; };
2CC32E9827F5D9BD00BB8C39 /* NCChatReaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC32E9727F5D9BD00BB8C39 /* NCChatReaction.m */; };
2CC32E9927F5DADA00BB8C39 /* NCChatReaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC32E9727F5D9BD00BB8C39 /* NCChatReaction.m */; };
2CC32E9A27F5DADB00BB8C39 /* NCChatReaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC32E9727F5D9BD00BB8C39 /* NCChatReaction.m */; };
2CC5F0982716FF1900DE1775 /* NCCommunication in Frameworks */ = {isa = PBXBuildFile; productRef = 2CC5F0972716FF1900DE1775 /* NCCommunication */; };
2CC5F09A2717028B00DE1775 /* NCCommunication in Frameworks */ = {isa = PBXBuildFile; productRef = 2CC5F0992717028B00DE1775 /* NCCommunication */; };
2CC5F09C2717198500DE1775 /* NCCommunication in Frameworks */ = {isa = PBXBuildFile; productRef = 2CC5F09B2717198500DE1775 /* NCCommunication */; };
@ -714,6 +720,11 @@
2CC007C920E125C20096D91F /* NewRoomTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NewRoomTableViewController.xib; sourceTree = "<group>"; };
2CC007CC20E50B0A0096D91F /* MessageBodyTextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageBodyTextView.h; sourceTree = "<group>"; };
2CC007CD20E50B0A0096D91F /* MessageBodyTextView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MessageBodyTextView.m; sourceTree = "<group>"; };
2CC32E8C27F4540E00BB8C39 /* ReactionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsView.swift; sourceTree = "<group>"; };
2CC32E9027F45AE000BB8C39 /* ReactionsViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionsViewCell.swift; sourceTree = "<group>"; };
2CC32E9127F45AE000BB8C39 /* ReactionsViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReactionsViewCell.xib; sourceTree = "<group>"; };
2CC32E9627F5D9BD00BB8C39 /* NCChatReaction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NCChatReaction.h; sourceTree = "<group>"; };
2CC32E9727F5D9BD00BB8C39 /* NCChatReaction.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NCChatReaction.m; sourceTree = "<group>"; };
2CC7158820B837140045C789 /* PlaceholderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PlaceholderView.xib; sourceTree = "<group>"; };
2CC7158A20B8394A0045C789 /* PlaceholderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlaceholderView.h; sourceTree = "<group>"; };
2CC7158B20B8394A0045C789 /* PlaceholderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlaceholderView.m; sourceTree = "<group>"; };
@ -1177,6 +1188,9 @@
2CA52AC92670D02800619610 /* VoiceMessageRecordingView.h */,
2CA52ACA2670D02800619610 /* VoiceMessageRecordingView.m */,
2CA52ACC2670D07900619610 /* VoiceMessageRecordingView.xib */,
2CC32E8C27F4540E00BB8C39 /* ReactionsView.swift */,
2CC32E9027F45AE000BB8C39 /* ReactionsViewCell.swift */,
2CC32E9127F45AE000BB8C39 /* ReactionsViewCell.xib */,
);
name = "Chat views";
sourceTree = "<group>";
@ -1413,6 +1427,8 @@
2C6DEAB3243CCCCA00AE8437 /* Chat views */,
2CA1553F208E350300CE8EF0 /* NCChatMessage.h */,
2CA15540208E350300CE8EF0 /* NCChatMessage.m */,
2CC32E9627F5D9BD00BB8C39 /* NCChatReaction.h */,
2CC32E9727F5D9BD00BB8C39 /* NCChatReaction.m */,
2C42ADB220B58E6300296DEA /* NCChatController.h */,
2C42ADB320B58E6300296DEA /* NCChatController.m */,
1FEDE3C5257D439500853F79 /* NCChatFileController.h */,
@ -1610,6 +1626,7 @@
buildActionMask = 2147483647;
files = (
2CC007BE20D8F24B0096D91F /* RoomCreation2TableViewController.xib in Resources */,
2CC32E9327F45AE000BB8C39 /* ReactionsViewCell.xib in Resources */,
2C330372255E6EBC00BDB4E4 /* InfoPlist.strings in Resources */,
2C78EFA11F828C41008AFA74 /* CallViewController.xib in Resources */,
2C3780C5210F4A26003F9AE8 /* HeaderWithButton.xib in Resources */,
@ -1838,6 +1855,7 @@
2C78EF9C1F826B22008AFA74 /* NCCallController.m in Sources */,
2C4D7D761F30F7B600FF4A0D /* ARDUtilities.m in Sources */,
2CB6ACE92641954700D3D641 /* MapViewController.m in Sources */,
2CC32E9227F45AE000BB8C39 /* ReactionsViewCell.swift in Sources */,
2CBF82AE1FC888FC00636459 /* NCPushNotification.m in Sources */,
2CC7159420C54D080045C789 /* ChatTableViewCell.m in Sources */,
2CA1CCAA1F02D1A4002FE6A2 /* NCAPIController.m in Sources */,
@ -1867,6 +1885,7 @@
2C4446F0265D454200DF1DBC /* NotificationCenterNotifications.m in Sources */,
1F3D3B22255F109E00230DAE /* BarButtonItemWithActivity.m in Sources */,
2C0574821EDD9E8E00D9E7F2 /* main.m in Sources */,
2CC32E9827F5D9BD00BB8C39 /* NCChatReaction.m in Sources */,
2C40281522832EED0000DDFC /* NCDatabaseManager.m in Sources */,
2CC007B820D8139D0096D91F /* RoomCreationTableViewController.m in Sources */,
DA7558132790D65700A48A1B /* AccountTableViewCell.swift in Sources */,
@ -1924,6 +1943,7 @@
2C1ABDCE257E939600AEDFB6 /* NCContact.m in Sources */,
2C7A12422017872600864818 /* AddParticipantsTableViewController.m in Sources */,
2C43BA7621309A1000B3068A /* NCMessageParameter.m in Sources */,
2CC32E8D27F4540E00BB8C39 /* ReactionsView.swift in Sources */,
2C4DE9F221F732B40096940D /* NCAudioController.m in Sources */,
2C8A2BC9221F094F00DE6D2C /* DirectoryTableViewController.m in Sources */,
2C42ADB420B58E6300296DEA /* NCChatController.m in Sources */,
@ -1986,6 +2006,7 @@
2C62AFB924C1A4E6007E460A /* ShareViewController.m in Sources */,
2C4446DF2658158000DF1DBC /* NCChatBlock.m in Sources */,
2C62B00924C1BDBD007E460A /* NCAPISessionManager.m in Sources */,
2CC32E9A27F5DADB00BB8C39 /* NCChatReaction.m in Sources */,
2C62AFBB24C1B7B1007E460A /* NCDatabaseManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -2024,6 +2045,7 @@
2C444704265D641300DF1DBC /* NCUserDefaults.m in Sources */,
2CC001B724A37A9A00A20167 /* NCUser.m in Sources */,
2CC0016124A25B5500A20167 /* NCAPIController.m in Sources */,
2CC32E9927F5DADA00BB8C39 /* NCChatReaction.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

Просмотреть файл

@ -27,14 +27,20 @@
#import "UIImageView+AFNetworking.h"
#import "UIImageView+Letters.h"
#import "NextcloudTalk-Swift.h"
#import "NCAPIController.h"
#import "NCAppBranding.h"
#import "NCChatMessage.h"
#import "NCDatabaseManager.h"
#import "NCUtils.h"
#import "QuotedMessageView.h"
@interface ChatMessageTableViewCell ()
@property (nonatomic, strong) UIView *quoteContainerView;
@property (nonatomic, strong) ReactionsView *reactionsView;
@property (nonatomic, strong) NSArray<NSLayoutConstraint *> *vConstraint1;
@property (nonatomic, strong) NSArray<NSLayoutConstraint *> *vConstraint2;
@end
@implementation ChatMessageTableViewCell
@ -83,6 +89,8 @@
[self.quoteContainerView addGestureRecognizer:quoteTap];
}
[self.contentView addSubview:self.reactionsView];
NSDictionary *views = @{@"avatarView": self.avatarView,
@"userStatusImageView": self.userStatusImageView,
@"statusView": self.statusView,
@ -90,7 +98,8 @@
@"dateLabel": self.dateLabel,
@"bodyTextView": self.bodyTextView,
@"quoteContainerView": self.quoteContainerView,
@"quotedMessageView": self.quotedMessageView
@"quotedMessageView": self.quotedMessageView,
@"reactionsView": self.reactionsView
};
NSDictionary *metrics = @{@"avatarSize": @(kChatCellAvatarHeight),
@ -104,9 +113,12 @@
if ([self.reuseIdentifier isEqualToString:ChatMessageCellIdentifier]) {
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-right-[avatarView(avatarSize)]-right-[titleLabel]-[dateLabel(dateLabelWidth)]-right-|" options:0 metrics:metrics views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-right-[avatarView(avatarSize)]-right-[bodyTextView(>=0)]-right-|" options:0 metrics:metrics views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-right-[avatarView(avatarSize)]-right-[reactionsView(>=0)]-right-|" options:0 metrics:metrics views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-padding-[statusView(statusSize)]-padding-[bodyTextView(>=0)]-right-|" options:0 metrics:metrics views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-right-[titleLabel(avatarSize)]-left-[bodyTextView(>=0@999)]-left-|" options:0 metrics:metrics views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-right-[dateLabel(avatarSize)]-left-[bodyTextView(>=0@999)]-left-|" options:0 metrics:metrics views:views]];
_vConstraint1 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-right-[titleLabel(avatarSize)]-left-[bodyTextView(>=0@999)]-0-[reactionsView(0)]-left-|" options:0 metrics:metrics views:views];
[self.contentView addConstraints:_vConstraint1];
_vConstraint2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-right-[dateLabel(avatarSize)]-left-[bodyTextView(>=0@999)]-0-[reactionsView(0)]-left-|" options:0 metrics:metrics views:views];
[self.contentView addConstraints:_vConstraint2];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-right-[titleLabel(avatarSize)]-left-[statusView(statusSize)]-(>=0)-|" options:0 metrics:metrics views:views]];
} else if ([self.reuseIdentifier isEqualToString:ReplyMessageCellIdentifier]) {
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-right-[avatarView(avatarSize)]-right-[titleLabel]-[dateLabel(dateLabelWidth)]-right-|" options:0 metrics:metrics views:views]];
@ -151,6 +163,10 @@
self.quotedMessageView.actorLabel.text = @"";
self.quotedMessageView.messageLabel.text = @"";
self.reactionsView.reactions = @[];
_vConstraint1[5].constant = 0;
_vConstraint2[5].constant = 0;
[self.avatarView cancelImageDownloadTask];
self.avatarView.image = nil;
self.avatarView.contentMode = UIViewContentModeScaleToFill;
@ -219,6 +235,17 @@
return _dateLabel;
}
- (ReactionsView *)reactionsView
{
if (!_reactionsView) {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_reactionsView = [[ReactionsView alloc] initWithFrame:CGRectMake(0, 0, 50, 50) collectionViewLayout:flowLayout];
_reactionsView.translatesAutoresizingMaskIntoConstraints = NO;
}
return _reactionsView;
}
- (UIView *)quoteContainerView
{
if (!_quoteContainerView) {
@ -270,10 +297,12 @@
[self setBotAvatar];
}
} else {
[self.avatarView setImageWithURLRequest:[[NCAPIController sharedInstance] createAvatarRequestForUser:message.actorId
andSize:96
usingAccount:activeAccount]
placeholderImage:nil success:nil failure:nil];
[self.avatarView
setImageWithURLRequest:[[NCAPIController sharedInstance]
createAvatarRequestForUser:message.actorId
andSize:96
usingAccount:activeAccount]
placeholderImage:nil success:nil failure:nil];
}
// This check is just a workaround to fix the issue with the deleted parents returned by the API.
@ -305,6 +334,13 @@
self.bodyTextView.textColor = [UIColor tertiaryLabelColor];
}
}
const NSArray *reactions = message.reactionsArray;
[self.reactionsView updateReactionsWithReactions:reactions];
if (reactions.count > 0) {
_vConstraint1[5].constant = 40;
_vConstraint2[5].constant = 40;
}
}
- (void)setGuestAvatar:(NSString *)displayName

Просмотреть файл

@ -21,6 +21,9 @@
*/
#import <UIKit/UIKit.h>
#import "NextcloudTalk-Swift.h"
#import "ChatTableViewCell.h"
#import "NCChatMessage.h"
#import "MessageBodyTextView.h"
@ -32,6 +35,8 @@ static NSString *GroupedChatMessageCellIdentifier = @"GroupedChatMessageCellIden
@property (nonatomic, strong) MessageBodyTextView *bodyTextView;
@property (nonatomic, strong) UIView *statusView;
@property (nonatomic, strong) ReactionsView *reactionsView;
@property (nonatomic, strong) NSArray<NSLayoutConstraint *> *vConstraint;
+ (CGFloat)defaultFontSize;
- (void)setupForMessage:(NCChatMessage *)message withLastCommonReadMessage:(NSInteger)lastCommonRead;

Просмотреть файл

@ -47,9 +47,11 @@
_statusView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kChatCellStatusViewHeight, kChatCellStatusViewHeight)];
_statusView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:_statusView];
[self.contentView addSubview:self.reactionsView];
NSDictionary *views = @{@"bodyTextView": self.bodyTextView,
@"statusView": self.statusView
@"statusView": self.statusView,
@"reactionsView": self.reactionsView
};
NSDictionary *metrics = @{@"avatar": @50,
@ -61,7 +63,9 @@
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-avatar-[bodyTextView(>=0)]-right-|" options:0 metrics:metrics views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-padding-[statusView(statusSize)]-padding-[bodyTextView(>=0)]-right-|" options:0 metrics:metrics views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-left-[bodyTextView(>=0@999)]-left-|" options:0 metrics:metrics views:views]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-padding-[statusView(statusSize)]-padding-[reactionsView(>=0)]-right-|" options:0 metrics:metrics views:views]];
_vConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-left-[bodyTextView(>=0@999)]-0-[reactionsView(0)]-left-|" options:0 metrics:metrics views:views];
[self.contentView addConstraints:_vConstraint];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-left-[statusView(statusSize)]-(>=0)-|" options:0 metrics:metrics views:views]];
}
@ -75,6 +79,9 @@
self.bodyTextView.text = @"";
self.reactionsView.reactions = @[];
_vConstraint[3].constant = 0;
self.statusView.hidden = NO;
[self.statusView.subviews makeObjectsPerformSelector: @selector(removeFromSuperview)];
}
@ -111,6 +118,11 @@
self.bodyTextView.textColor = [UIColor tertiaryLabelColor];
}
}
const NSArray *reactions = message.reactionsArray;
[self.reactionsView updateReactionsWithReactions:reactions];
if (reactions.count > 0) {
_vConstraint[3].constant = 40;
}
}
- (void)setDeliveryState:(ChatMessageDeliveryState)state
@ -153,6 +165,17 @@
return _bodyTextView;
}
- (ReactionsView *)reactionsView
{
if (!_reactionsView) {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_reactionsView = [[ReactionsView alloc] initWithFrame:CGRectMake(0, 0, 50, 50) collectionViewLayout:flowLayout];
_reactionsView.translatesAutoresizingMaskIntoConstraints = NO;
}
return _reactionsView;
}
+ (CGFloat)defaultFontSize
{
CGFloat pointSize = 16.0;

Просмотреть файл

@ -376,7 +376,7 @@ NSString * const NCChatControllerDidReceiveCallEndedMessageNotification
userInfo:userInfo];
}
// Notify if "deleted messages" have been received
if ([message.systemMessage isEqualToString:@"message_deleted"] || [message.systemMessage isEqualToString:@"reaction"]) {
if ([message.systemMessage isEqualToString:@"message_deleted"] || [message.systemMessage isEqualToString:@"reaction"] || [message.systemMessage isEqualToString:@"reaction_revoked"]) {
[userInfo setObject:message forKey:@"updateMessage"];
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveUpdateMessageNotification
object:self
@ -624,8 +624,10 @@ NSString * const NCChatControllerDidReceiveCallEndedMessageNotification
object:self
userInfo:userInfo];
}
// Notify if "deleted messages" have been received
if ([message.systemMessage isEqualToString:@"message_deleted"] || [message.systemMessage isEqualToString:@"reaction"]) {
// Notify if an "update messages" have been received
if ([message.systemMessage isEqualToString:@"message_deleted"] ||
[message.systemMessage isEqualToString:@"reaction"] ||
[message.systemMessage isEqualToString:@"reaction_revoked"]) {
[userInfo setObject:message forKey:@"updateMessage"];
[[NSNotificationCenter defaultCenter] postNotificationName:NCChatControllerDidReceiveUpdateMessageNotification
object:self

Просмотреть файл

@ -23,6 +23,7 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <Realm/Realm.h>
#import "NCChatReaction.h"
#import "NCDatabaseManager.h"
#import "NCMessageParameter.h"
#import "NCMessageFileParameter.h"
@ -37,11 +38,6 @@ extern NSString * const kMessageTypeSystem;
extern NSString * const kMessageTypeCommand;
extern NSString * const kMessageTypeVoiceMessage;
@interface NCChatReaction : RLMObject
@property (nonatomic, strong) NSString *reaction;
@property (nonatomic, assign) NSInteger count;
@end
RLM_ARRAY_TYPE(NCChatReaction)
@interface NCChatMessage : RLMObject <NSCopying>
@ -81,5 +77,6 @@ RLM_ARRAY_TYPE(NCChatReaction)
- (NSMutableAttributedString *)parsedMessage;
- (NSMutableAttributedString *)systemMessageFormat;
- (NCChatMessage *)parent;
- (NSArray *)reactionsArray;
@end

Просмотреть файл

@ -41,9 +41,6 @@ NSString * const kMessageTypeVoiceMessage = @"voice-message";
@end
@implementation NCChatReaction
@end
@implementation NCChatMessage
+ (instancetype)messageWithDictionary:(NSDictionary *)messageDict
@ -93,9 +90,7 @@ NSString * const kMessageTypeVoiceMessage = @"voice-message";
NSDictionary *reactionsDict = reactions;
NSMutableArray *reactionsArray = [NSMutableArray new];
for (NSString *reactionKey in reactionsDict.allKeys) {
NCChatReaction *reaction = [[NCChatReaction alloc] init];
reaction.reaction = reactionKey;
reaction.count = [[reactionsDict objectForKey:reactionKey] integerValue];
NCChatReaction *reaction = [NCChatReaction initWithReaction:reactionKey andCount:[[reactionsDict objectForKey:reactionKey] integerValue]];
[reactionsArray addObject:reaction];
}
message.reactions = (RLMArray<NCChatReaction *><NCChatReaction> *)reactionsArray;
@ -374,4 +369,13 @@ NSString * const kMessageTypeVoiceMessage = @"voice-message";
return nil;
}
- (NSArray *)reactionsArray
{
NSMutableArray *reactions = [NSMutableArray new];
for (NCChatReaction *reaction in _reactions) {
[reactions addObject:reaction];
}
return reactions;
}
@end

Просмотреть файл

@ -0,0 +1,34 @@
/**
* @copyright Copyright (c) 2022 Ivan Sein <ivan@nextcloud.com>
*
* @author Ivan Sein <ivan@nextcloud.com>
*
* @license GNU GPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#import <Realm/Realm.h>
@interface NCChatReaction : RLMObject
@property (nonatomic, strong) NSString *reaction;
@property (nonatomic, assign) NSInteger count;
+ (instancetype)initWithReaction:(NSString *)reaction andCount:(NSInteger)count;
@end

Просмотреть файл

@ -0,0 +1,35 @@
/**
* @copyright Copyright (c) 2022 Ivan Sein <ivan@nextcloud.com>
*
* @author Ivan Sein <ivan@nextcloud.com>
*
* @license GNU GPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#import "NCChatReaction.h"
@implementation NCChatReaction
+ (instancetype)initWithReaction:(NSString *)reaction andCount:(NSInteger)count
{
NCChatReaction *reactionObject = [[NCChatReaction alloc] init];
reactionObject.reaction = reaction;
reactionObject.count = count;
return reactionObject;
}
@end

Просмотреть файл

@ -3041,7 +3041,9 @@ NSString * const NCChatViewControllerTalkToUserNotification = @"NCChatViewContro
return separatorCell;
}
if (message.isSystemMessage) {
if ([message.systemMessage isEqualToString:@"message_deleted"] || [message.systemMessage isEqualToString:@"reaction"]) {
if ([message.systemMessage isEqualToString:@"message_deleted"] ||
[message.systemMessage isEqualToString:@"reaction"] ||
[message.systemMessage isEqualToString:@"reaction_revoked"]) {
return (SystemMessageTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:InvisibleSystemMessageCellIdentifier];
}
SystemMessageTableViewCell *systemCell = (SystemMessageTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:SystemMessageCellIdentifier];
@ -3129,8 +3131,11 @@ NSString * const NCChatViewControllerTalkToUserNotification = @"NCChatViewContro
return kMessageSeparatorCellHeight;
}
// Message deleted (the ones that notify about a deleted message, they should not be displayed)
if (message.message.length == 0 || [message.systemMessage isEqualToString:@"message_deleted"] || [message.systemMessage isEqualToString:@"reaction"]) {
// Update messages (the ones that notify about an update in one message, they should not be displayed)
if (message.message.length == 0 ||
[message.systemMessage isEqualToString:@"message_deleted"] ||
[message.systemMessage isEqualToString:@"reaction"] ||
[message.systemMessage isEqualToString:@"reaction_revoked"]) {
return 0.0;
}
@ -3146,6 +3151,10 @@ NSString * const NCChatViewControllerTalkToUserNotification = @"NCChatViewContro
height = kChatMessageCellMinimumHeight;
}
if (message.reactionsArray.count > 0) {
height += 40; // reactionsView(40)
}
if (message.parent) {
height += 55; // left(5) + quoteView(50)
return height;
@ -3157,6 +3166,10 @@ NSString * const NCChatViewControllerTalkToUserNotification = @"NCChatViewContro
if (height < kGroupedChatMessageCellMinimumHeight) {
height = kGroupedChatMessageCellMinimumHeight;
}
if (message.reactionsArray.count > 0) {
height += 40; // reactionsView(40)
}
}
// Voice message should be before message.file check since it contains a file

Просмотреть файл

@ -0,0 +1,81 @@
/**
* @copyright Copyright (c) 2022 Ivan Sein <ivan@nextcloud.com>
*
* @author Ivan Sein <ivan@nextcloud.com>
*
* @license GNU GPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import UIKit
@objcMembers class ReactionsView: UICollectionView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var reactions: [NCChatReaction] = []
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.dataSource = self
self.delegate = self
}
required override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
self.dataSource = self
self.delegate = self
self.register(UINib(nibName: "ReactionsViewCell", bundle: .main), forCellWithReuseIdentifier: "ReactionCellIdentifier")
self.backgroundColor = .clear
self.showsHorizontalScrollIndicator = false
}
func updateReactions(reactions: [NCChatReaction]) {
self.reactions = reactions
self.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return reactions.count
}
func collectionView(_ collectionView: UICollectionView, numberOfSections section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 2
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 50, height: 30)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ReactionCellIdentifier", for: indexPath) as? ReactionsViewCell
if indexPath.row < reactions.count {
cell?.setReaction(reaction: reactions[indexPath.row])
}
return cell ?? UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// TODO: Set reaction
}
func neededHeight() -> CGFloat {
return self.collectionViewLayout.collectionViewContentSize.height
}
}

Просмотреть файл

@ -0,0 +1,47 @@
/**
* @copyright Copyright (c) 2022 Ivan Sein <ivan@nextcloud.com>
*
* @author Ivan Sein <ivan@nextcloud.com>
*
* @license GNU GPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import UIKit
@objcMembers class ReactionsViewCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
label.layer.borderWidth = 1.0
label.layer.borderColor = NCAppBranding.elementColor().cgColor
label.layer.cornerRadius = 15.0
label.clipsToBounds = true
label.backgroundColor = NCAppBranding.backgroundColor()
}
override func prepareForReuse() {
super.prepareForReuse()
label.text = ""
}
func setReaction(reaction: NCChatReaction) {
label.text = reaction.reaction + " " + String(reaction.count)
}
}

Просмотреть файл

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="ReactionsViewCell" customModule="NextcloudTalk" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="50" height="30"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="50" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="👍999" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1w7-iO-0oY">
<rect key="frame" x="0.0" y="0.0" width="50" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</view>
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
<size key="customSize" width="66" height="50"/>
<connections>
<outlet property="label" destination="1w7-iO-0oY" id="QBG-3F-rJ4"/>
</connections>
<point key="canvasLocation" x="149.27536231884059" y="71.651785714285708"/>
</collectionViewCell>
</objects>
</document>