Implement group member count, fix QR code scanning & clean

This commit is contained in:
Niels Andriesse 2020-01-22 09:53:29 +11:00
parent 0f22b4b36c
commit 7cfd43ff6b
11 changed files with 117 additions and 36 deletions

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "SESSION_ICON_WHT.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,5 +1,6 @@
@objc final class ConversationTitleView : UIView {
@objc(LKConversationTitleView)
final class ConversationTitleView : UIView {
private let thread: TSThread
private var currentStatus: Status? { didSet { updateSubtitleForCurrentStatus() } }
@ -141,7 +142,7 @@
self.currentStatus = nil
}
private func updateSubtitleForCurrentStatus() {
@objc func updateSubtitleForCurrentStatus() {
DispatchQueue.main.async {
self.subtitleLabel.isHidden = false
switch self.currentStatus {
@ -159,13 +160,29 @@
dateFormatter.timeStyle = .medium
dateFormatter.dateStyle = .medium
subtitle.append(NSAttributedString(string: "Muted until " + dateFormatter.string(from: muteEndDate)))
} else if self.thread.isGroupThread() {
subtitle.append(NSAttributedString(string: "26 members")) // TODO: Implement
} else if self.thread.isGroupThread() && !(self.thread as! TSGroupThread).isRSSFeed {
let storage = OWSPrimaryStorage.shared()
var userCount: Int?
storage.dbReadConnection.readWrite { transaction in
if let publicChat = LokiDatabaseUtilities.getPublicChat(for: self.thread.uniqueId!, in: transaction) {
userCount = storage.getUserCount(for: publicChat, in: transaction)
}
}
if let userCount = userCount {
if userCount > 2500 {
subtitle.append(NSAttributedString(string: "2500+ members"))
} else {
subtitle.append(NSAttributedString(string: "\(userCount) members"))
}
} else {
self.subtitleLabel.isHidden = true
}
} else {
self.subtitleLabel.isHidden = true
}
self.subtitleLabel.attributedText = subtitle
}
self.titleLabel.font = .boldSystemFont(ofSize: self.subtitleLabel.isHidden ? Values.veryLargeFontSize : Values.mediumFontSize)
}
}

View File

@ -326,6 +326,9 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat
thread.remove(with: transaction)
}
NotificationCenter.default.post(name: .threadDeleted, object: nil, userInfo: [ "threadId" : thread.uniqueId! ])
if let publicChat = publicChat {
let _ = LokiPublicChatAPI.leave(publicChat.channel, on: publicChat.server)
}
})
alert.addAction(UIAlertAction(title: NSLocalizedString("TXT_CANCEL_TITLE", comment: ""), style: .default) { _ in })
guard let self = self else { return }

View File

@ -153,6 +153,7 @@ final class JoinPublicChatVC : UIViewController, UIPageViewControllerDataSource,
.done(on: .main) { [weak self] _ in
let _ = LokiPublicChatAPI.getMessages(for: channelID, on: urlAsString)
let _ = LokiPublicChatAPI.setDisplayName(to: displayName, on: urlAsString)
let _ = LokiPublicChatAPI.join(channelID, on: urlAsString)
self?.presentingViewController!.dismiss(animated: true, completion: nil)
}
.catch(on: .main) { [weak self] _ in

View File

@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (atomic) ZXCapture *capture;
@property (nonatomic) BOOL captureEnabled;
@property (nonatomic) UIView *maskingView;
@property (nonatomic) dispatch_queue_t captureQueue;
@end
@ -34,6 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
}
_captureEnabled = NO;
_captureQueue = dispatch_get_main_queue();
return self;
}
@ -46,6 +48,7 @@ NS_ASSUME_NONNULL_BEGIN
}
_captureEnabled = NO;
_captureQueue = dispatch_get_main_queue();
return self;
}
@ -102,7 +105,7 @@ NS_ASSUME_NONNULL_BEGIN
{
self.captureEnabled = YES;
if (!self.capture) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(self.captureQueue, ^{
self.capture = [[ZXCapture alloc] init];
// self.capture.invert = YES;
self.capture.camera = self.capture.back;
@ -124,7 +127,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)stopCapture
{
self.captureEnabled = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(self.captureQueue, ^{
[self.capture stop];
});
}

View File

@ -160,7 +160,7 @@ typedef enum : NSUInteger {
@property (nonatomic, nullable) NSTimer *readTimer;
@property (nonatomic) NSCache *cellMediaCache;
@property (nonatomic) ConversationTitleView *headerView;
@property (nonatomic) LKConversationTitleView *headerView;
@property (nonatomic, nullable) UIView *bannerView;
@property (nonatomic, nullable) OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
@ -662,6 +662,19 @@ typedef enum : NSUInteger {
UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"Gear"] style:UIBarButtonItemStylePlain target:self action:@selector(showConversationSettings)];
settingsButton.tintColor = LKColors.text;
self.navigationItem.rightBarButtonItem = settingsButton;
if (self.thread.isGroupThread) {
TSGroupThread *thread = (TSGroupThread *)self.thread;
if (thread.isRSSFeed) { return; }
__block LKPublicChat *publicChat;
[OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
publicChat = [LKDatabaseUtilities getPublicChatForThreadID:thread.uniqueId transaction:transaction];
}];
[LKPublicChatAPI getUserCountForGroup:publicChat.channel onServer:publicChat.server]
.thenOn(dispatch_get_main_queue(), ^(id userCount) {
[self.headerView updateSubtitleForCurrentStatus];
});
}
}
- (void)createContents
@ -1410,7 +1423,7 @@ typedef enum : NSUInteger {
- (void)createHeaderViews
{
ConversationTitleView *headerView = [[ConversationTitleView alloc] initWithThread:self.thread];
LKConversationTitleView *headerView = [[LKConversationTitleView alloc] initWithThread:self.thread];
self.headerView = headerView;
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, headerView);

View File

@ -12,15 +12,6 @@ public final class ProfilePictureView : UIView {
private lazy var imageView = getImageView()
private lazy var additionalImageView = getImageView()
private lazy var rssLabel: UILabel = {
let result = UILabel()
result.textColor = UIColor(rgbHex: 0xFFFFFF) // Colors.text
result.font = .systemFont(ofSize: 13) // Values.smallFontSize
result.textAlignment = .center
result.text = "RSS"
return result
}()
// MARK: Lifecycle
public override init(frame: CGRect) {
super.init(frame: frame)
@ -45,12 +36,6 @@ public final class ProfilePictureView : UIView {
additionalImageView.set(.width, to: additionalImageViewSize)
additionalImageView.set(.height, to: additionalImageViewSize)
additionalImageView.layer.cornerRadius = additionalImageViewSize / 2
// Set up RSS label
addSubview(rssLabel)
rssLabel.pin(.leading, to: .leading, of: self)
rssLabel.pin(.top, to: .top, of: self)
rssLabel.autoPinWidth(toWidthOf: imageView)
rssLabel.autoPinHeight(toHeightOf: imageView)
}
// MARK: Updating
@ -80,8 +65,10 @@ public final class ProfilePictureView : UIView {
imageView.image = isRSSFeed ? nil : getProfilePicture(of: size, for: hexEncodedPublicKey)
imageView.backgroundColor = isRSSFeed ? UIColor(rgbHex: 0x353535) : UIColor(rgbHex: 0xD8D8D8) // UIColor(rgbHex: 0xD8D8D8) = Colors.unimportant
imageView.layer.cornerRadius = size / 2
rssLabel.isHidden = !isRSSFeed
rssLabel.font = size == (75) ? .systemFont(ofSize: 20) : .systemFont(ofSize: 13) // Values.largeProfilePictureSize / Values.largeFontSize / Values.smallFontSize
imageView.contentMode = isRSSFeed ? .center : .scaleAspectFit
if isRSSFeed {
imageView.image = #imageLiteral(resourceName: "SessionWhite").resizedImage(to: CGSize(width: (303*24)/337, height: 24))
}
}
// MARK: Convenience

View File

@ -242,6 +242,49 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
}
}
public static func join(_ channel: UInt64, on server: String) -> Promise<Void> {
return getAuthToken(for: server).then(on: DispatchQueue.global()) { token -> Promise<Void> in
let url = URL(string: "\(server)/channels/\(channel)/subscribe")!
let request = TSRequest(url: url, method: "POST", parameters: [:])
request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ]
return TSNetworkManager.shared().perform(request, withCompletionQueue: DispatchQueue.global()).done(on: DispatchQueue.global()) { result -> Void in
print("[Loki] Joined channel with ID: \(channel) on server: \(server).")
}.retryingIfNeeded(maxRetryCount: maxRetryCount)
}
}
public static func leave(_ channel: UInt64, on server: String) -> Promise<Void> {
return getAuthToken(for: server).then(on: DispatchQueue.global()) { token -> Promise<Void> in
let url = URL(string: "\(server)/channels/\(channel)/subscribe")!
let request = TSRequest(url: url, method: "DELETE", parameters: [:])
request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ]
return TSNetworkManager.shared().perform(request, withCompletionQueue: DispatchQueue.global()).done(on: DispatchQueue.global()) { result -> Void in
print("[Loki] Left channel with ID: \(channel) on server: \(server).")
}.retryingIfNeeded(maxRetryCount: maxRetryCount)
}
}
public static func getUserCount(for channel: UInt64, on server: String) -> Promise<Int> {
return getAuthToken(for: server).then(on: DispatchQueue.global()) { token -> Promise<Int> in
let queryParameters = "count=2500"
let url = URL(string: "\(server)/channels/\(channel)/subscribers?\(queryParameters)")!
let request = TSRequest(url: url)
request.allHTTPHeaderFields = [ "Content-Type" : "application/json", "Authorization" : "Bearer \(token)" ]
return TSNetworkManager.shared().perform(request, withCompletionQueue: DispatchQueue.global()).map { $0.responseObject }.map { rawResponse in
guard let json = rawResponse as? JSON, let users = json["data"] as? [JSON] else {
print("[Loki] Couldn't parse user count for public chat channel with ID: \(channel) on server: \(server) from: \(rawResponse).")
throw Error.parsingFailed
}
let userCount = users.count
let storage = OWSPrimaryStorage.shared()
storage.dbReadWriteConnection.readWrite { transaction in
storage.setUserCount(userCount, forPublicChatWithID: "\(server).\(channel)", in: transaction)
}
return userCount
}
}
}
public static func getDisplayNames(for channel: UInt64, on server: String) -> Promise<Void> {
let publicChatID = "\(server).\(channel)"
guard let hexEncodedPublicKeys = displayNameUpdatees[publicChatID] else { return Promise.value(()) }
@ -344,6 +387,11 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
return AnyPromise.from(deleteMessage(with: messageID, for: group, on: server, isSentByUser: isSentByUser))
}
@objc(getUserCountForGroup:onServer:)
public static func objc_getUserCount(for group: UInt64, on server: String) -> AnyPromise {
return AnyPromise.from(getUserCount(for: group, on: server))
}
@objc(setDisplayName:on:)
public static func objc_setDisplayName(to newDisplayName: String?, on server: String) -> AnyPromise {
return AnyPromise.from(setDisplayName(to: newDisplayName, on: server))

View File

@ -71,17 +71,6 @@ public final class LokiPublicChatManager : NSObject {
// Store the group chat mapping
self.storage.dbReadWriteConnection.readWrite { transaction in
let thread = TSGroupThread.getOrCreateThread(with: model, transaction: transaction)
// Mute the thread
if let utc = TimeZone(identifier: "UTC") {
var calendar = Calendar.current
calendar.timeZone = utc
var dateComponents = DateComponents()
dateComponents.setValue(999, for: .year)
if let date = calendar.date(byAdding: dateComponents, to: Date()) {
thread.updateWithMuted(until: date, transaction: transaction)
}
}
// Save the group chat
LokiDatabaseUtilities.setPublicChat(chat, for: thread.uniqueId!, in: transaction)

View File

@ -51,4 +51,12 @@ public extension OWSPrimaryStorage {
public func getMasterHexEncodedPublicKey(for slaveHexEncodedPublicKey: String, in transaction: YapDatabaseReadTransaction) -> String? {
return getDeviceLink(for: slaveHexEncodedPublicKey, in: transaction)?.master.hexEncodedPublicKey
}
public func getUserCount(for publicChat: LokiPublicChat, in transaction: YapDatabaseReadTransaction) -> Int? {
return transaction.object(forKey: publicChat.id, inCollection: "LokiPublicChatUserCountCollection") as? Int
}
public func setUserCount(_ userCount: Int, forPublicChatWithID publicChatID: String, in transaction: YapDatabaseReadWriteTransaction) {
transaction.setObject(userCount, forKey: publicChatID, inCollection: "LokiPublicChatUserCountCollection")
}
}