Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Public Chats #57

Merged
merged 19 commits into from
Oct 15, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Pods
Submodule Pods updated from a6c8ea to 68a1e4
8 changes: 4 additions & 4 deletions Signal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
241C6315231F64CE00B4198E /* CGFloat+Rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241C6312231F5F1D00B4198E /* CGFloat+Rounding.swift */; };
241C6316231F64CE00B4198E /* UIColor+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241C6310231F5C4400B4198E /* UIColor+Helper.swift */; };
24A830A22293CD0100F4CAC0 /* LokiP2PServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A830A12293CD0100F4CAC0 /* LokiP2PServer.swift */; };
24BD2609234DA2050008EB0A /* NewPublicChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24BD2608234DA2050008EB0A /* NewPublicChatVC.swift */; };
2AE2882E4C2B96BFFF9EE27C /* Pods_SignalShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F94C85CB0B235DA37F68ED0 /* Pods_SignalShareExtension.framework */; };
3403B95D20EA9527001A1F44 /* OWSContactShareButtonsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */; };
34074F61203D0CBE004596AE /* OWSSounds.m in Sources */ = {isa = PBXBuildFile; fileRef = 34074F5F203D0CBD004596AE /* OWSSounds.m */; };
Expand Down Expand Up @@ -565,7 +566,6 @@
B821F2FA2272CEEE002C88C0 /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B821F2F92272CEEE002C88C0 /* SeedVC.swift */; };
B8258493230FA5E9001B41CB /* ScanQRCodeVC.m in Sources */ = {isa = PBXBuildFile; fileRef = B8258492230FA5E9001B41CB /* ScanQRCodeVC.m */; };
B82584A02315024B001B41CB /* RSSFeedPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B825849F2315024B001B41CB /* RSSFeedPoller.swift */; };
B845B4D4230CD09100D759F0 /* GroupChatPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B845B4D3230CD09000D759F0 /* GroupChatPoller.swift */; };
B846365B22B7418B00AF1514 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */; };
B86BD08123399883000F5AE3 /* QRCodeModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08023399883000F5AE3 /* QRCodeModal.swift */; };
B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; };
Expand Down Expand Up @@ -681,6 +681,7 @@
241C6310231F5C4400B4198E /* UIColor+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Helper.swift"; sourceTree = "<group>"; };
241C6312231F5F1D00B4198E /* CGFloat+Rounding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Rounding.swift"; sourceTree = "<group>"; };
24A830A12293CD0100F4CAC0 /* LokiP2PServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiP2PServer.swift; sourceTree = "<group>"; };
24BD2608234DA2050008EB0A /* NewPublicChatVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPublicChatVC.swift; sourceTree = "<group>"; };
264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalMessaging.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3403B95B20EA9526001A1F44 /* OWSContactShareButtonsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactShareButtonsView.m; sourceTree = "<group>"; };
3403B95C20EA9527001A1F44 /* OWSContactShareButtonsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactShareButtonsView.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1376,7 +1377,6 @@
B8258491230FA5DA001B41CB /* ScanQRCodeVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScanQRCodeVC.h; sourceTree = "<group>"; };
B8258492230FA5E9001B41CB /* ScanQRCodeVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScanQRCodeVC.m; sourceTree = "<group>"; };
B825849F2315024B001B41CB /* RSSFeedPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSSFeedPoller.swift; sourceTree = "<group>"; };
B845B4D3230CD09000D759F0 /* GroupChatPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupChatPoller.swift; sourceTree = "<group>"; };
B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Identicon+ObjC.swift"; sourceTree = "<group>"; };
B86BD08023399883000F5AE3 /* QRCodeModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeModal.swift; sourceTree = "<group>"; };
B86BD08323399ACF000F5AE3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2655,6 +2655,7 @@
B89841E222B7579F00B1BDC6 /* NewConversationVC.swift */,
B8258491230FA5DA001B41CB /* ScanQRCodeVC.h */,
B8258492230FA5E9001B41CB /* ScanQRCodeVC.m */,
24BD2608234DA2050008EB0A /* NewPublicChatVC.swift */,
B8B26C8E234D629C004ED98C /* UserSelectionView.swift */,
B8B26C90234D8CBD004ED98C /* UserSelectionViewDelegate.swift */,
);
Expand Down Expand Up @@ -2705,7 +2706,6 @@
B86BD0892339A278000F5AE3 /* Group Chat */ = {
isa = PBXGroup;
children = (
B845B4D3230CD09000D759F0 /* GroupChatPoller.swift */,
B825849F2315024B001B41CB /* RSSFeedPoller.swift */,
);
path = "Group Chat";
Expand Down Expand Up @@ -3750,7 +3750,6 @@
34A4C62022175C5C0042EF2E /* OnboardingProfileViewController.swift in Sources */,
4505C2BF1E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */,
EF764C351DB67CC5000D9A87 /* UIViewController+Permissions.m in Sources */,
B845B4D4230CD09100D759F0 /* GroupChatPoller.swift in Sources */,
45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */,
34D2CCE0206939B400CB1A14 /* DebugUIMessagesAssetLoader.m in Sources */,
4CEB78C92178EBAB00F315D2 /* OWSSessionResetJobRecord.m in Sources */,
Expand Down Expand Up @@ -3852,6 +3851,7 @@
B821F2F82272CED3002C88C0 /* DisplayNameVC.swift in Sources */,
34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */,
B885D5F62334A32100EE0D8E /* UIView+Constraint.swift in Sources */,
24BD2609234DA2050008EB0A /* NewPublicChatVC.swift in Sources */,
34DBF003206BD5A500025978 /* OWSMessageTextView.m in Sources */,
34D1F0B41F86D31D0066283D /* ConversationCollectionView.m in Sources */,
34B3F8821E8DF1700035BE1A /* NewContactThreadViewController.m in Sources */,
Expand Down
56 changes: 13 additions & 43 deletions Signal/src/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ @interface AppDelegate () <UNUserNotificationCenterDelegate>
// Loki
@property (nonatomic) LKP2PServer *lokiP2PServer;
@property (nonatomic) LKLongPoller *lokiLongPoller;
@property (nonatomic) LKGroupChatPoller *lokiPublicChatPoller;
@property (nonatomic) LKRSSFeedPoller *lokiNewsFeedPoller;
@property (nonatomic) LKRSSFeedPoller *lokiMessengerUpdatesFeedPoller;

Expand Down Expand Up @@ -1525,11 +1524,6 @@ - (void)stopLongPollerIfNeeded
[self.lokiLongPoller stopIfNeeded];
}

- (LKGroupChat *)lokiPublicChat
{
return [[LKGroupChat alloc] initWithServerID:LKGroupChatAPI.publicChatServerID server:LKGroupChatAPI.publicChatServer displayName:NSLocalizedString(@"Loki Public Chat", @"") isDeletable:true];
}

- (LKRSSFeed *)lokiNewsFeed
{
return [[LKRSSFeed alloc] initWithId:@"loki.network.feed" server:@"https://loki.network/feed/" displayName:NSLocalizedString(@"Loki News", @"") isDeletable:true];
Expand All @@ -1542,25 +1536,18 @@ - (LKRSSFeed *)lokiMessengerUpdatesFeed

- (void)createGroupChatsIfNeeded
{
LKGroupChat *publicChat = self.lokiPublicChat;
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *userDefaultsKey = [@"isGroupChatSetUp." stringByAppendingString:publicChat.id];
BOOL isChatSetUp = [NSUserDefaults.standardUserDefaults boolForKey:userDefaultsKey];
if (!isChatSetUp || !publicChat.isDeletable) {
TSGroupModel *group = [[TSGroupModel alloc] initWithTitle:publicChat.displayName memberIds:@[ userHexEncodedPublicKey, publicChat.server ] image:nil groupId:[publicChat.id dataUsingEncoding:NSUTF8StringEncoding]];
__block TSGroupThread *thread;
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
thread = [TSGroupThread getOrCreateThreadWithGroupModel:group transaction:transaction];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
NSCalendar *calendar = NSCalendar.currentCalendar;
[calendar setTimeZone:timeZone];
NSDateComponents *dateComponents = [NSDateComponents new];
[dateComponents setYear:999];
NSDate *date = [calendar dateByAddingComponents:dateComponents toDate:[NSDate new] options:0];
[thread updateWithMutedUntilDate:date transaction:transaction];
}];
[OWSProfileManager.sharedManager addThreadToProfileWhitelist:thread];
[NSUserDefaults.standardUserDefaults setBool:YES forKey:userDefaultsKey];
// Setup our default public chats
for (LKGroupChat *chat in LKGroupChat.defaultChats) {
NSString *userDefaultsKey = [@"isGroupChatSetUp." stringByAppendingString:chat.id];
BOOL isChatSetUp = [NSUserDefaults.standardUserDefaults boolForKey:userDefaultsKey];
if (!isChatSetUp || !chat.isDeletable) {
[LKPublicChatManager.shared addChatWithServer:chat.server channel:chat.channel name:chat.displayName];
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update the display name on the server

[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
TSGroupThread *thread = [TSGroupThread threadWithGroupId:chat.idAsData transaction:transaction];
if (thread != nil) { [OWSProfileManager.sharedManager addThreadToProfileWhitelist:thread]; }
}];
[NSUserDefaults.standardUserDefaults setBool:YES forKey:userDefaultsKey];
}
}
}

Expand Down Expand Up @@ -1590,18 +1577,6 @@ - (void)createRSSFeedsIfNeeded
}
}

- (void)createGroupChatPollersIfNeeded
{
// Only create the group chat pollers if their threads aren't deleted
__block TSGroupThread *thread;
[OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
thread = [TSGroupThread threadWithGroupId:[self.lokiPublicChat.id dataUsingEncoding:NSUTF8StringEncoding] transaction:transaction];
}];
if (thread != nil && self.lokiPublicChatPoller == nil) {
self.lokiPublicChatPoller = [[LKGroupChatPoller alloc] initForGroup:self.lokiPublicChat];
}
}

- (void)createRSSFeedPollersIfNeeded
{
// Only create the RSS feed pollers if their threads aren't deleted
Expand All @@ -1620,8 +1595,7 @@ - (void)createRSSFeedPollersIfNeeded

- (void)startGroupChatPollersIfNeeded
{
[self createGroupChatPollersIfNeeded];
if (self.lokiPublicChatPoller != nil) { [self.lokiPublicChatPoller startIfNeeded]; }
[LKPublicChatManager.shared startPollersIfNeeded];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes the function redundant so let's remove it then

}

- (void)startRSSFeedPollersIfNeeded
Expand All @@ -1635,10 +1609,6 @@ - (void)handleThreadDeleted:(NSNotification *)notification {
NSDictionary *userInfo = notification.userInfo;
NSString *threadID = (NSString *)userInfo[@"threadId"];
if (threadID == nil) { return; }
if ([threadID isEqualToString:[TSGroupThread threadIdFromGroupId:[self.lokiPublicChat.id dataUsingEncoding:NSUTF8StringEncoding]]] && self.lokiPublicChatPoller != nil) {
[self.lokiPublicChatPoller stop];
self.lokiPublicChatPoller = nil;
}
if ([threadID isEqualToString:[TSGroupThread threadIdFromGroupId:[self.lokiNewsFeed.id dataUsingEncoding:NSUTF8StringEncoding]]] && self.lokiNewsFeedPoller != nil) {
[self.lokiNewsFeedPoller stop];
self.lokiNewsFeedPoller = nil;
Expand Down
97 changes: 97 additions & 0 deletions Signal/src/Loki/NewPublicChatVC.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

@objc(LKNewPublicChatVC)
final class NewPublicChatVC : OWSViewController {

// MARK: Components
private lazy var serverUrlTextField: UITextField = {
let result = UITextField()
result.textColor = Theme.primaryColor
result.font = UIFont.ows_dynamicTypeBodyClamped
let placeholder = NSMutableAttributedString(string: NSLocalizedString("Enter a Server URL", comment: ""))
placeholder.addAttribute(.foregroundColor, value: Theme.placeholderColor, range: NSRange(location: 0, length: placeholder.length))
result.attributedPlaceholder = placeholder
result.tintColor = UIColor.lokiGreen()
result.keyboardAppearance = .dark

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would've been nice to also set keyboardType to .URL

return result
}()

private lazy var addButton: OWSFlatButton = {
let addButtonFont = UIFont.ows_dynamicTypeBodyClamped.ows_mediumWeight()
let addButtonHeight = addButtonFont.pointSize * 48 / 17
let addButton = OWSFlatButton.button(title: NSLocalizedString("Add", comment: ""), font: addButtonFont, titleColor: .white, backgroundColor: .lokiGreen(), target: self, selector: #selector(handleNextButtonTapped))
addButton.autoSetDimension(.height, toSize: addButtonHeight)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convention is to not set up constraints here. The reason is that not all constraints can be set up at this point (the view needs to be added as a subview before some of them can be created), so the idea is to wait for that and then set up everything.

return addButton
}()

// MARK: Lifecycle
override func viewDidLoad() {
// Background color & margins
view.backgroundColor = Theme.backgroundColor
view.layoutMargins = .zero
// Navigation bar
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(close))
title = NSLocalizedString("Add Public Chat Server", comment: "")
// Separator
let separator = UIView()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This separator is never added as a subview

separator.autoSetDimension(.height, toSize: 1 / UIScreen.main.scale)
separator.backgroundColor = Theme.hairlineColor

updateButton(enabled: true)

// Stack view
let stackView = UIStackView(arrangedSubviews: [
serverUrlTextField,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An explainer label would be nice

UIView.vStretchingSpacer(),
addButton
])
stackView.axis = .vertical
stackView.alignment = .fill
stackView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
stackView.isLayoutMarginsRelativeArrangement = true
view.addSubview(stackView)
stackView.autoPinWidthToSuperview()
stackView.autoPin(toTopLayoutGuideOf: self, withInset: 0)
autoPinView(toBottomOfViewControllerOrKeyboard: stackView, avoidNotch: true)
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
serverUrlTextField.becomeFirstResponder()
}

// MARK: Interaction
@objc private func close() {
dismiss(animated: true, completion: nil)
}

@objc private func handleNextButtonTapped() {
let serverURL = (serverUrlTextField.text?.trimmingCharacters(in: .whitespaces) ?? "").lowercased().replacingOccurrences(of: "http://", with: "https://")
guard let url = URL(string: serverURL), let scheme = url.scheme, scheme == "https", let _ = url.host else {
showAlert(title: NSLocalizedString("Invalid server URL provided", comment: ""), message: NSLocalizedString("Please make sure you have provided the full url", comment: ""))
return
}

updateButton(enabled: false)

// TODO: Upon adding we should fetch previous messages
LokiPublicChatManager.shared.addChat(server: serverURL, channel: 1)
.done(on: .main) { _ in
self.presentingViewController!.dismiss(animated: true, completion: nil)
nielsandriesse marked this conversation as resolved.
Show resolved Hide resolved

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're capturing self strongly here. This can cause crashes if you're not careful.

}
.catch(on: .main) { e in
self.updateButton(enabled: true)
self.showAlert(title: NSLocalizedString("Failed to connect to server", comment: ""))
}
}

private func showAlert(title: String, message: String = "") {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil))
presentAlert(alert)
}

private func updateButton(enabled: Bool) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be under the interaction mark

addButton.setEnabled(enabled)
addButton.setTitle(enabled ? NSLocalizedString("Add", comment: "") : NSLocalizedString("Connecting to server", comment: ""))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These need to be localized

}
}
16 changes: 12 additions & 4 deletions Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#import "OWSMessageBubbleView.h"
#import "OWSMessageHeaderView.h"
#import "Session-Swift.h"
#import <SignalServiceKit/SignalServiceKit-Swift.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -298,10 +299,17 @@ - (BOOL)updateAvatarView
[self.contentView addSubview:self.avatarView];

if (self.viewItem.isGroupThread && !self.viewItem.isRSSFeed) {
BOOL isModerator = [LKGroupChatAPI isUserModerator:incomingMessage.authorId forGroup:LKGroupChatAPI.publicChatServerID onServer:LKGroupChatAPI.publicChatServer];
UIImage *moderatorIcon = [UIImage imageNamed:@"Crown"];
self.moderatorIconImageView.image = moderatorIcon;
self.moderatorIconImageView.hidden = !isModerator;
__block LKGroupChat *groupChat;
[OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
groupChat = [LKDatabaseUtilities getGroupChatForThreadID:self.viewItem.interaction.uniqueThreadId transaction: transaction];
}];

if (groupChat != nil) {
BOOL isModerator = [LKGroupChatAPI isUserModerator:incomingMessage.authorId forGroup:groupChat.channel onServer:groupChat.server];
UIImage *moderatorIcon = [UIImage imageNamed:@"Crown"];
self.moderatorIconImageView.image = moderatorIcon;
self.moderatorIconImageView.hidden = !isModerator;
}
}

[self.contentView addSubview:self.moderatorIconImageView];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import <SignalMessaging/UIView+OWS.h>
#import <SignalServiceKit/TSAttachmentStream.h>
#import <SignalServiceKit/TSMessage.h>
#import <SignalServiceKit/SignalServiceKit-Swift.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -553,9 +554,12 @@ - (UILabel *)configureQuotedAuthorLabel

if (quotedAuthor == self.quotedMessage.authorId) {
[OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
NSString *collection = [NSString stringWithFormat:@"%@.%@", LKGroupChatAPI.publicChatServer, @(LKGroupChatAPI.publicChatServerID)];
NSString *displayName = [transaction stringForKey:self.quotedMessage.authorId inCollection:collection];
if (displayName != nil) { quotedAuthor = displayName; }
LKGroupChat *chat = [LKDatabaseUtilities getGroupChatForThreadID:self.quotedMessage.threadId transaction:transaction];
if (chat != nil) {
NSString *collection = [NSString stringWithFormat:@"%@.%@", chat.server, @(chat.channel)];
NSString *displayName = [transaction stringForKey:self.quotedMessage.authorId inCollection:collection];
if (displayName != nil) { quotedAuthor = displayName; }
}
}];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,7 @@ - (void)populateReplyForViewItem:(id<ConversationViewItem>)conversationItem
__block OWSQuotedReplyModel *quotedReply;
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
quotedReply = [OWSQuotedReplyModel quotedReplyForSendingWithConversationViewItem:conversationItem
threadId:conversationItem.interaction.uniqueThreadId
transaction:transaction];
}];

Expand Down
Loading