123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- // _____ _
- // |_ _| |_ _ _ ___ ___ _ __ __ _
- // | | | ' \| '_/ -_) -_) ' \/ _` |_
- // |_| |_||_|_| \___\___|_|_|_\__,_(_)
- //
- // Threema iOS Client
- // Copyright (c) 2014-2020 Threema GmbH
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Affero General Public License, version 3,
- // as published by the Free Software Foundation.
- //
- // 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 Affero General Public License for more details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with this program. If not, see <https://www.gnu.org/licenses/>.
- #import "ChatBallotMessageCell.h"
- #import "BallotMessage.h"
- #import "UserSettings.h"
- #import "Ballot.h"
- #import "RectUtil.h"
- #import "BallotDispatcher.h"
- #import "ModalNavigationController.h"
- #import "UIImage+ColoredImage.h"
- #define ICON_IMAGE @"ActionBallot"
- @implementation ChatBallotMessageCell {
- UILabel *headerLabel;
- UILabel *nameLabel;
- UIImageView *icon;
- }
- + (CGFloat)heightForMessage:(BaseMessage*)message forTableWidth:(CGFloat)tableWidth {
- CGSize sizeConstrains = CGSizeMake([ChatMessageCell maxContentWidthForTableWidth:tableWidth] - 25, CGFLOAT_MAX);
- NSString *header = [ChatBallotMessageCell headerForMessage:message];
- UIFont *headerFont = [ChatBallotMessageCell headerFont];
-
- CGSize headerSize = [header boundingRectWithSize:sizeConstrains options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : headerFont} context:nil].size;
-
- headerSize.height = ceilf(headerSize.height);
- NSString *text = [ChatBallotMessageCell displayTextForMessage:message];
- UIFont *textFont = [ChatMessageCell textFont];
- CGSize size = [text boundingRectWithSize:sizeConstrains options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : textFont} context:nil].size;
-
- size.height = ceilf(size.height);
-
- return MAX(size.height + headerSize.height, 34.0f);
- }
- - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier transparent:(BOOL)transparent
- {
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier transparent:transparent];
- if (self) {
- icon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:ICON_IMAGE]];
- icon.frame = CGRectMake(0.0, 0.0, 20.0, 20.0);
- [self.contentView addSubview:icon];
- headerLabel = [[UILabel alloc] init];
- headerLabel.clearsContextBeforeDrawing = NO;
- headerLabel.backgroundColor = [UIColor clearColor];
- headerLabel.numberOfLines = 1;
- headerLabel.lineBreakMode = NSLineBreakByWordWrapping;
- headerLabel.font = [ChatBallotMessageCell headerFont];
- [self.contentView addSubview:headerLabel];
- nameLabel = [[UILabel alloc] init];
- nameLabel.clearsContextBeforeDrawing = NO;
- nameLabel.backgroundColor = [UIColor clearColor];
- nameLabel.numberOfLines = 0;
- nameLabel.lineBreakMode = NSLineBreakByWordWrapping;
- nameLabel.font = [ChatMessageCell textFont];
- [self.contentView addSubview:nameLabel];
-
- UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(messageTapped:)];
- gestureRecognizer.delegate = self;
- self.msgBackground.userInteractionEnabled = YES;
- [self.msgBackground addGestureRecognizer:gestureRecognizer];
-
- self.accessibilityIdentifier = @"ballot_matrix_cell";
- }
- return self;
- }
- - (void)setupColors {
- [super setupColors];
-
- icon.image = [UIImage imageNamed:ICON_IMAGE inColor:[Colors fontNormal]];
- icon.accessibilityLabel = @"ballot_matrix_image";
- headerLabel.textColor = [Colors fontNormal];
- nameLabel.textColor = [Colors fontNormal];
- }
- - (void)dealloc {
- @try {
- [self.message removeObserver:self forKeyPath:@"ballot.modifyDate"];
- }
- @catch(NSException *e) {}
- }
- - (void)layoutSubviews {
- CGFloat messageTextWidth;
- if (@available(iOS 11.0, *)) {
- messageTextWidth = [ChatMessageCell maxContentWidthForTableWidth:self.safeAreaLayoutGuide.layoutFrame.size.width];
- } else {
- messageTextWidth = [ChatMessageCell maxContentWidthForTableWidth:self.frame.size.width];
- }
- CGSize textSize = [nameLabel.text boundingRectWithSize:CGSizeMake(messageTextWidth - 25, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [ChatMessageCell textFont]} context:nil].size;
- CGSize headerSize = [headerLabel.text boundingRectWithSize:CGSizeMake(messageTextWidth - 25, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [ChatMessageCell textFont]} context:nil].size;
-
- CGFloat width = ceilf(MAX(textSize.width, headerSize.width));
- CGFloat height = ceilf(textSize.height + headerSize.height);
- CGSize size = CGSizeMake(width + 25, MAX(34.0f, height));
- [self setBubbleContentSize:size];
-
- [super layoutSubviews];
-
- CGFloat headerY = 7.0;
-
- CGFloat textY = 7.0 + floorf(headerSize.height);
-
- CGFloat xOffsetText;
- CGFloat xOffsetIcon;
- if (self.message.isOwn.boolValue) {
- xOffsetText = self.contentView.frame.size.width - width - 20;
- xOffsetIcon = self.contentView.frame.size.width - width - 48;
- } else {
- xOffsetText = 46 + self.contentLeftOffset;
- xOffsetIcon = 18 + self.contentLeftOffset;
- }
-
- nameLabel.frame = CGRectMake(xOffsetText, textY, floorf(textSize.width+1), floorf(textSize.height+1));
- headerLabel.frame = CGRectMake(xOffsetText, headerY, floorf(headerSize.width+1), floorf(headerSize.height+1));
-
- icon.frame = [RectUtil setXPositionOf:icon.frame x:xOffsetIcon];
- icon.frame = [RectUtil rect:icon.frame centerVerticalIn:self.contentView.frame];
- }
- - (NSString *)accessibilityLabelForContent {
- return [NSString stringWithFormat:@"%@, %@", [ChatBallotMessageCell headerForMessage:self.message], [ChatBallotMessageCell displayTextForMessage:self.message]];
- }
- - (void)setMessage:(BaseMessage *)newMessage {
- @try {
- [self.message removeObserver:self forKeyPath:@"ballot.modifyDate"];
- }
- @catch(NSException *e) {}
- [super setMessage:newMessage];
- if (!self.chatVc.isOpenWithForceTouch) {
- [self.message addObserver:self forKeyPath:@"ballot.modifyDate" options:0 context:nil];
- }
- [self updateView];
- }
- - (void)updateView {
- if (self.message.isOwn.boolValue) {
- nameLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
- icon.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
- } else {
- nameLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
- icon.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
- }
-
- [self setNeedsLayout];
-
- nameLabel.text = [ChatBallotMessageCell displayTextForMessage:self.message];
- headerLabel.text = [ChatBallotMessageCell headerForMessage:self.message];
- }
- - (void)messageTapped:(id)sender {
- [self.chatVc ballotMessageTapped:(BallotMessage*)self.message];
- }
- - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
- if (action == @selector(copyMessage:) || action == @selector(shareMessage:)) {
- return NO;
- } else if (action == @selector(forwardMessage:)) {
- return NO;
- } else if (action == @selector(speakMessage:)) {
- return YES;
- }
- else {
- return [super canPerformAction:action withSender:sender];
- }
- }
- - (void)copyMessage:(UIMenuController *)menuController {
- }
- - (void)shareMessage:(UIMenuController *)menuController {
- }
- - (void)forwardMessage:(UIMenuController *)menuController {
- }
- - (void)speakMessage:(UIMenuController *)menuController {
- NSString *speakText = [NSString stringWithFormat:@"%@, %@", [ChatBallotMessageCell headerForMessage:self.message], [ChatBallotMessageCell displayTextForMessage:self.message]];;
- AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:speakText];
- AVSpeechSynthesizer *syn = [[AVSpeechSynthesizer alloc] init];
- [syn speakUtterance:utterance];
- }
- - (void)deleteMessage:(UIMenuController*)menuController {
- if (self.message.isOwn.boolValue && !self.message.sent.boolValue && !self.message.sendFailed.boolValue)
- return;
- else
- [super deleteMessage:menuController];
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
- dispatch_async(dispatch_get_main_queue(), ^{
- if (object == self.message) {
- [UIView animateWithDuration:0.5 animations:^{
- [self updateView];
- }];
- }
- });
- }
- - (BOOL)highlightOccurencesOf:(NSString *)pattern {
- NSAttributedString *attributedString = [ChatMessageCell highlightedOccurencesOf:pattern inString:nameLabel.text];
- if (attributedString) {
- nameLabel.attributedText = attributedString;
- return YES;
- }
-
- return NO;
- }
- + (NSString*)displayTextForMessage:(BaseMessage*)message {
- return ((BallotMessage*)message).ballot.title;
- }
- + (NSString*)headerForMessage:(BaseMessage*)message {
- BallotMessage *ballotMessage = (BallotMessage*)message;
-
- NSString *key;
- if (ballotMessage.isClosed) {
- key = @"ballot_closed_cell_title";
- } else {
- key = @"ballot_new_cell_title";
- }
-
- NSString *title = NSLocalizedStringFromTable(key, @"Ballot", nil);
-
- Ballot *ballot = ballotMessage.ballot;
- if (ballot.isClosed) {
- return title;
- } else {
- if (ballot.isIntermediate || ballot.isOwn) {
- NSInteger countParticipants = ballot.participantCount;
- NSInteger countVotes = ballot.numberOfReceivedVotes;
-
- return [NSString stringWithFormat:@"%@ %li/%li", title, (long)countVotes, (long)countParticipants];
- } else {
- return title;
- }
- }
- }
- + (UIFont *)headerFont {
- CGFloat fontSize = roundf([UserSettings sharedUserSettings].chatFontSize * 0.9);
- return [UIFont italicSystemFontOfSize: fontSize];
- }
- - (UIViewController *)previewViewController {
- BallotMessage *ballotMessage = (BallotMessage*)self.message;
-
- UIViewController *viewController = [BallotDispatcher viewControllerForBallot:ballotMessage.ballot];
- ModalNavigationController *modalNav = [[ModalNavigationController alloc] initWithRootViewController:viewController];
- modalNav.showDoneButton = YES;
- return modalNav;
- }
- - (BOOL)performPlayActionForAccessibility {
- [self messageTapped:self];
- return YES;
- }
- @end
|