diff --git a/src/ConversationVC.mm b/src/ConversationVC.mm index 7ae6cf501a74d73d38b465328c6aa11fbaa9e150..127a16a75f53e31e70ae65b4b8fb5be13dd03638 100644 --- a/src/ConversationVC.mm +++ b/src/ConversationVC.mm @@ -196,13 +196,7 @@ NSInteger const SEND_PANEL_MAX_HEIGHT = 120; return; // Setup UI elements according to new conversation - NSLog(@"account info, %@", conv->accountId.toNSString()); - NSLog(@"conv info, %@", conv->uid.toNSString()); - NSLog(@"paricipant info, %@", conv->participants[0].toNSString()); NSString* bestName = bestNameForConversation(*conv, *convModel_); - NSLog(@"account info, %@", conv->accountId.toNSString()); - NSLog(@"conv info, %@", conv->uid.toNSString()); - NSLog(@"paricipant info, %@", conv->participants[0].toNSString()); NSString* bestId = bestIDForConversation(*conv, *convModel_); [conversationTitle setStringValue: bestName]; [conversationID setStringValue: bestId]; @@ -218,6 +212,9 @@ NSInteger const SEND_PANEL_MAX_HEIGHT = 120; } catch (std::out_of_range& e) { NSLog(@"contact out of range"); } + if (!conv->allMessagesLoaded) { + convModel_->loadConversationMessages(convUid_, 0); + } } - (void) initFrame diff --git a/src/MessagesVC.mm b/src/MessagesVC.mm index 6a8642e228795188fef80e6ec70d9cff4cb43003..5d4cc0192377ec721aad428ed554077daaf08e4a 100644 --- a/src/MessagesVC.mm +++ b/src/MessagesVC.mm @@ -64,6 +64,7 @@ QString convUid_; lrc::api::ConversationModel* convModel_; const lrc::api::conversation::Info* cachedConv_; + std::vector<std::pair<QString, lrc::api::interaction::Info >> messages; lrc::api::AVModel* avModel; QMetaObject::Connection newInteractionSignal_; @@ -75,6 +76,7 @@ QMetaObject::Connection interactionRemovedSignal_; QMetaObject::Connection peerComposingMsgSignal_; QMetaObject::Connection lastDisplayedChanged_; + QMetaObject::Connection newMessages_; NSString* previewImage; NSMutableDictionary *pendingMessagesToSend; RecordFileVC* recordingController; @@ -181,6 +183,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { cachedConv_ = nil; convUid_ = ""; convModel_ = nil; + messages = {}; QObject::disconnect(modelSortedSignal_); QObject::disconnect(filterChangedSignal_); @@ -188,6 +191,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { QObject::disconnect(newInteractionSignal_); QObject::disconnect(peerComposingMsgSignal_); QObject::disconnect(lastDisplayedChanged_); + QObject::disconnect(newMessages_); [self closeRecordingView]; } @@ -219,31 +223,24 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { } -(void) reloadConversationForMessage:(const QString&) uid updateSize:(BOOL) update { - auto* conv = [self getCurrentConversation]; - if (conv == nil) - return; - auto it = conv->interactions.find(uid); - if (it == conv->interactions.end()) { + auto index = [self indexOfIntercation: uid]; + if (index < 0) { return; } - auto itIndex = distance(conv->interactions.begin(),it); - if (itIndex >= ([conversationView numberOfRows] - 1) || itIndex >= conv->interactions.size()) { - return; - } - NSRange rangeToUpdate = NSMakeRange(itIndex, 2); + auto it = messages.at(index); + NSRange rangeToUpdate = NSMakeRange(index, 2); NSIndexSet* indexSet = [NSIndexSet indexSetWithIndexesInRange:rangeToUpdate]; //reload previous message to update bubbleview - if (itIndex > 0) { + if (index > 0) { auto previousIt = it; - previousIt--; - auto previousInteraction = previousIt->second; + auto previousInteraction = messages.at(index-1).second; if (previousInteraction.type == lrc::api::interaction::Type::TEXT) { - NSRange range = NSMakeRange(itIndex - 1, 3); + NSRange range = NSMakeRange(index - 1, 3); indexSet = [NSIndexSet indexSetWithIndexesInRange:range]; } } if (update) { - NSRange insertRange = NSMakeRange(itIndex, 1); + NSRange insertRange = NSMakeRange(index, 1); NSIndexSet* insertRangeSet = [NSIndexSet indexSetWithIndexesInRange:insertRange]; [conversationView removeRowsAtIndexes:insertRangeSet withAnimation:(NSTableViewAnimationEffectNone)]; [conversationView insertRowsAtIndexes:insertRangeSet withAnimation:(NSTableViewAnimationEffectNone)]; @@ -263,6 +260,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { convModel_ = model; peerComposingMessage = false; composingMessage = false; + [self reloadMessages]; // Signal triggered when messages are received or their status updated QObject::disconnect(newInteractionSignal_); @@ -270,6 +268,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { QObject::disconnect(peerComposingMsgSignal_); QObject::disconnect(lastDisplayedChanged_); QObject::disconnect(interactionRemovedSignal_); + QObject::disconnect(newMessages_); lastDisplayedChanged_ = QObject::connect(convModel_, &lrc::api::ConversationModel::displayedInteractionChanged, @@ -283,6 +282,27 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { [self reloadConversationForMessage:previousUid updateSize: NO]; }); + newMessages_ = + QObject::connect(convModel_, + &lrc::api::ConversationModel::newMessagesAvailable, + [self](const QString &accountId, + const QString &conversationId) { + if (conversationId != convUid_) + return; + cachedConv_ = nil; + [self reloadMessages]; + conversationView.alphaValue = 0.0; + [conversationView reloadData]; + [conversationView scrollToEndOfDocument:nil]; + CABasicAnimation *fadeIn = [CABasicAnimation animationWithKeyPath:@"opacity"]; + fadeIn.fromValue = [NSNumber numberWithFloat:0.0]; + fadeIn.toValue = [NSNumber numberWithFloat:1.0]; + fadeIn.duration = 0.4f; + + [conversationView.layer addAnimation:fadeIn forKey:fadeIn.keyPath]; + conversationView.alphaValue = 1; + }); + peerComposingMsgSignal_ = QObject::connect(convModel_, &lrc::api::ConversationModel::composingStatusChanged, [self](const QString &uid, @@ -322,10 +342,12 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { } }); newInteractionSignal_ = QObject::connect(convModel_, &lrc::api::ConversationModel::newInteraction, - [self](const QString& uid, QString& interactionId, const lrc::api::interaction::Info& interaction){ - if (uid != convUid_) + [self](const QString& uid, QString& interactionId, const lrc::api::interaction::Info& interaction) { + bool transferForOtherDevice = interaction.type == lrc::api::interaction::Type::DATA_TRANSFER && interaction.body.isEmpty() && lrc::api::interaction::isOutgoing(interaction); + if (uid != convUid_ || interaction.type == lrc::api::interaction::Type::MERGE || transferForOtherDevice) return; cachedConv_ = nil; + messages.push_back(std::make_pair(interactionId, interaction)); peerComposingMessage = false; [conversationView noteNumberOfRowsChanged]; [self reloadConversationForMessage:interactionId updateSize: YES]; @@ -335,11 +357,12 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { [self](const QString& uid, const QString& interactionId, const lrc::api::interaction::Info& interaction){ if (uid != convUid_) return; - cachedConv_ = nil; - bool isOutgoing = lrc::api::interaction::isOutgoing(interaction); - if (interaction.type == lrc::api::interaction::Type::TEXT && isOutgoing) { - convModel_->refreshFilter(); + auto index = [self indexOfIntercation: interactionId]; + if (index < 0) { + return; } + cachedConv_ = nil; + messages.at(index).second = interaction; [self reloadConversationForMessage:interactionId updateSize: interaction.type == lrc::api::interaction::Type::DATA_TRANSFER]; [self scrollToBottom]; }); @@ -414,6 +437,26 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { messageView.placeholderAttributedString = attributedPlaceholder; } +-(void)reloadMessages { + auto* conv = [self getCurrentConversation]; + messages = {}; + for (auto& interaction : conv->interactions) { + bool transferForOtherDevice = interaction.second.type == lrc::api::interaction::Type::DATA_TRANSFER && interaction.second.body.isEmpty() && lrc::api::interaction::isOutgoing(interaction.second); + if (interaction.second.type != lrc::api::interaction::Type::MERGE && !transferForOtherDevice) { + messages.push_back(std::make_pair(interaction.first, interaction.second)); + } + } +} + +-(int)indexOfIntercation:(const QString&)uid { + for (int i = 0; i < messages.size(); i++) { + if (messages.at(i).first == uid) { + return i; + } + } + return -1; +} + #pragma mark - configure cells -(NSTableCellView*) makeGenericInteractionViewForTableView:(NSTableView*)tableView withText:(NSString*)text andTime:(NSString*) time @@ -695,10 +738,10 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { return nil; IMTableCellView* result; - auto it = conv->interactions.begin(); + auto it = messages.begin(); auto size = [conversationView numberOfRows] - 1; - if (row > size || row > conv->interactions.size()) { + if (row > size || row > messages.size()) { return [[NSView alloc] init]; } @@ -726,7 +769,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { std::advance(it, row); - if (it == conv->interactions.end()) { + if (it == messages.end()) { return [[NSView alloc] init]; } @@ -841,30 +884,24 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { try { double someWidth = tableView.frame.size.width * 0.7; - auto* conv = [self getCurrentConversation]; - - if (conv == nil) - return HEIGHT_DEFAULT; - auto size = [conversationView numberOfRows] - 1; - if (row > size || row > conv->interactions.size()) { + if (row > size || row > messages.size()) { return HEIGHT_DEFAULT; } if (row == size) { return peerComposingMessage ? HEIGHT_FOR_COMPOSING_INDICATOR : DEFAULT_ROW_HEIGHT; } - auto it = conv->interactions.begin(); + auto it = messages.begin(); std::advance(it, row); - if (it == conv->interactions.end()) { + if (it == messages.end()) { return HEIGHT_DEFAULT; } auto interaction = it->second; - MessageSequencing sequence = [self computeSequencingFor:row]; bool shouldDisplayTime = (sequence == FIRST_WITH_TIME || sequence == SINGLE_WITH_TIME) ? YES : NO; @@ -922,7 +959,7 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { -(NSString *) getDataTransferPath:(const QString&)interactionId { lrc::api::datatransfer::Info info = {}; - convModel_->getTransferInfo(interactionId, info); + convModel_->getTransferInfo(convUid_, interactionId, info); double convertData = static_cast<double>(info.totalSize); return info.path.toNSString(); } @@ -950,15 +987,12 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { -(MessageSequencing) computeSequencingFor:(NSInteger) row { try { - auto* conv = [self getCurrentConversation]; - if (row >= conversationView.numberOfRows - 1 || row >= conv->interactions.size()) { + if (row >= conversationView.numberOfRows - 1 || row >= messages.size()) { return SINGLE_WITHOUT_TIME; } - if (conv == nil) - return SINGLE_WITHOUT_TIME; - auto it = conv->interactions.begin(); + auto it = messages.begin(); std::advance(it, row); - if (it == conv->interactions.end()) { + if (it == messages.end()) { return SINGLE_WITHOUT_TIME; } auto interaction = it->second; @@ -967,12 +1001,12 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { } // first message in comversation if (row == 0) { - if (it == conv->interactions.end() || conv->interactions.size() < 2) { + if (it == messages.end() || messages.size() < 2) { return SINGLE_WITH_TIME; } auto nextIt = it; nextIt++; - if (nextIt == conv->interactions.end()) { + if (nextIt == messages.end()) { return SINGLE_WITH_TIME; } auto nextInteraction = nextIt->second; @@ -982,12 +1016,12 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { return FIRST_WITH_TIME; } // last message in comversation - if (row == conv->interactions.size() - 1) { - if(it == conv->interactions.begin()) { + if (row == messages.size() - 1) { + if(it == messages.begin()) { return SINGLE_WITH_TIME; } auto previousIt = it; - previousIt--; + std::advance(previousIt, -1); auto previousInteraction = previousIt->second; bool timeChanged = [self sequenceTimeChangedFrom:interaction to:previousInteraction]; bool authorChanged = [self sequenceAuthorChangedFrom:interaction to:previousInteraction]; @@ -1000,16 +1034,17 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { return SINGLE_WITH_TIME; } // single message in comversation - if(it == conv->interactions.begin() || it == conv->interactions.end()) { + if(it == messages.begin() || it == messages.end()) { return SINGLE_WITH_TIME; } // message in the middle of conversation auto previousIt = it; - previousIt--; + std::advance(previousIt, -1); + // previousIt--; auto previousInteraction = previousIt->second; auto nextIt = it; nextIt++; - if (nextIt == conv->interactions.end()) { + if (nextIt == messages.end()) { return SINGLE_WITHOUT_TIME; } auto nextInteraction = nextIt->second; @@ -1129,8 +1164,9 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { auto* conv = [self getCurrentConversation]; // return conversation +1 view for composing indicator - if (conv) - return conv->interactions.size() + 1; + if (conv) { + return messages.size() + 1; + } else return 0; } @@ -1171,16 +1207,15 @@ typedef NS_ENUM(NSInteger, MessageSequencing) { - (void)acceptIncomingFile:(id)sender { auto interId = [(IMTableCellView*)[[[[[[sender superview] superview] superview] superview] superview] superview] interaction]; - auto& inter = [self getCurrentConversation]->interactions.find(interId)->second; if (convModel_ && !convUid_.isEmpty()) { convModel_->acceptTransfer(convUid_, interId); } } - (void)declineIncomingFile:(id)sender { - auto inter = [(IMTableCellView*)[[[[[[sender superview] superview] superview] superview] superview] superview] interaction]; + auto interId = [(IMTableCellView*)[[[[[[sender superview] superview] superview] superview] superview] superview] interaction]; if (convModel_ && !convUid_.isEmpty()) { - convModel_->cancelTransfer(convUid_, inter); + convModel_->cancelTransfer(convUid_, interId); } } diff --git a/src/SmartViewVC.mm b/src/SmartViewVC.mm index f3f510d1d11ea803ab48c6780a86eb42fa7848d8..32820daf43a82c5e498a2110d79c392f4427d831 100755 --- a/src/SmartViewVC.mm +++ b/src/SmartViewVC.mm @@ -183,7 +183,6 @@ NSInteger const REQUEST_SEG = 1; [searchResultsView layoutSubtreeIfNeeded]; } - -(void) reloadData { [contactsHeader setHidden: convModel_->allFilteredConversations().get().empty() || searchField.stringValue.length == 0]; @@ -276,6 +275,7 @@ NSInteger const REQUEST_SEG = 1; QObject::disconnect(newInteractionConnection_); QObject::disconnect(searchStatusChangedConnection_); QObject::disconnect(searchResultUpdated_); + convModel_->setFilter(currentFilterType); [self reloadData]; [self reloadSearchResults]; diff --git a/ui/Base.lproj/Conversation.xib b/ui/Base.lproj/Conversation.xib index 5ebe2a2fa3286b8b48a6e0d47badbfbe58f171fc..794d1037caeafabcfbba4f923c17997f0411fa9c 100644 --- a/ui/Base.lproj/Conversation.xib +++ b/ui/Base.lproj/Conversation.xib @@ -10,6 +10,8 @@ <outlet property="addContactButton" destination="pGK-hO-X1Y" id="YeP-Gd-x6e"/> <outlet property="conversationID" destination="SQT-Vf-Lhr" id="eab-vD-7X7"/> <outlet property="conversationTitle" destination="ucx-6g-eJw" id="40T-pM-nix"/> + <outlet property="loadingindicator" destination="jf4-9g-QVb" id="pGV-oY-KTG"/> + <outlet property="loadingindicatorContainer" destination="a2B-6B-Ge1" id="msM-JI-qUj"/> <outlet property="messagesViewVC" destination="iH6-17-JsM" id="uxH-Ra-lSr"/> <outlet property="pluginButton" destination="FvO-Yj-ry0" id="35Y-R2-Gwa"/> <outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/> @@ -947,8 +949,44 @@ <real value="3.4028234663852886e+38"/> </customSpacing> </stackView> - <customView translatesAutoresizingMaskIntoConstraints="NO" id="u1v-eG-gBV" customClass="DraggingDestinationView"> - <rect key="frame" x="0.0" y="0.0" width="838" height="666"/> + <customView hidden="YES" translatesAutoresizingMaskIntoConstraints="NO" id="a2B-6B-Ge1"> + <rect key="frame" x="299" y="251" width="200" height="80"/> + <subviews> + <stackView distribution="fill" orientation="vertical" alignment="centerX" spacing="10" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ux8-7c-iqB"> + <rect key="frame" x="35" y="12" width="130" height="56"/> + <subviews> + <progressIndicator wantsLayer="YES" maxValue="100" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="jf4-9g-QVb"> + <rect key="frame" x="50" y="26" width="30" height="30"/> + <constraints> + <constraint firstAttribute="width" constant="30" id="FtR-se-7Fd"/> + <constraint firstAttribute="height" constant="30" id="cWd-oz-BGI"/> + </constraints> + </progressIndicator> + <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3HL-Cv-WFO"> + <rect key="frame" x="-2" y="0.0" width="134" height="16"/> + <textFieldCell key="cell" lineBreakMode="clipping" title="Loading conversation" id="mfD-q3-nnf"> + <font key="font" usesAppearanceFont="YES"/> + <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + </subviews> + <visibilityPriorities> + <integer value="1000"/> + <integer value="1000"/> + </visibilityPriorities> + <customSpacing> + <real value="3.4028234663852886e+38"/> + <real value="3.4028234663852886e+38"/> + </customSpacing> + </stackView> + </subviews> + <constraints> + <constraint firstAttribute="height" constant="80" id="UyJ-03-RLP"/> + <constraint firstItem="ux8-7c-iqB" firstAttribute="centerX" secondItem="a2B-6B-Ge1" secondAttribute="centerX" id="fIA-5F-V8l"/> + <constraint firstItem="ux8-7c-iqB" firstAttribute="centerY" secondItem="a2B-6B-Ge1" secondAttribute="centerY" id="o1A-cu-d8A"/> + <constraint firstAttribute="width" constant="200" id="yiD-Tf-FpX"/> + </constraints> </customView> </subviews> <constraints>