UI: update chat view UI
Now view used for sending and receiving messages during the call (ChatView)
is the same as for regular ConversationView.
Also this commit fix two problems:
1)remove black imprints of text views, that appeared after window resizing
2)set status "read" for messages arriving during call, so they don't appear
in SmartList as unread.
Change-Id: I6d0cb79878395d28cfc93491a9d4cab42ed89192
Reviewed-by: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
diff --git a/src/MessagesVC.mm b/src/MessagesVC.mm
new file mode 100644
index 0000000..a38ba67
--- /dev/null
+++ b/src/MessagesVC.mm
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2015-2017 Savoir-faire Linux Inc.
+ * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#import <QItemSelectionModel>
+#import <qstring.h>
+#import <QPixmap>
+#import <QtMacExtras/qmacfunctions.h>
+
+#import <media/media.h>
+#import <person.h>
+#import <media/text.h>
+#import <media/textrecording.h>
+#import <globalinstances.h>
+
+#import "MessagesVC.h"
+#import "QNSTreeController.h"
+#import "views/IMTableCellView.h"
+#import "views/MessageBubbleView.h"
+#import "INDSequentialTextSelectionManager.h"
+
+@interface MessagesVC () {
+
+ QNSTreeController* treeController;
+ __unsafe_unretained IBOutlet NSOutlineView* conversationView;
+
+}
+
+@property (nonatomic, strong, readonly) INDSequentialTextSelectionManager* selectionManager;
+
+@end
+
+@implementation MessagesVC
+QAbstractItemModel* currentModel;
+
+-(void)setUpViewWithModel: (QAbstractItemModel*) model {
+
+ _selectionManager = [[INDSequentialTextSelectionManager alloc] init];
+
+ [self.selectionManager unregisterAllTextViews];
+
+ treeController = [[QNSTreeController alloc] initWithQModel:model];
+ [treeController setAvoidsEmptySelection:NO];
+ [treeController setChildrenKeyPath:@"children"];
+ [conversationView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
+ [conversationView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
+ [conversationView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
+ [conversationView scrollToEndOfDocument:nil];
+ currentModel = model;
+}
+
+#pragma mark - NSOutlineViewDelegate methods
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
+{
+ return YES;
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ return YES;
+}
+
+- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
+ if(!qIdx.isValid()) {
+ return [outlineView makeViewWithIdentifier:@"LeftMessageView" owner:self];
+ }
+ auto dir = qvariant_cast<Media::Media::Direction>(qIdx.data((int)Media::TextRecording::Role::Direction));
+ IMTableCellView* result;
+
+ if (dir == Media::Media::Direction::IN) {
+ result = [outlineView makeViewWithIdentifier:@"LeftMessageView" owner:self];
+ } else {
+ result = [outlineView makeViewWithIdentifier:@"RightMessageView" owner:self];
+ }
+
+ // check if the message first in incoming or outgoing messages sequence
+ Boolean isFirstInSequence = true;
+ int row = qIdx.row() - 1;
+ if(row >= 0) {
+ QModelIndex index = currentModel->index(row, 0);
+ if(index.isValid()) {
+ auto dirOld = qvariant_cast<Media::Media::Direction>(index.data((int)Media::TextRecording::Role::Direction));
+ isFirstInSequence = !(dirOld == dir);
+ }
+ }
+ [result.photoView setHidden:!isFirstInSequence];
+ result.msgBackground.needPointer = isFirstInSequence;
+ [result setup];
+
+ NSMutableAttributedString* msgAttString =
+ [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n",qIdx.data((int)Qt::DisplayRole).toString().toNSString()]
+ attributes:[self messageAttributesFor:qIdx]];
+
+ NSAttributedString* timestampAttrString =
+ [[NSAttributedString alloc] initWithString:qIdx.data((int)Media::TextRecording::Role::FormattedDate).toString().toNSString()
+ attributes:[self timestampAttributesFor:qIdx]];
+
+
+ CGFloat finalWidth = MAX(msgAttString.size.width, timestampAttrString.size.width);
+
+ finalWidth = MIN(finalWidth + 30, outlineView.frame.size.width * 0.7);
+
+ NSString* msgString = qIdx.data((int)Qt::DisplayRole).toString().toNSString();
+ NSString* dateString = qIdx.data((int)Qt::DisplayRole).toString().toNSString();
+
+ [msgAttString appendAttributedString:timestampAttrString];
+ [[result.msgView textStorage] appendAttributedString:msgAttString];
+ [result.msgView checkTextInDocument:nil];
+ [result updateWidthConstraint:finalWidth];
+ [result.photoView setImage:QtMac::toNSImage(qvariant_cast<QPixmap>(qIdx.data(Qt::DecorationRole)))];
+ return result;
+}
+
+- (void)outlineView:(NSOutlineView *)outlineView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row
+{
+ if (IMTableCellView* cellView = [outlineView viewAtColumn:0 row:row makeIfNecessary:NO]) {
+ [self.selectionManager registerTextView:cellView.msgView withUniqueIdentifier:@(row).stringValue];
+ }
+ [self.delegate newMessageAdded];
+}
+
+- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
+{
+ QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
+ double someWidth = outlineView.frame.size.width * 0.7;
+
+ NSMutableAttributedString* msgAttString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n",qIdx.data((int)Qt::DisplayRole).toString().toNSString()]
+ attributes:[self messageAttributesFor:qIdx]];
+ NSAttributedString *timestampAttrString = [[NSAttributedString alloc] initWithString:
+ qIdx.data((int)Media::TextRecording::Role::FormattedDate).toString().toNSString()
+ attributes:[self timestampAttributesFor:qIdx]];
+
+ [msgAttString appendAttributedString:timestampAttrString];
+
+ NSRect frame = NSMakeRect(0, 0, someWidth, MAXFLOAT);
+ NSTextView *tv = [[NSTextView alloc] initWithFrame:frame];
+ [tv setEnabledTextCheckingTypes:NSTextCheckingTypeLink];
+ [tv setAutomaticLinkDetectionEnabled:YES];
+ [[tv textStorage] setAttributedString:msgAttString];
+ [tv sizeToFit];
+
+ double height = tv.frame.size.height + 10;
+ return MAX(height, 50.0f);
+}
+
+#pragma mark - Text formatting
+
+- (NSMutableDictionary*) timestampAttributesFor:(QModelIndex) qIdx
+{
+ auto dir = qvariant_cast<Media::Media::Direction>(qIdx.data((int)Media::TextRecording::Role::Direction));
+ NSMutableDictionary* attrs = [NSMutableDictionary dictionary];
+
+ if (dir == Media::Media::Direction::IN) {
+ attrs[NSForegroundColorAttributeName] = [NSColor grayColor];
+ } else {
+ attrs[NSForegroundColorAttributeName] = [NSColor whiteColor];
+ }
+
+ NSFont* systemFont = [NSFont systemFontOfSize:12.0f];
+ attrs[NSFontAttributeName] = systemFont;
+ attrs[NSParagraphStyleAttributeName] = [self paragraphStyle];
+
+ return attrs;
+}
+
+- (NSMutableDictionary*) messageAttributesFor:(QModelIndex) qIdx
+{
+ auto dir = qvariant_cast<Media::Media::Direction>(qIdx.data((int)Media::TextRecording::Role::Direction));
+ NSMutableDictionary* attrs = [NSMutableDictionary dictionary];
+
+ if (dir == Media::Media::Direction::IN) {
+ attrs[NSForegroundColorAttributeName] = [NSColor blackColor];
+ } else {
+ attrs[NSForegroundColorAttributeName] = [NSColor whiteColor];
+ }
+
+ NSFont* systemFont = [NSFont systemFontOfSize:14.0f];
+ attrs[NSFontAttributeName] = systemFont;
+ attrs[NSParagraphStyleAttributeName] = [self paragraphStyle];
+
+ return attrs;
+}
+
+- (NSParagraphStyle*) paragraphStyle
+{
+ /*
+ The only way to instantiate an NSMutableParagraphStyle is to mutably copy an
+ NSParagraphStyle. And since we don't have an existing NSParagraphStyle available
+ to copy, we use the default one.
+
+ The default values supplied by the default NSParagraphStyle are:
+ Alignment NSNaturalTextAlignment
+ Tab stops 12 left-aligned tabs, spaced by 28.0 points
+ Line break mode NSLineBreakByWordWrapping
+ All others 0.0
+ */
+ NSMutableParagraphStyle* aMutableParagraphStyle =
+ [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
+
+ // Now adjust our NSMutableParagraphStyle formatting to be whatever we want.
+ // The numeric values below are in points (72 points per inch)
+ [aMutableParagraphStyle setLineSpacing:1.5];
+ [aMutableParagraphStyle setParagraphSpacing:5.0];
+ [aMutableParagraphStyle setHeadIndent:5.0];
+ [aMutableParagraphStyle setTailIndent:-5.0];
+ [aMutableParagraphStyle setFirstLineHeadIndent:5.0];
+ return aMutableParagraphStyle;
+}
+
+@end