From e81a074efcda9b0a303b5ae8473f02d4b67d5f63 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 27 May 2019 16:30:28 +1000 Subject: [PATCH] Show online status --- .../AppSettings/AppSettingsViewController.m | 1 + .../ConversationHeaderView.swift | 2 - .../ViewControllers/HomeView/HomeViewCell.m | 3 +- .../OWSConversationSettingsViewController.m | 1 + SignalMessaging/Views/AvatarImageView.swift | 42 ++++++++++++++++--- SignalServiceKit/src/Loki/API/LokiAPI.swift | 6 +-- .../src/Loki/API/LokiP2PManager.swift | 16 +++---- .../Loki/API/Notification+OnlineStatus.swift | 4 ++ 8 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 SignalServiceKit/src/Loki/API/Notification+OnlineStatus.swift diff --git a/Signal/src/ViewControllers/AppSettings/AppSettingsViewController.m b/Signal/src/ViewControllers/AppSettings/AppSettingsViewController.m index 8a55a5f43..02ba53534 100644 --- a/Signal/src/ViewControllers/AppSettings/AppSettingsViewController.m +++ b/Signal/src/ViewControllers/AppSettings/AppSettingsViewController.m @@ -306,6 +306,7 @@ [avatarView autoPinLeadingToSuperviewMargin]; [avatarView autoSetDimension:ALDimensionWidth toSize:kLargeAvatarSize]; [avatarView autoSetDimension:ALDimensionHeight toSize:kLargeAvatarSize]; + avatarView.contactID = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; if (!localProfileAvatarImage) { UIImage *cameraImage = [UIImage imageNamed:@"settings-avatar-camera"]; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationHeaderView.swift b/Signal/src/ViewControllers/ConversationView/ConversationHeaderView.swift index a0ae1b92c..680060ac6 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationHeaderView.swift +++ b/Signal/src/ViewControllers/ConversationView/ConversationHeaderView.swift @@ -61,8 +61,6 @@ public class ConversationHeaderView: UIStackView { let avatarView = ConversationAvatarImageView(thread: thread, diameter: 36, contactsManager: contactsManager) self.avatarView = avatarView - // remove default border on avatarView - avatarView.layer.borderWidth = 0 titleLabel = UILabel() titleLabel.textColor = Theme.navbarTitleColor diff --git a/Signal/src/ViewControllers/HomeView/HomeViewCell.m b/Signal/src/ViewControllers/HomeView/HomeViewCell.m index 89dd0d735..1a217565a 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewCell.m +++ b/Signal/src/ViewControllers/HomeView/HomeViewCell.m @@ -360,7 +360,8 @@ NS_ASSUME_NONNULL_BEGIN self.avatarView.image = nil; return; } - + self.avatarView.contactID = thread.contactIdentifier; + [self.avatarView updateOnlineStatusIndicator]; self.avatarView.image = [OWSAvatarBuilder buildImageForThread:thread.threadRecord diameter:self.avatarSize]; } diff --git a/Signal/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m b/Signal/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m index fc6da4104..3ba78c584 100644 --- a/Signal/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m +++ b/Signal/src/ViewControllers/ThreadSettings/OWSConversationSettingsViewController.m @@ -908,6 +908,7 @@ const CGFloat kIconViewLength = 24; [avatarView autoPinLeadingToSuperviewMargin]; [avatarView autoSetDimension:ALDimensionWidth toSize:kLargeAvatarSize]; [avatarView autoSetDimension:ALDimensionHeight toSize:kLargeAvatarSize]; + avatarView.contactID = self.thread.contactIdentifier; UIView *threadNameView = [UIView containerView]; [threadInfoView addSubview:threadNameView]; diff --git a/SignalMessaging/Views/AvatarImageView.swift b/SignalMessaging/Views/AvatarImageView.swift index 5495bc2e8..fa8c5d793 100644 --- a/SignalMessaging/Views/AvatarImageView.swift +++ b/SignalMessaging/Views/AvatarImageView.swift @@ -6,30 +6,37 @@ import UIKit @objc public class AvatarImageView: UIImageView { - private let shadowLayer = CAShapeLayer() + @objc var contactID: String = "" public init() { super.init(frame: .zero) - self.configureView() + self.initialize() } override init(frame: CGRect) { super.init(frame: frame) - self.configureView() + self.initialize() } required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - self.configureView() + self.initialize() } override init(image: UIImage?) { super.init(image: image) - self.configureView() + self.initialize() } - func configureView() { + func initialize() { + // Loki: Used to indicate a contact's online status + layer.borderWidth = 3 + + // Loki: Observe online status changes + NotificationCenter.default.addObserver(self, selector: #selector(handleOnlineStatusChangedNotification), name: .contactOnlineStatusChanged, object: nil) + + // Set up UI self.autoPinToSquareAspectRatio() self.layer.minificationFilter = .trilinear @@ -44,6 +51,9 @@ public class AvatarImageView: UIImageView { override public func layoutSubviews() { self.layer.cornerRadius = self.frame.size.width / 2 + // Loki: Update the online status indicator if needed + updateOnlineStatusIndicator() + // Inner shadow. // This should usually not be visible; it is used to distinguish // profile pics from the background if they are similar. @@ -63,6 +73,25 @@ public class AvatarImageView: UIImageView { self.shadowLayer.shadowOpacity = 0.15 self.shadowLayer.shadowOffset = .zero } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + @objc private func handleOnlineStatusChangedNotification(_ notification: Notification) { + let contactID = notification.object as! String + guard contactID == self.contactID else { return } + updateOnlineStatusIndicator() + } + + @objc func updateOnlineStatusIndicator() { + let peerInfo = LokiP2PManager.getInfo(for: contactID) + let isOnline = peerInfo?.isOnline ?? false + let color: UIColor = isOnline ? .ows_green : .ows_gray75 + let currentUserID = OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey + let isCurrentUser = (contactID == currentUserID) + layer.borderColor = isCurrentUser ? UIColor.clear.cgColor : color.cgColor + } } /// Avatar View which updates itself as necessary when the profile, contact, or group picture changes. @@ -100,6 +129,7 @@ public class ConversationAvatarImageView: AvatarImageView { super.init(frame: .zero) if recipientId != nil { + self.contactID = recipientId! // Loki NotificationCenter.default.addObserver(self, selector: #selector(handleOtherUsersProfileChanged(notification:)), name: NSNotification.Name(rawValue: kNSNotificationName_OtherUsersProfileDidChange), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleSignalAccountsChanged(notification:)), name: NSNotification.Name.OWSContactsManagerSignalAccountsDidChange, object: nil) diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index ebf79c7ad..8f49ff98f 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -76,9 +76,9 @@ import PromiseKit LokiP2PManager.markOffline(destination) if lokiMessage.isPing { Logger.warn("[Loki] Failed to ping \(destination); marking contact as offline.") - if let nsError = error as? NSError { - nsError.isRetryable = false - throw nsError + if let error = error as? NSError { + error.isRetryable = false + throw error } else { throw error } diff --git a/SignalServiceKit/src/Loki/API/LokiP2PManager.swift b/SignalServiceKit/src/Loki/API/LokiP2PManager.swift index 979eb7cff..c7882981f 100644 --- a/SignalServiceKit/src/Loki/API/LokiP2PManager.swift +++ b/SignalServiceKit/src/Loki/API/LokiP2PManager.swift @@ -8,12 +8,12 @@ private static let offlinePingTime = 2 * kMinuteInterval /// A p2p state struct - internal struct PeerInfo { - var address: String - var port: UInt16 - var isOnline: Bool - var timerDuration: Double - var pingTimer: Timer? = nil + public struct PeerInfo { + public var address: String + public var port: UInt16 + public var isOnline: Bool + public var timerDuration: Double + public var pingTimer: Timer? = nil } /// Our p2p address @@ -77,7 +77,7 @@ /// /// - Parameter pubKey: The contact hex pubkey /// - Returns: The P2P Details or nil if they don't exist - internal static func getInfo(for hexEncodedPublicKey: String) -> PeerInfo? { + public static func getInfo(for hexEncodedPublicKey: String) -> PeerInfo? { return peerInfo[hexEncodedPublicKey] } @@ -163,6 +163,8 @@ info.isOnline = isOnline peerInfo[pubKey] = info + + NotificationCenter.default.post(name: .contactOnlineStatusChanged, object: pubKey) } } diff --git a/SignalServiceKit/src/Loki/API/Notification+OnlineStatus.swift b/SignalServiceKit/src/Loki/API/Notification+OnlineStatus.swift new file mode 100644 index 000000000..da76ea460 --- /dev/null +++ b/SignalServiceKit/src/Loki/API/Notification+OnlineStatus.swift @@ -0,0 +1,4 @@ + +public extension Notification.Name { + public static let contactOnlineStatusChanged = Notification.Name("contactOnlineStatusChanged") +}