mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Add typing indicators in home view.
This commit is contained in:
parent
b063a49d56
commit
50381cc94c
4 changed files with 165 additions and 10 deletions
|
@ -216,6 +216,7 @@
|
||||||
34B3F8821E8DF1700035BE1A /* NewContactThreadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8501E8DF1700035BE1A /* NewContactThreadViewController.m */; };
|
34B3F8821E8DF1700035BE1A /* NewContactThreadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8501E8DF1700035BE1A /* NewContactThreadViewController.m */; };
|
||||||
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 */; };
|
||||||
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 */; };
|
||||||
|
@ -866,6 +867,7 @@
|
||||||
34B3F8551E8DF1700035BE1A /* NewGroupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewGroupViewController.m; sourceTree = "<group>"; };
|
34B3F8551E8DF1700035BE1A /* NewGroupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewGroupViewController.m; sourceTree = "<group>"; };
|
||||||
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>"; };
|
||||||
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>"; };
|
||||||
|
@ -2215,10 +2217,11 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
452EA09D1EA7ABE00078744B /* AttachmentPointerView.swift */,
|
452EA09D1EA7ABE00078744B /* AttachmentPointerView.swift */,
|
||||||
4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */,
|
|
||||||
34E3E5671EC4B19400495BAC /* AudioProgressView.swift */,
|
34E3E5671EC4B19400495BAC /* AudioProgressView.swift */,
|
||||||
|
4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */,
|
||||||
451764291DE939FD00EDB8B9 /* ContactCell.swift */,
|
451764291DE939FD00EDB8B9 /* ContactCell.swift */,
|
||||||
4523149F1F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift */,
|
4523149F1F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift */,
|
||||||
|
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */,
|
||||||
45A663C41F92EC760027B59E /* GroupTableViewCell.swift */,
|
45A663C41F92EC760027B59E /* GroupTableViewCell.swift */,
|
||||||
45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */,
|
45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */,
|
||||||
34386A53207D271C009F5D9C /* NeverClearView.swift */,
|
34386A53207D271C009F5D9C /* NeverClearView.swift */,
|
||||||
|
@ -2234,8 +2237,8 @@
|
||||||
45A6DAD51EBBF85500893231 /* ReminderView.swift */,
|
45A6DAD51EBBF85500893231 /* ReminderView.swift */,
|
||||||
450D19111F85236600970622 /* RemoteVideoView.h */,
|
450D19111F85236600970622 /* RemoteVideoView.h */,
|
||||||
450D19121F85236600970622 /* RemoteVideoView.m */,
|
450D19121F85236600970622 /* RemoteVideoView.m */,
|
||||||
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */,
|
|
||||||
4CA5F792211E1F06008C2708 /* Toast.swift */,
|
4CA5F792211E1F06008C2708 /* Toast.swift */,
|
||||||
|
34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */,
|
||||||
);
|
);
|
||||||
name = Views;
|
name = Views;
|
||||||
path = views;
|
path = views;
|
||||||
|
@ -3382,6 +3385,7 @@
|
||||||
457C87B82032645C008D52D6 /* DebugUINotifications.swift in Sources */,
|
457C87B82032645C008D52D6 /* DebugUINotifications.swift in Sources */,
|
||||||
4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */,
|
4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */,
|
||||||
4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */,
|
4CC1ECFB211A553000CC13BE /* AppUpdateNag.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 */,
|
||||||
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,
|
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,
|
||||||
|
|
|
@ -22,6 +22,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
@property (nonatomic) UILabel *snippetLabel;
|
@property (nonatomic) UILabel *snippetLabel;
|
||||||
@property (nonatomic) UILabel *dateTimeLabel;
|
@property (nonatomic) UILabel *dateTimeLabel;
|
||||||
@property (nonatomic) MessageStatusView *messageStatusView;
|
@property (nonatomic) MessageStatusView *messageStatusView;
|
||||||
|
@property (nonatomic) TypingIndicatorView *typingIndicatorView;
|
||||||
|
@property (nonatomic) UIStackView *previewStackView;
|
||||||
|
|
||||||
@property (nonatomic) UIView *unreadBadge;
|
@property (nonatomic) UIView *unreadBadge;
|
||||||
@property (nonatomic) UILabel *unreadLabel;
|
@property (nonatomic) UILabel *unreadLabel;
|
||||||
|
@ -45,6 +47,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
return Environment.shared.contactsManager;
|
return Environment.shared.contactsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id<OWSTypingIndicators>)typingIndicators
|
||||||
|
{
|
||||||
|
return SSKEnvironment.shared.typingIndicators;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
|
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
|
||||||
|
@ -111,15 +118,25 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
self.snippetLabel.font = [self snippetFont];
|
self.snippetLabel.font = [self snippetFont];
|
||||||
self.snippetLabel.numberOfLines = 1;
|
self.snippetLabel.numberOfLines = 1;
|
||||||
self.snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
self.snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||||
[self.snippetLabel setContentHuggingHorizontalLow];
|
|
||||||
[self.snippetLabel setCompressionResistanceHorizontalLow];
|
self.typingIndicatorView = [TypingIndicatorView new];
|
||||||
|
|
||||||
|
self.previewStackView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
||||||
|
self.snippetLabel,
|
||||||
|
self.typingIndicatorView,
|
||||||
|
]];
|
||||||
|
self.previewStackView.axis = UILayoutConstraintAxisVertical;
|
||||||
|
self.previewStackView.alignment = UIStackViewAlignmentLeading;
|
||||||
|
[self.previewStackView setContentHuggingHorizontalLow];
|
||||||
|
[self.previewStackView setCompressionResistanceHorizontalLow];
|
||||||
|
|
||||||
UIStackView *bottomRowView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
UIStackView *bottomRowView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
||||||
self.snippetLabel,
|
self.previewStackView,
|
||||||
self.messageStatusView,
|
self.messageStatusView,
|
||||||
]];
|
]];
|
||||||
|
|
||||||
bottomRowView.axis = UILayoutConstraintAxisHorizontal;
|
bottomRowView.axis = UILayoutConstraintAxisHorizontal;
|
||||||
bottomRowView.alignment = UIStackViewAlignmentLastBaseline;
|
bottomRowView.alignment = UIStackViewAlignmentCenter;
|
||||||
bottomRowView.spacing = 6.f;
|
bottomRowView.spacing = 6.f;
|
||||||
|
|
||||||
UIStackView *vStackView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
UIStackView *vStackView = [[UIStackView alloc] initWithArrangedSubviews:@[
|
||||||
|
@ -203,6 +220,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
selector:@selector(otherUsersProfileDidChange:)
|
selector:@selector(otherUsersProfileDidChange:)
|
||||||
name:kNSNotificationName_OtherUsersProfileDidChange
|
name:kNSNotificationName_OtherUsersProfileDidChange
|
||||||
object:nil];
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(typingIndicatorStateDidChange:)
|
||||||
|
name:[OWSTypingIndicatorsImpl typingIndicatorStateDidChange]
|
||||||
|
object:nil];
|
||||||
[self updateNameLabel];
|
[self updateNameLabel];
|
||||||
[self updateAvatarView];
|
[self updateAvatarView];
|
||||||
|
|
||||||
|
@ -215,7 +236,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
} else {
|
} else {
|
||||||
self.snippetLabel.attributedText = [self attributedSnippetForThread:thread isBlocked:isBlocked];
|
self.snippetLabel.attributedText = [self attributedSnippetForThread:thread isBlocked:isBlocked];
|
||||||
}
|
}
|
||||||
|
[self updatePreview];
|
||||||
|
CGFloat previewHeight = MAX(self.snippetLabel.font.lineHeight,
|
||||||
|
TypingIndicatorView.kMaxRadiusPt);
|
||||||
|
[self.viewConstraints addObjectsFromArray:@[
|
||||||
|
[self.previewStackView autoSetDimension:ALDimensionHeight
|
||||||
|
toSize:previewHeight],
|
||||||
|
]];
|
||||||
self.dateTimeLabel.text
|
self.dateTimeLabel.text
|
||||||
= (overrideDate ? [self stringForDate:overrideDate] : [self stringForDate:thread.lastMessageDate]);
|
= (overrideDate ? [self stringForDate:overrideDate] : [self stringForDate:thread.lastMessageDate]);
|
||||||
|
|
||||||
|
@ -500,6 +527,28 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
self.nameLabel.attributedText = name;
|
self.nameLabel.attributedText = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Typing Indicators
|
||||||
|
|
||||||
|
- (void)updatePreview
|
||||||
|
{
|
||||||
|
if ([self.typingIndicators typingIndicatorsForThread:self.thread.threadRecord] != nil) {
|
||||||
|
self.snippetLabel.hidden = YES;
|
||||||
|
self.typingIndicatorView.hidden = NO;
|
||||||
|
[self.typingIndicatorView startAnimation];
|
||||||
|
} else {
|
||||||
|
self.snippetLabel.hidden = NO;
|
||||||
|
self.typingIndicatorView.hidden = YES;
|
||||||
|
[self.typingIndicatorView stopAnimation];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)typingIndicatorStateDidChange:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
|
[self updatePreview];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
101
Signal/src/views/TypingIndicatorView.swift
Normal file
101
Signal/src/views/TypingIndicatorView.swift
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@objc class TypingIndicatorView: UIStackView {
|
||||||
|
private let kDotMaxHSpacing: CGFloat = 8
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public static let kMinRadiusPt: CGFloat = 6
|
||||||
|
@objc
|
||||||
|
public static let kMaxRadiusPt: CGFloat = 8
|
||||||
|
|
||||||
|
private let dot1 = DotView(dotType: .dotType1)
|
||||||
|
private let dot2 = DotView(dotType: .dotType2)
|
||||||
|
private let dot3 = DotView(dotType: .dotType3)
|
||||||
|
|
||||||
|
override public var isHidden: Bool {
|
||||||
|
didSet {
|
||||||
|
Logger.verbose("\(oldValue) -> \(isHidden)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message:"use other constructor instead.")
|
||||||
|
required init(coder aDecoder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message:"use other constructor instead.")
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public init() {
|
||||||
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
// init(arrangedSubviews:...) is not a designated initializer.
|
||||||
|
addArrangedSubview(dot1)
|
||||||
|
addArrangedSubview(dot2)
|
||||||
|
addArrangedSubview(dot3)
|
||||||
|
|
||||||
|
self.axis = .horizontal
|
||||||
|
self.spacing = kDotMaxHSpacing
|
||||||
|
self.alignment = .center
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public func startAnimation() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public func stopAnimation() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum DotType {
|
||||||
|
case dotType1
|
||||||
|
case dotType2
|
||||||
|
case dotType3
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DotView: UIView {
|
||||||
|
private let dotType: DotType
|
||||||
|
|
||||||
|
private let shapeLayer = CAShapeLayer()
|
||||||
|
|
||||||
|
@available(*, unavailable, message:"use other constructor instead.")
|
||||||
|
required init?(coder aDecoder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message:"use other constructor instead.")
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(dotType: DotType) {
|
||||||
|
self.dotType = dotType
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
autoSetDimension(.width, toSize: kMaxRadiusPt)
|
||||||
|
autoSetDimension(.height, toSize: kMaxRadiusPt)
|
||||||
|
|
||||||
|
self.layer.addSublayer(shapeLayer)
|
||||||
|
|
||||||
|
updateLayer()
|
||||||
|
// self.text = text
|
||||||
|
//
|
||||||
|
// setupSubviews()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateLayer() {
|
||||||
|
shapeLayer.fillColor = UIColor.ows_signalBlue.cgColor
|
||||||
|
|
||||||
|
let margin = (TypingIndicatorView.kMaxRadiusPt - TypingIndicatorView.kMinRadiusPt) * 0.5
|
||||||
|
let bezierPath = UIBezierPath(ovalIn: CGRect(x: margin, y: margin, width: TypingIndicatorView.kMinRadiusPt, height: TypingIndicatorView.kMinRadiusPt))
|
||||||
|
shapeLayer.path = bezierPath.cgPath
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ public protocol TypingIndicators: class {
|
||||||
//
|
//
|
||||||
// TODO: Use this method.
|
// TODO: Use this method.
|
||||||
@objc
|
@objc
|
||||||
func typingIndicators(forThread thread: TSThread, recipientId: String) -> String?
|
func typingIndicators(forThread thread: TSThread) -> String?
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
func setTypingIndicatorsEnabled(value: Bool)
|
func setTypingIndicatorsEnabled(value: Bool)
|
||||||
|
@ -45,7 +45,8 @@ public protocol TypingIndicators: class {
|
||||||
@objc(OWSTypingIndicatorsImpl)
|
@objc(OWSTypingIndicatorsImpl)
|
||||||
public class TypingIndicatorsImpl: NSObject, TypingIndicators {
|
public class TypingIndicatorsImpl: NSObject, TypingIndicators {
|
||||||
|
|
||||||
@objc public static let typingIndicatorStateDidChange = Notification.Name("typingIndicatorStateDidChange")
|
@objc
|
||||||
|
public static let typingIndicatorStateDidChange = Notification.Name("typingIndicatorStateDidChange")
|
||||||
|
|
||||||
private let kDatabaseCollection = "TypingIndicators"
|
private let kDatabaseCollection = "TypingIndicators"
|
||||||
private let kDatabaseKey_TypingIndicatorsEnabled = "kDatabaseKey_TypingIndicatorsEnabled"
|
private let kDatabaseKey_TypingIndicatorsEnabled = "kDatabaseKey_TypingIndicatorsEnabled"
|
||||||
|
@ -150,7 +151,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public func typingIndicators(forThread thread: TSThread, recipientId: String) -> String? {
|
public func typingIndicators(forThread thread: TSThread) -> String? {
|
||||||
AssertIsOnMainThread()
|
AssertIsOnMainThread()
|
||||||
|
|
||||||
var firstRecipientId: String?
|
var firstRecipientId: String?
|
||||||
|
|
Loading…
Reference in a new issue