mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Sketch out "typing indicators" interaction and cell.
This commit is contained in:
parent
50381cc94c
commit
eedc9f9a26
9 changed files with 211 additions and 1 deletions
|
@ -217,6 +217,8 @@
|
||||||
34B3F8851E8DF1700035BE1A /* NewGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8551E8DF1700035BE1A /* NewGroupViewController.m */; };
|
34B3F8851E8DF1700035BE1A /* NewGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8551E8DF1700035BE1A /* NewGroupViewController.m */; };
|
||||||
34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */; };
|
34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */; };
|
||||||
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */; };
|
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */; };
|
||||||
|
34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */; };
|
||||||
|
34B6A907218B5241007C4606 /* TypingIndicatorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */; };
|
||||||
34B6D27420F664C900765BE2 /* OWSUnreadIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 34B6D27220F664C800765BE2 /* OWSUnreadIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
34B6D27420F664C900765BE2 /* OWSUnreadIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 34B6D27220F664C800765BE2 /* OWSUnreadIndicator.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
34B6D27520F664C900765BE2 /* OWSUnreadIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B6D27320F664C800765BE2 /* OWSUnreadIndicator.m */; };
|
34B6D27520F664C900765BE2 /* OWSUnreadIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B6D27320F664C800765BE2 /* OWSUnreadIndicator.m */; };
|
||||||
34BECE2B1F74C12700D7438D /* DebugUIStress.m in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2A1F74C12700D7438D /* DebugUIStress.m */; };
|
34BECE2B1F74C12700D7438D /* DebugUIStress.m in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2A1F74C12700D7438D /* DebugUIStress.m */; };
|
||||||
|
@ -868,6 +870,8 @@
|
||||||
34B3F86D1E8DF1700035BE1A /* SignalsNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalsNavigationController.h; sourceTree = "<group>"; };
|
34B3F86D1E8DF1700035BE1A /* SignalsNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalsNavigationController.h; sourceTree = "<group>"; };
|
||||||
34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalsNavigationController.m; sourceTree = "<group>"; };
|
34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalsNavigationController.m; sourceTree = "<group>"; };
|
||||||
34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = "<group>"; };
|
34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = "<group>"; };
|
||||||
|
34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorInteraction.swift; sourceTree = "<group>"; };
|
||||||
|
34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorCell.swift; sourceTree = "<group>"; };
|
||||||
34B6D27220F664C800765BE2 /* OWSUnreadIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSUnreadIndicator.h; sourceTree = "<group>"; };
|
34B6D27220F664C800765BE2 /* OWSUnreadIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSUnreadIndicator.h; sourceTree = "<group>"; };
|
||||||
34B6D27320F664C800765BE2 /* OWSUnreadIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSUnreadIndicator.m; sourceTree = "<group>"; };
|
34B6D27320F664C800765BE2 /* OWSUnreadIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSUnreadIndicator.m; sourceTree = "<group>"; };
|
||||||
34BECE291F74C12700D7438D /* DebugUIStress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIStress.h; sourceTree = "<group>"; };
|
34BECE291F74C12700D7438D /* DebugUIStress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIStress.h; sourceTree = "<group>"; };
|
||||||
|
@ -1575,6 +1579,7 @@
|
||||||
34D1F0721F8678AA0066283D /* ConversationViewLayout.m */,
|
34D1F0721F8678AA0066283D /* ConversationViewLayout.m */,
|
||||||
341341ED2187467900192D59 /* ConversationViewModel.h */,
|
341341ED2187467900192D59 /* ConversationViewModel.h */,
|
||||||
341341EE2187467900192D59 /* ConversationViewModel.m */,
|
341341EE2187467900192D59 /* ConversationViewModel.m */,
|
||||||
|
34B6A904218B4C90007C4606 /* TypingIndicatorInteraction.swift */,
|
||||||
);
|
);
|
||||||
path = ConversationView;
|
path = ConversationView;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1844,6 +1849,7 @@
|
||||||
34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */,
|
34277A5C20751BDC006049F2 /* OWSQuotedMessageView.m */,
|
||||||
34D1F0A51F867BFC0066283D /* OWSSystemMessageCell.h */,
|
34D1F0A51F867BFC0066283D /* OWSSystemMessageCell.h */,
|
||||||
34D1F0A61F867BFC0066283D /* OWSSystemMessageCell.m */,
|
34D1F0A61F867BFC0066283D /* OWSSystemMessageCell.m */,
|
||||||
|
34B6A906218B5240007C4606 /* TypingIndicatorCell.swift */,
|
||||||
);
|
);
|
||||||
path = Cells;
|
path = Cells;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -3310,6 +3316,7 @@
|
||||||
34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */,
|
34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */,
|
||||||
348570A820F67575004FF32B /* OWSMessageHeaderView.m in Sources */,
|
348570A820F67575004FF32B /* OWSMessageHeaderView.m in Sources */,
|
||||||
450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */,
|
450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */,
|
||||||
|
34B6A907218B5241007C4606 /* TypingIndicatorCell.swift in Sources */,
|
||||||
34D1F0AB1F867BFC0066283D /* OWSContactOffersCell.m in Sources */,
|
34D1F0AB1F867BFC0066283D /* OWSContactOffersCell.m in Sources */,
|
||||||
340FC8C7204DE64D007AEB0F /* OWSBackupAPI.swift in Sources */,
|
340FC8C7204DE64D007AEB0F /* OWSBackupAPI.swift in Sources */,
|
||||||
343A65981FC4CFE7000477A1 /* ConversationScrollButton.m in Sources */,
|
343A65981FC4CFE7000477A1 /* ConversationScrollButton.m in Sources */,
|
||||||
|
@ -3388,6 +3395,7 @@
|
||||||
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */,
|
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */,
|
||||||
340FC8D0205BF2FA007AEB0F /* OWSBackupIO.m in Sources */,
|
340FC8D0205BF2FA007AEB0F /* OWSBackupIO.m in Sources */,
|
||||||
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
|
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
|
||||||
|
34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */,
|
||||||
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,
|
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,
|
||||||
340FC8AB204DAC8D007AEB0F /* DomainFrontingCountryViewController.m in Sources */,
|
340FC8AB204DAC8D007AEB0F /* DomainFrontingCountryViewController.m in Sources */,
|
||||||
3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */,
|
3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */,
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc(OWSTypingIndicatorCell)
|
||||||
|
public class TypingIndicatorCell: ConversationViewCell {
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public static let cellReuseIdentifier = "TypingIndicatorCell"
|
||||||
|
|
||||||
|
@available(*, unavailable, message:"use other constructor instead.")
|
||||||
|
@objc
|
||||||
|
public required init(coder aDecoder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public override func loadForDisplay() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public override func cellSize() -> CGSize {
|
||||||
|
return .zero
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public override func prepareForReuse() {
|
||||||
|
super.prepareForReuse()
|
||||||
|
}
|
||||||
|
}
|
|
@ -596,6 +596,8 @@ typedef enum : NSUInteger {
|
||||||
{
|
{
|
||||||
[self.collectionView registerClass:[OWSSystemMessageCell class]
|
[self.collectionView registerClass:[OWSSystemMessageCell class]
|
||||||
forCellWithReuseIdentifier:[OWSSystemMessageCell cellReuseIdentifier]];
|
forCellWithReuseIdentifier:[OWSSystemMessageCell cellReuseIdentifier]];
|
||||||
|
[self.collectionView registerClass:[OWSTypingIndicatorCell class]
|
||||||
|
forCellWithReuseIdentifier:[OWSTypingIndicatorCell cellReuseIdentifier]];
|
||||||
[self.collectionView registerClass:[OWSContactOffersCell class]
|
[self.collectionView registerClass:[OWSContactOffersCell class]
|
||||||
forCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier]];
|
forCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier]];
|
||||||
[self.collectionView registerClass:[OWSMessageCell class]
|
[self.collectionView registerClass:[OWSMessageCell class]
|
||||||
|
|
|
@ -302,6 +302,9 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
||||||
case OWSInteractionType_Offer:
|
case OWSInteractionType_Offer:
|
||||||
measurementCell = [OWSContactOffersCell new];
|
measurementCell = [OWSContactOffersCell new];
|
||||||
break;
|
break;
|
||||||
|
case OWSInteractionType_TypingIndicator:
|
||||||
|
measurementCell = [OWSTypingIndicatorCell new];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
OWSAssertDebug(measurementCell);
|
OWSAssertDebug(measurementCell);
|
||||||
|
@ -319,6 +322,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
||||||
return OWSMessageHeaderViewDateHeaderVMargin;
|
return OWSMessageHeaderViewDateHeaderVMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
|
||||||
// "Bubble Collapse". Adjacent messages with the same author should be close together.
|
// "Bubble Collapse". Adjacent messages with the same author should be close together.
|
||||||
if (self.interaction.interactionType == OWSInteractionType_IncomingMessage
|
if (self.interaction.interactionType == OWSInteractionType_IncomingMessage
|
||||||
&& previousLayoutItem.interaction.interactionType == OWSInteractionType_IncomingMessage) {
|
&& previousLayoutItem.interaction.interactionType == OWSInteractionType_IncomingMessage) {
|
||||||
|
@ -359,6 +364,10 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
||||||
case OWSInteractionType_Offer:
|
case OWSInteractionType_Offer:
|
||||||
return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier]
|
return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier]
|
||||||
forIndexPath:indexPath];
|
forIndexPath:indexPath];
|
||||||
|
|
||||||
|
case OWSInteractionType_TypingIndicator:
|
||||||
|
return [collectionView dequeueReusableCellWithReuseIdentifier:[OWSTypingIndicatorCell cellReuseIdentifier]
|
||||||
|
forIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,6 +489,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
||||||
switch (self.interaction.interactionType) {
|
switch (self.interaction.interactionType) {
|
||||||
case OWSInteractionType_Unknown:
|
case OWSInteractionType_Unknown:
|
||||||
case OWSInteractionType_Offer:
|
case OWSInteractionType_Offer:
|
||||||
|
case OWSInteractionType_TypingIndicator:
|
||||||
return;
|
return;
|
||||||
case OWSInteractionType_Error:
|
case OWSInteractionType_Error:
|
||||||
case OWSInteractionType_Info:
|
case OWSInteractionType_Info:
|
||||||
|
|
|
@ -143,6 +143,7 @@ static const int kYapDatabaseRangeMinLength = 0;
|
||||||
@property (nonatomic, nullable) ThreadDynamicInteractions *dynamicInteractions;
|
@property (nonatomic, nullable) ThreadDynamicInteractions *dynamicInteractions;
|
||||||
@property (nonatomic) BOOL hasClearedUnreadMessagesIndicator;
|
@property (nonatomic) BOOL hasClearedUnreadMessagesIndicator;
|
||||||
@property (nonatomic, nullable) NSDate *collapseCutoffDate;
|
@property (nonatomic, nullable) NSDate *collapseCutoffDate;
|
||||||
|
@property (nonatomic, nullable) NSString *typingIndicatorsRecipient;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -200,6 +201,11 @@ static const int kYapDatabaseRangeMinLength = 0;
|
||||||
return OWSBlockingManager.sharedManager;
|
return OWSBlockingManager.sharedManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id<OWSTypingIndicators>)typingIndicators
|
||||||
|
{
|
||||||
|
return SSKEnvironment.shared.typingIndicators;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark
|
#pragma mark
|
||||||
|
|
||||||
- (void)addNotificationListeners
|
- (void)addNotificationListeners
|
||||||
|
@ -224,6 +230,10 @@ static const int kYapDatabaseRangeMinLength = 0;
|
||||||
selector:@selector(signalAccountsDidChange:)
|
selector:@selector(signalAccountsDidChange:)
|
||||||
name:OWSContactsManagerSignalAccountsDidChangeNotification
|
name:OWSContactsManagerSignalAccountsDidChangeNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(typingIndicatorStateDidChange:)
|
||||||
|
name:[OWSTypingIndicatorsImpl typingIndicatorStateDidChange]
|
||||||
|
object:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)signalAccountsDidChange:(NSNotification *)notification
|
- (void)signalAccountsDidChange:(NSNotification *)notification
|
||||||
|
@ -240,6 +250,7 @@ static const int kYapDatabaseRangeMinLength = 0;
|
||||||
// We need to update the "unread indicator" _before_ we determine the initial range
|
// We need to update the "unread indicator" _before_ we determine the initial range
|
||||||
// size, since it depends on where the unread indicator is placed.
|
// size, since it depends on where the unread indicator is placed.
|
||||||
self.lastRangeLength = 0;
|
self.lastRangeLength = 0;
|
||||||
|
self.typingIndicatorsRecipient = [self.typingIndicators typingIndicatorsForThread:self.thread];
|
||||||
|
|
||||||
[self ensureDynamicInteractions];
|
[self ensureDynamicInteractions];
|
||||||
[self.primaryStorage updateUIDatabaseConnectionToLatest];
|
[self.primaryStorage updateUIDatabaseConnectionToLatest];
|
||||||
|
@ -574,6 +585,36 @@ static const int kYapDatabaseRangeMinLength = 0;
|
||||||
updatedNeighborItemSet:updatedNeighborItemSet];
|
updatedNeighborItemSet:updatedNeighborItemSet];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A simpler version of the update logic we call when
|
||||||
|
// only transient items have changed.
|
||||||
|
- (void)updateForTransientItems
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
|
OWSLogVerbose(@"");
|
||||||
|
|
||||||
|
NSMutableArray<NSString *> *oldItemIdList = [NSMutableArray new];
|
||||||
|
for (id<ConversationViewItem> viewItem in self.viewItems) {
|
||||||
|
[oldItemIdList addObject:viewItem.itemId];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSUInteger oldViewItemCount = self.viewItems.count;
|
||||||
|
if (![self reloadViewItems]) {
|
||||||
|
// These errors are rare.
|
||||||
|
OWSFailDebug(@"could not reload view items; hard resetting message mappings.");
|
||||||
|
// resetMappings will call delegate.conversationViewModelDidUpdate.
|
||||||
|
[self resetMappings];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OWSLogVerbose(@"self.viewItems.count: %zd -> %zd", oldViewItemCount, self.viewItems.count);
|
||||||
|
|
||||||
|
[self updateViewWitholdItemIdList:oldItemIdList
|
||||||
|
updatedItemSet:[NSSet set]
|
||||||
|
oldViewItemCount:oldViewItemCount
|
||||||
|
updatedNeighborItemSet:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)updateViewWithOldItemIdList:(NSArray<NSString *> *)oldItemIdList
|
- (void)updateViewWithOldItemIdList:(NSArray<NSString *> *)oldItemIdList
|
||||||
updatedItemSet:(NSSet<NSString *> *)updatedItemSet
|
updatedItemSet:(NSSet<NSString *> *)updatedItemSet
|
||||||
updatedNeighborItemSet:(nullable NSMutableSet<NSString *> *)updatedNeighborItemSet
|
updatedNeighborItemSet:(nullable NSMutableSet<NSString *> *)updatedNeighborItemSet
|
||||||
|
@ -863,6 +904,25 @@ static const int kYapDatabaseRangeMinLength = 0;
|
||||||
OWSAssertDebug(!viewItemCache[interaction.uniqueId]);
|
OWSAssertDebug(!viewItemCache[interaction.uniqueId]);
|
||||||
viewItemCache[interaction.uniqueId] = viewItem;
|
viewItemCache[interaction.uniqueId] = viewItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self.typingIndicatorsRecipient) {
|
||||||
|
id<ConversationViewItem> _Nullable lastViewItem = viewItems.lastObject;
|
||||||
|
uint64_t typingIndicatorTimestamp = (lastViewItem ? lastViewItem.interaction.timestamp + 1 : 1);
|
||||||
|
TSInteraction *interaction =
|
||||||
|
[[OWSTypingIndicatorInteraction alloc] initWithThread:self.thread
|
||||||
|
timestamp:typingIndicatorTimestamp
|
||||||
|
recipientId:self.typingIndicatorsRecipient];
|
||||||
|
id<ConversationViewItem> _Nullable viewItem = self.viewItemCache[interaction.uniqueId];
|
||||||
|
if (!viewItem) {
|
||||||
|
viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:interaction
|
||||||
|
isGroupThread:isGroupThread
|
||||||
|
transaction:transaction
|
||||||
|
conversationStyle:conversationStyle];
|
||||||
|
}
|
||||||
|
[viewItems addObject:viewItem];
|
||||||
|
OWSAssertDebug(!viewItemCache[interaction.uniqueId]);
|
||||||
|
viewItemCache[interaction.uniqueId] = viewItem;
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Flag to ensure that we only increment once per launch.
|
// Flag to ensure that we only increment once per launch.
|
||||||
|
@ -883,6 +943,7 @@ static const int kYapDatabaseRangeMinLength = 0;
|
||||||
switch (viewItem.interaction.interactionType) {
|
switch (viewItem.interaction.interactionType) {
|
||||||
case OWSInteractionType_Unknown:
|
case OWSInteractionType_Unknown:
|
||||||
case OWSInteractionType_Offer:
|
case OWSInteractionType_Offer:
|
||||||
|
case OWSInteractionType_TypingIndicator:
|
||||||
canShowDate = NO;
|
canShowDate = NO;
|
||||||
break;
|
break;
|
||||||
case OWSInteractionType_IncomingMessage:
|
case OWSInteractionType_IncomingMessage:
|
||||||
|
@ -1276,6 +1337,28 @@ static const int kYapDatabaseRangeMinLength = 0;
|
||||||
return @(groupIndex);
|
return @(groupIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)typingIndicatorStateDidChange:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
|
self.typingIndicatorsRecipient = [self.typingIndicators typingIndicatorsForThread:self.thread];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTypingIndicatorsRecipient:(nullable NSString *)typingIndicatorsRecipient
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
|
BOOL didChange = ![NSObject isNullableObject:typingIndicatorsRecipient equalTo:_typingIndicatorsRecipient];
|
||||||
|
|
||||||
|
_typingIndicatorsRecipient = typingIndicatorsRecipient;
|
||||||
|
|
||||||
|
// Update the view items if necessary.
|
||||||
|
// We don't have to do this if they haven't been configured yet.
|
||||||
|
if (didChange && self.viewItems != nil) {
|
||||||
|
[self updateForTransientItems];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc(OWSTypingIndicatorInteraction)
|
||||||
|
public class TypingIndicatorInteraction: TSInteraction {
|
||||||
|
@objc
|
||||||
|
public static let TypingIndicatorId = "TypingIndicator"
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public override func isDynamicInteraction() -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public override func interactionType() -> OWSInteractionType {
|
||||||
|
return .typingIndicator
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message:"use other constructor instead.")
|
||||||
|
@objc
|
||||||
|
public required init(coder aDecoder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message:"use other constructor instead.")
|
||||||
|
@objc
|
||||||
|
public required init(dictionary dictionaryValue: [AnyHashable: Any]!) throws {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public let recipientId: String
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public init(thread: TSThread, timestamp: UInt64, recipientId: String) {
|
||||||
|
self.recipientId = recipientId
|
||||||
|
|
||||||
|
super.init(interactionWithUniqueId: TypingIndicatorInteraction.TypingIndicatorId,
|
||||||
|
timestamp: timestamp, in: thread)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,9 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
@objc class TypingIndicatorView: UIStackView {
|
@objc class TypingIndicatorView: UIStackView {
|
||||||
private let kDotMaxHSpacing: CGFloat = 8
|
// This represents the spacing between the dots
|
||||||
|
// _at their max size_.
|
||||||
|
private let kDotMaxHSpacing: CGFloat = 3
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public static let kMinRadiusPt: CGFloat = 6
|
public static let kMinRadiusPt: CGFloat = 6
|
||||||
|
|
|
@ -16,6 +16,7 @@ typedef NS_ENUM(NSInteger, OWSInteractionType) {
|
||||||
OWSInteractionType_Call,
|
OWSInteractionType_Call,
|
||||||
OWSInteractionType_Info,
|
OWSInteractionType_Info,
|
||||||
OWSInteractionType_Offer,
|
OWSInteractionType_Offer,
|
||||||
|
OWSInteractionType_TypingIndicator,
|
||||||
};
|
};
|
||||||
|
|
||||||
NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
||||||
|
@ -28,6 +29,9 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
|
||||||
|
|
||||||
@interface TSInteraction : TSYapDatabaseObject
|
@interface TSInteraction : TSYapDatabaseObject
|
||||||
|
|
||||||
|
- (instancetype)initInteractionWithUniqueId:(NSString *)uniqueId
|
||||||
|
timestamp:(uint64_t)timestamp
|
||||||
|
inThread:(TSThread *)thread;
|
||||||
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread;
|
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread;
|
||||||
|
|
||||||
@property (nonatomic, readonly) NSString *uniqueThreadId;
|
@property (nonatomic, readonly) NSString *uniqueThreadId;
|
||||||
|
|
|
@ -27,6 +27,8 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
||||||
return @"OWSInteractionType_Info";
|
return @"OWSInteractionType_Info";
|
||||||
case OWSInteractionType_Offer:
|
case OWSInteractionType_Offer:
|
||||||
return @"OWSInteractionType_Offer";
|
return @"OWSInteractionType_Offer";
|
||||||
|
case OWSInteractionType_TypingIndicator:
|
||||||
|
return @"OWSInteractionType_TypingIndicator";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +76,24 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
|
||||||
return @"TSInteraction";
|
return @"TSInteraction";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (instancetype)initInteractionWithUniqueId:(NSString *)uniqueId
|
||||||
|
timestamp:(uint64_t)timestamp
|
||||||
|
inThread:(TSThread *)thread
|
||||||
|
{
|
||||||
|
OWSAssertDebug(timestamp > 0);
|
||||||
|
|
||||||
|
self = [super initWithUniqueId:uniqueId];
|
||||||
|
|
||||||
|
if (!self) {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
_timestamp = timestamp;
|
||||||
|
_uniqueThreadId = thread.uniqueId;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread
|
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread
|
||||||
{
|
{
|
||||||
OWSAssertDebug(timestamp > 0);
|
OWSAssertDebug(timestamp > 0);
|
||||||
|
|
Loading…
Reference in a new issue