This commit is contained in:
Niels Andriesse 2019-08-27 16:48:53 +10:00
parent b61b440063
commit e21cced9bb
10 changed files with 177 additions and 124 deletions

View File

@ -562,6 +562,7 @@
B821F2FA2272CEEE002C88C0 /* SeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B821F2F92272CEEE002C88C0 /* SeedViewController.swift */; };
B825848B230F94FE001B41CB /* QRCodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B825848A230F94FE001B41CB /* QRCodeViewController.swift */; };
B8258493230FA5E9001B41CB /* ScanQRCodeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B8258492230FA5E9001B41CB /* ScanQRCodeViewController.m */; };
B82584A02315024B001B41CB /* LokiRSSFeedPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B825849F2315024B001B41CB /* LokiRSSFeedPoller.swift */; };
B845B4D4230CD09100D759F0 /* LokiGroupChatPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B845B4D3230CD09000D759F0 /* LokiGroupChatPoller.swift */; };
B846365B22B7418B00AF1514 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */; };
B89841E322B7579F00B1BDC6 /* NewConversationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B89841E222B7579F00B1BDC6 /* NewConversationViewController.swift */; };
@ -1355,6 +1356,7 @@
B825848A230F94FE001B41CB /* QRCodeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeViewController.swift; sourceTree = "<group>"; };
B8258491230FA5DA001B41CB /* ScanQRCodeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScanQRCodeViewController.h; sourceTree = "<group>"; };
B8258492230FA5E9001B41CB /* ScanQRCodeViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScanQRCodeViewController.m; sourceTree = "<group>"; };
B825849F2315024B001B41CB /* LokiRSSFeedPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiRSSFeedPoller.swift; sourceTree = "<group>"; };
B845B4D3230CD09000D759F0 /* LokiGroupChatPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiGroupChatPoller.swift; sourceTree = "<group>"; };
B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Identicon+ObjC.swift"; sourceTree = "<group>"; };
B89841E222B7579F00B1BDC6 /* NewConversationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationViewController.swift; sourceTree = "<group>"; };
@ -2620,6 +2622,7 @@
B821F2F92272CEEE002C88C0 /* SeedViewController.swift */,
24A830A12293CD0100F4CAC0 /* LokiP2PServer.swift */,
B845B4D3230CD09000D759F0 /* LokiGroupChatPoller.swift */,
B825849F2315024B001B41CB /* LokiRSSFeedPoller.swift */,
B825848A230F94FE001B41CB /* QRCodeViewController.swift */,
B8258491230FA5DA001B41CB /* ScanQRCodeViewController.h */,
B8258492230FA5E9001B41CB /* ScanQRCodeViewController.m */,
@ -3674,6 +3677,7 @@
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */,
4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */,
3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */,
B82584A02315024B001B41CB /* LokiRSSFeedPoller.swift in Sources */,
24A830A22293CD0100F4CAC0 /* LokiP2PServer.swift in Sources */,
349ED990221B0194008045B0 /* Onboarding2FAViewController.swift in Sources */,
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */,

View File

@ -9,6 +9,8 @@ extern NSString *const AppDelegateStoryboardMain;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
- (void)createGroupChatsIfNeeded;
- (void)createRSSFeedsIfNeeded;
- (void)startGroupChatPollersIfNeeded;
- (void)startRSSFeedPollersIfNeeded;
@end

View File

@ -65,8 +65,8 @@ static NSTimeInterval launchStartedAt;
@property (nonatomic) BOOL didAppLaunchFail;
@property (nonatomic) LKP2PServer *lokiP2PServer;
@property (nonatomic) LKGroupChatPoller *lokiPublicChatPoller;
@property (nonatomic) LKGroupChatPoller *lokiNewsPoller;
@property (nonatomic) LKGroupChatPoller *lokiMessengerUpdatesPoller;
@property (nonatomic) LKRSSFeedPoller *lokiNewsFeedPoller;
@property (nonatomic) LKRSSFeedPoller *lokiMessengerUpdatesFeedPoller;
@end
@ -1489,28 +1489,52 @@ static NSTimeInterval launchStartedAt;
- (LKGroupChat *)lokiPublicChat
{
return [[LKGroupChat alloc] initWithKindAsString:@"publicChat" id:@(LKGroupChatAPI.publicChatID).stringValue server:LKGroupChatAPI.publicChatServer displayName:NSLocalizedString(@"Loki Public Chat", @"") isDeletable:true];
return [[LKGroupChat alloc] initWithServerID:@(LKGroupChatAPI.publicChatServerID).unsignedIntegerValue server:LKGroupChatAPI.publicChatServer displayName:NSLocalizedString(@"Loki Public Chat", @"") isDeletable:true];
}
- (LKGroupChat *)lokiNews
- (LKRSSFeed *)lokiNewsFeed
{
return [[LKGroupChat alloc] initWithKindAsString:@"rss" id:@"loki.network.feed" server:@"https://loki.network/feed/" displayName:NSLocalizedString(@"Loki News", @"") isDeletable:true];
return [[LKRSSFeed alloc] initWithId:@"loki.network.feed" server:@"https://loki.network/feed/" displayName:NSLocalizedString(@"Loki News", @"") isDeletable:true];
}
- (LKGroupChat *)lokiMessengerUpdates
- (LKRSSFeed *)lokiMessengerUpdatesFeed
{
return [[LKGroupChat alloc] initWithKindAsString:@"rss" id:@"loki.network.messenger-update" server:@"https://loki.network/category/messenger-updates/feed/" displayName:NSLocalizedString(@"Loki Messenger Updates", @"") isDeletable:false];
return [[LKRSSFeed alloc] initWithId:@"loki.network.messenger-updates" server:@"https://loki.network/category/messenger-updates/feed/" displayName:NSLocalizedString(@"Loki Messenger Updates", @"") isDeletable:false];
}
- (void)createGroupChatsIfNeeded
{
NSArray *allGroupChats = @[ self.lokiPublicChat, self.lokiNews, self.lokiMessengerUpdates ];
LKGroupChat *publicChat = self.lokiPublicChat;
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
for (LKGroupChat *chat in allGroupChats) {
NSString *userDefaultsKey = [@"isSetUp." stringByAppendingString:chat.id];
BOOL isChatSetUp = [NSUserDefaults.standardUserDefaults boolForKey:userDefaultsKey];
if (!isChatSetUp || !chat.isDeletable) {
TSGroupModel *group = [[TSGroupModel alloc] initWithTitle:chat.displayName memberIds:@[ userHexEncodedPublicKey, chat.server ] image:nil groupId:[chat.id dataUsingEncoding:NSUTF8StringEncoding]];
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];
}
}
- (void)createRSSFeedsIfNeeded
{
NSArray *feeds = @[ self.lokiNewsFeed, self.lokiMessengerUpdatesFeed ];
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
for (LKRSSFeed *feed in feeds) {
NSString *userDefaultsKey = [@"isRSSFeedSetUp." stringByAppendingString:feed.id];
BOOL isFeedSetUp = [NSUserDefaults.standardUserDefaults boolForKey:userDefaultsKey];
if (!isFeedSetUp || !feed.isDeletable) {
TSGroupModel *group = [[TSGroupModel alloc] initWithTitle:feed.displayName memberIds:@[ userHexEncodedPublicKey, feed.server ] image:nil groupId:[feed.id dataUsingEncoding:NSUTF8StringEncoding]];
__block TSGroupThread *thread;
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
thread = [TSGroupThread getOrCreateThreadWithGroupModel:group transaction:transaction];
@ -1531,16 +1555,25 @@ static NSTimeInterval launchStartedAt;
- (void)createGroupChatPollersIfNeeded
{
if (self.lokiPublicChatPoller == nil) { self.lokiPublicChatPoller = [[LKGroupChatPoller alloc] initForGroup:self.lokiPublicChat]; }
if (self.lokiNewsPoller == nil) { self.lokiNewsPoller = [[LKGroupChatPoller alloc] initForGroup:self.lokiNews]; }
if (self.lokiMessengerUpdatesPoller == nil) { self.lokiMessengerUpdatesPoller = [[LKGroupChatPoller alloc] initForGroup:self.lokiMessengerUpdates]; }
}
- (void)createRSSFeedPollersIfNeeded
{
if (self.lokiNewsFeedPoller == nil) { self.lokiNewsFeedPoller = [[LKRSSFeedPoller alloc] initForFeed:self.lokiNewsFeed]; }
if (self.lokiMessengerUpdatesFeedPoller == nil) { self.lokiMessengerUpdatesFeedPoller = [[LKRSSFeedPoller alloc] initForFeed:self.lokiMessengerUpdatesFeed]; }
}
- (void)startGroupChatPollersIfNeeded
{
[self createGroupChatPollersIfNeeded];
[self.lokiPublicChatPoller startIfNeeded];
[self.lokiNewsPoller startIfNeeded];
[self.lokiMessengerUpdatesPoller startIfNeeded];
}
- (void)startRSSFeedPollersIfNeeded
{
[self createRSSFeedPollersIfNeeded];
[self.lokiNewsFeedPoller startIfNeeded];
[self.lokiMessengerUpdatesFeedPoller startIfNeeded];
}
@end

View File

@ -1,6 +1,3 @@
import FeedKit
// TODO: Move the RSS feed logic into its own file
@objc(LKGroupChatPoller)
public final class LokiGroupChatPoller : NSObject {
@ -9,19 +6,8 @@ public final class LokiGroupChatPoller : NSObject {
private var pollForDeletedMessagesTimer: Timer? = nil
private var hasStarted = false
private lazy var pollForNewMessagesInterval: TimeInterval = {
switch group.kind {
case .publicChat(_): return 4
case .rss(_): return 8 * 60
}
}()
private lazy var pollForDeletedMessagesInterval: TimeInterval = {
switch group.kind {
case .publicChat(_): return 32 * 60
case .rss(_): preconditionFailure()
}
}()
private let pollForNewMessagesInterval: TimeInterval = 4
private let pollForDeletedMessagesInterval: TimeInterval = 32 * 60
@objc(initForGroup:)
public init(for group: LokiGroupChat) {
@ -33,9 +19,7 @@ public final class LokiGroupChatPoller : NSObject {
if hasStarted { return }
pollForNewMessagesTimer = Timer.scheduledTimer(withTimeInterval: pollForNewMessagesInterval, repeats: true) { [weak self] _ in self?.pollForNewMessages() }
pollForNewMessages() // Perform initial update
if group.isPublicChat {
pollForDeletedMessagesTimer = Timer.scheduledTimer(withTimeInterval: pollForDeletedMessagesInterval, repeats: true) { [weak self] _ in self?.pollForDeletedMessages() }
}
pollForDeletedMessagesTimer = Timer.scheduledTimer(withTimeInterval: pollForDeletedMessagesInterval, repeats: true) { [weak self] _ in self?.pollForDeletedMessages() }
hasStarted = true
}
@ -47,57 +31,27 @@ public final class LokiGroupChatPoller : NSObject {
private func pollForNewMessages() {
let group = self.group
func parseGroupMessage(body: String, timestamp: UInt64, senderDisplayName: String) {
let id = group.id.data(using: String.Encoding.utf8)!
let x1 = SSKProtoGroupContext.builder(id: id, type: .deliver)
x1.setName(group.displayName)
let x2 = SSKProtoDataMessage.builder()
x2.setTimestamp(timestamp)
x2.setGroup(try! x1.build())
x2.setBody(body)
let x3 = SSKProtoContent.builder()
x3.setDataMessage(try! x2.build())
let x4 = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: timestamp)
x4.setSource(senderDisplayName)
x4.setSourceDevice(OWSDevicePrimaryDeviceId)
x4.setContent(try! x3.build().serializedData())
OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite { transaction in
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! x4.build(), plaintextData: try! x3.build().serializedData(), wasReceivedByUD: false, transaction: transaction)
}
}
switch group.kind {
case .publicChat(let id):
let _ = LokiGroupChatAPI.getMessages(for: id, on: group.server).done { messages in
messages.reversed().forEach { message in
let senderHexEncodedPublicKey = message.hexEncodedPublicKey
let endIndex = senderHexEncodedPublicKey.endIndex
let cutoffIndex = senderHexEncodedPublicKey.index(endIndex, offsetBy: -8)
let senderDisplayName = "\(message.displayName) (...\(senderHexEncodedPublicKey[cutoffIndex..<endIndex]))"
parseGroupMessage(body: message.body, timestamp: message.timestamp, senderDisplayName: senderDisplayName)
}
}
case .rss(_):
let url = URL(string: group.server)!
FeedParser(URL: url).parseAsync { wrapper in
guard case .rss(let feed) = wrapper, let items = feed.items else { return print("[Loki] Failed to parse RSS feed for: \(group.server)") }
items.reversed().forEach { item in
guard let title = item.title, let description = item.description, let date = item.pubDate else { return }
let timestamp = UInt64(date.timeIntervalSince1970 * 1000)
let regex = try! NSRegularExpression(pattern: "<a\\s+(?:[^>]*?\\s+)?href=\"([^\"]*)\".*?>(.*?)<.*?\\/a>")
var bodyAsHTML = "<b>\(title)</b>\(description)"
while true {
guard let match = regex.firstMatch(in: bodyAsHTML, options: [], range: NSRange(location: 0, length: bodyAsHTML.utf16.count)) else { break }
let matchRange = match.range(at: 0)
let urlRange = match.range(at: 1)
let descriptionRange = match.range(at: 2)
let url = (bodyAsHTML as NSString).substring(with: urlRange)
let description = (bodyAsHTML as NSString).substring(with: descriptionRange)
bodyAsHTML = (bodyAsHTML as NSString).replacingCharacters(in: matchRange, with: "\(description) (\(url))") as String
}
guard let bodyAsData = bodyAsHTML.data(using: String.Encoding.unicode) else { return }
let options = [ NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html ]
guard let body = try? NSAttributedString(data: bodyAsData, options: options, documentAttributes: nil) else { return }
parseGroupMessage(body: body.string, timestamp: timestamp, senderDisplayName: NSLocalizedString("Loki", comment: ""))
let _ = LokiGroupChatAPI.getMessages(for: group.serverID, on: group.server).done { messages in
messages.reversed().forEach { message in
let senderHexEncodedPublicKey = message.hexEncodedPublicKey
let endIndex = senderHexEncodedPublicKey.endIndex
let cutoffIndex = senderHexEncodedPublicKey.index(endIndex, offsetBy: -8)
let senderDisplayName = "\(message.displayName) (...\(senderHexEncodedPublicKey[cutoffIndex..<endIndex]))"
let id = group.id.data(using: String.Encoding.utf8)!
let x1 = SSKProtoGroupContext.builder(id: id, type: .deliver)
x1.setName(group.displayName)
let x2 = SSKProtoDataMessage.builder()
x2.setTimestamp(message.timestamp)
x2.setGroup(try! x1.build())
x2.setBody(message.body)
let x3 = SSKProtoContent.builder()
x3.setDataMessage(try! x2.build())
let x4 = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: message.timestamp)
x4.setSource(senderDisplayName)
x4.setSourceDevice(OWSDevicePrimaryDeviceId)
x4.setContent(try! x3.build().serializedData())
OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite { transaction in
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! x4.build(), plaintextData: try! x3.build().serializedData(), wasReceivedByUD: false, transaction: transaction)
}
}
}

View File

@ -0,0 +1,70 @@
import FeedKit
@objc(LKRSSFeedPoller)
public final class LokiRSSFeedPoller : NSObject {
private let feed: LokiRSSFeed
private var timer: Timer? = nil
private var hasStarted = false
private let interval: TimeInterval = 8 * 60
@objc(initForFeed:)
public init(for feed: LokiRSSFeed) {
self.feed = feed
super.init()
}
@objc public func startIfNeeded() {
if hasStarted { return }
timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { [weak self] _ in self?.poll() }
poll() // Perform initial update
hasStarted = true
}
@objc public func stop() {
timer?.invalidate()
hasStarted = false
}
private func poll() {
let feed = self.feed
let url = URL(string: feed.server)!
FeedParser(URL: url).parseAsync { wrapper in
guard case .rss(let x) = wrapper, let items = x.items else { return print("[Loki] Failed to parse RSS feed for: \(feed.server).") }
items.reversed().forEach { item in
guard let title = item.title, let description = item.description, let date = item.pubDate else { return }
let timestamp = UInt64(date.timeIntervalSince1970 * 1000)
let urlRegex = try! NSRegularExpression(pattern: "<a\\s+(?:[^>]*?\\s+)?href=\"([^\"]*)\".*?>(.*?)<.*?\\/a>")
var bodyAsHTML = "\(title)<br>\(description)"
while true {
guard let match = urlRegex.firstMatch(in: bodyAsHTML, options: [], range: NSRange(location: 0, length: bodyAsHTML.utf16.count)) else { break }
let matchRange = match.range(at: 0)
let urlRange = match.range(at: 1)
let descriptionRange = match.range(at: 2)
let url = (bodyAsHTML as NSString).substring(with: urlRange)
let description = (bodyAsHTML as NSString).substring(with: descriptionRange)
bodyAsHTML = (bodyAsHTML as NSString).replacingCharacters(in: matchRange, with: "\(description) (\(url))") as String
}
guard let bodyAsData = bodyAsHTML.data(using: String.Encoding.unicode) else { return }
let options = [ NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html ]
guard let body = try? NSAttributedString(data: bodyAsData, options: options, documentAttributes: nil).string else { return }
let id = feed.id.data(using: String.Encoding.utf8)!
let x1 = SSKProtoGroupContext.builder(id: id, type: .deliver)
x1.setName(feed.displayName)
let x2 = SSKProtoDataMessage.builder()
x2.setTimestamp(timestamp)
x2.setGroup(try! x1.build())
x2.setBody(body)
let x3 = SSKProtoContent.builder()
x3.setDataMessage(try! x2.build())
let x4 = SSKProtoEnvelope.builder(type: .ciphertext, timestamp: timestamp)
x4.setSource(NSLocalizedString("Loki", comment: ""))
x4.setSourceDevice(OWSDevicePrimaryDeviceId)
x4.setContent(try! x3.build().serializedData())
OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite { transaction in
SSKEnvironment.shared.messageManager.throws_processEnvelope(try! x4.build(), plaintextData: try! x3.build().serializedData(), wasReceivedByUD: false, transaction: transaction)
}
}
}
}
}

View File

@ -693,7 +693,9 @@ typedef NS_ENUM(NSInteger, HomeViewControllerSection) {
if (OWSIdentityManager.sharedManager.identityKeyPair != nil) {
AppDelegate *appDelegate = (AppDelegate *)UIApplication.sharedApplication.delegate;
[appDelegate createGroupChatsIfNeeded];
[appDelegate createRSSFeedsIfNeeded];
[appDelegate startGroupChatPollersIfNeeded];
[appDelegate startRSSFeedPollersIfNeeded];
}
}

View File

@ -1,48 +1,19 @@
@objc(LKGroupChat)
public final class LokiGroupChat : NSObject {
public let kind: Kind
@objc public let id: String
@objc public let serverID: UInt
@objc public let server: String
@objc public let displayName: String
@objc public let isDeletable: Bool
@objc public var id: String {
switch kind {
case .publicChat(let id): return "\(server).\(id)"
case .rss(let customID): return "rss://\(customID)"
}
}
// MARK: Convenience
@objc public var isPublicChat: Bool {
if case .publicChat(_) = kind { return true } else { return false }
}
@objc public var isRSS: Bool {
if case .rss(_) = kind { return true } else { return false }
}
// MARK: Kind
public enum Kind { case publicChat(id: UInt), rss(customID: String) }
// MARK: Initialization
public init(kind: Kind, server: String, displayName: String, isDeletable: Bool) {
self.kind = kind
@objc public init(serverID: UInt, server: String, displayName: String, isDeletable: Bool) {
self.id = "\(server).\(serverID)"
self.serverID = serverID
self.server = server
self.displayName = displayName
self.isDeletable = isDeletable
}
@objc public convenience init(kindAsString: String, id: String, server: String, displayName: String, isDeletable: Bool) {
let kind: Kind
switch kindAsString {
case "publicChat": kind = .publicChat(id: UInt(id)!)
case "rss": kind = .rss(customID: id)
default: preconditionFailure()
}
self.init(kind: kind, server: server, displayName: displayName, isDeletable: isDeletable)
}
// MARK: Description
override public var description: String { return "\(id) (\(displayName))" }
override public var description: String { return displayName }
}

View File

@ -11,7 +11,7 @@ public final class LokiGroupChatAPI : NSObject {
// MARK: Public Chat
@objc public static let publicChatServer = "https://chat.lokinet.org"
@objc public static let publicChatMessageType = "network.loki.messenger.publicChat"
@objc public static let publicChatID = 1
@objc public static let publicChatServerID = 1
// MARK: Convenience
private static var userDisplayName: String {

View File

@ -0,0 +1,17 @@
@objc(LKRSSFeed)
public final class LokiRSSFeed : NSObject {
@objc public let id: String
@objc public let server: String
@objc public let displayName: String
@objc public let isDeletable: Bool
@objc public init(id: String, server: String, displayName: String, isDeletable: Bool) {
self.id = id
self.server = server
self.displayName = displayName
self.isDeletable = isDeletable
}
override public var description: String { return displayName }
}

View File

@ -1114,7 +1114,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSString *displayName = SSKEnvironment.shared.profileManager.localProfileName;
if (displayName == nil) { displayName = @"Anonymous"; }
LKGroupMessage *groupMessage = [[LKGroupMessage alloc] initWithHexEncodedPublicKey:userHexEncodedPublicKey displayName:displayName body:message.body type:LKGroupChatAPI.publicChatMessageType timestamp:message.timestamp];
[[LKGroupChatAPI sendMessage:groupMessage toGroup:LKGroupChatAPI.publicChatID onServer:LKGroupChatAPI.publicChatServer]
[[LKGroupChatAPI sendMessage:groupMessage toGroup:LKGroupChatAPI.publicChatServerID onServer:LKGroupChatAPI.publicChatServer]
.thenOn(OWSDispatch.sendingQueue, ^(id result) {
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:false wasSentByWebsocket:false];
})