Signal-iOS/Signal/src/ViewControllers/DebugUI/DebugUIScreenshots.swift
2021-03-25 09:24:27 -03:00

1134 lines
81 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
#if DEBUG
public extension DebugUIScreenshots {
@objc
class func deleteAllThreads() {
databaseStorage.write { transaction in
TSInteraction.anyRemoveAllWithoutInstantation(transaction: transaction)
TSAttachment.anyRemoveAllWithoutInstantation(transaction: transaction)
TSThread.anyRemoveAllWithoutInstantation(transaction: transaction)
}
}
@objc
class func makeThreadsForScreenshots() {
// Get the address of the local user.
guard let localAddress = tsAccountManager.localAddress else {
owsFailDebug("missing local address")
return
}
databaseStorage.asyncWrite { transaction in
// Time to start
// Modify the macOS system clock to "set" this to a specific time
let startingDateMS = Date.ows_millisecondTimestamp()
// Localizing content:
//
// 1. Add NS_LocalizedString() (remove '_' like below).
// Make sure the "key" (e.g. SCREENSHOT_USERNAME_1) is unique for each string.
// Make sure you add a comment for the translators.
//
// someString1 will always be "Alice."
// let someString1 = "Alice"
// someLocalizedString might be "Alice" in English and "Boris" in Russian,
// depending on your device/simulator's locale's language.
// let someLocalizedString = NSLocalizedString("SCREENSHOT_USERNAME_1", comment: "An example name for a user we use in the screenshots.")
// 2. Run the l10n string script in the terminal
// Scripts/translation/auto-genstrings
// This will make sure there's an entry in the _English_ localization for each key in the source.
// 3. Search for the key you just added - you'll find it in the English localization file.
// Add a English value.
// 4. The strings for the other languages won't be set until you sync your l10n strings.
// DON'T DO THIS without checking with the engineers.
// It can cause leave Transifex in the wrong state.
// It is done with this script:
// Scripts/translation/sync-translations
// If you add more users, make sure they each have
// unique numbers and uuid strings.
// TODOs set local profile phone number per locale
self.setLocalProfile(givenName: NSLocalizedString("SCREENSHOT_NAME_LOCAL_PROFILE",
comment: "This appears in Signal > Settings. A female leadership/presidential/chairwoman position + female name Freyja or similar spelling. This will have a cat profile photo."),
familyName: "",
avatarBundleFilename: "address-chairwoman-freya.jpg")
let address1 = self.ensureAccount(phoneNumber: "+13213214301",
uuidString: "123e4567-e89b-12d3-a456-426655440001",
// Example usage of NS_LocalizedString().
// givenName: NSLocalizedString("SCREENSHOT_USERNAME_1", comment: "An example name for a user we use in the screenshots."),
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_ONE",
comment: "This is a contact's name. A male leadership/presidential position + the sound a cat makes. This will have a cat profile photo."),
familyName: "",
avatarBundleFilename: "address-chairman-meow.jpg",
transaction: transaction)
let address2 = self.ensureAccount(phoneNumber: "+13213214302",
uuidString: "123e4567-e89b-12d3-a456-426655440002",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_TWO",
comment: "This is a contact's name. Replace the name for a more common name in your locale if this sounds too foreign. This should be a unique non-public figure's name. This profile photo will be either male or female."),
familyName: "",
avatarBundleFilename: "address-male-1.jpg",
transaction: transaction)
let address3 = self.ensureAccount(phoneNumber: "+13213214303",
uuidString: "123e4567-e89b-12d3-a456-426655440003",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_THREE",
comment: "This is a contact's name. Please keep a similar nickname for Nikola/Nikita/etc in your language and only post the last initial. This profile photo will be either male or female but mostly female."),
familyName: "",
avatarBundleFilename: "address-female-9.jpg",
transaction: transaction)
let address4 = self.ensureAccount(phoneNumber: "+13213214304",
uuidString: "123e4567-e89b-12d3-a456-426655440004",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_FOUR",
comment: "This is a contact's name. Replace the name for a more common name in your locale if this sounds too foreign. This should be a unique non-public figure's name. This profile photo will be either male or female. Choose a unisex name if possible."),
familyName: "",
avatarBundleFilename: "address-female-12.jpg",
transaction: transaction)
let address5 = self.ensureAccount(phoneNumber: "+13213214305",
uuidString: "123e4567-e89b-12d3-a456-426655440005",
// givenName: "Ali Smith",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_FIVE",
comment: "This is a contact's name. Please keep the nick name Ali and change the last name to a popular lastname in your language. This will have male profile photo."),
familyName: "",
avatarBundleFilename: "address-male-4.jpg",
transaction: transaction)
let address6 = self.ensureAccount(phoneNumber: "+13213214306",
uuidString: "123e4567-e89b-12d3-a456-426655440006",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_SIX",
comment: "This is a contact's name. Replace the name for a more common name in your locale if this sounds too foreign. This will have a male profile photo."),
familyName: "",
avatarBundleFilename: "address-male-3.jpg",
transaction: transaction)
let address7 = self.ensureAccount(phoneNumber: "+13213214307",
uuidString: "123e4567-e89b-12d3-a456-426655440007",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_SEVEN",
comment: "This is a contact's name. Please keep a similar unisex first name (Kai) if this name isn't common and only post the last initial. This will have a female profile photo."),
familyName: "",
avatarBundleFilename: "address-female-1.jpg",
transaction: transaction)
let address8 = self.ensureAccount(phoneNumber: "+13213214308",
uuidString: "123e4567-e89b-12d3-a456-426655440008",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_EIGHT",
comment: "This is a contact's name. Replace the name for a more common name in your locale if this sounds too foreign. This should be a unique non-public figure's name. This will have a female profile photo."),
familyName: "",
avatarBundleFilename: "address-female-2.jpg",
transaction: transaction)
let address9 = self.ensureAccount(phoneNumber: "+13213214309",
uuidString: "123e4567-e89b-12d3-a456-426655440009",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_NINE",
comment: "This is a contact's name. Replace the name for a more common name in your locale if this sounds too foreign. Include two last names if that is represented in your locale. This should be a unique non-public figure's name. This will have a female profile photo."),
familyName: "",
avatarBundleFilename: "address-female-7.jpg",
transaction: transaction)
let address10 = self.ensureAccount(phoneNumber: "+13213214310",
uuidString: "123e4567-e89b-12d3-a456-426655440010",
givenName: NSLocalizedString("SCREENSHOT_NAME_CONTACT_TEN",
comment: "This is a contact's name. Replace the name for a more common name in your locale if this sounds too foreign. This should be a unique non-public figure's name. This will have a female profile photo."),
familyName: "",
avatarBundleFilename: "address-female-8.jpg",
transaction: transaction)
// 1:1 website screenshot for thread
if true {
let otherAddress = address10
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
let timestampMessage0 = startingDateMS - (6 * kDayInMs + 55 * kMinuteInMs)
let attachmentMessage0 = buildAttachment(bundleFilename: "nature-5-cat.jpg",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let attachmentMessage1 = buildAttachment(bundleFilename: "nature-7-cat.jpg",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let attachmentMessage2 = buildAttachment(bundleFilename: "nature-6-cat.jpg",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let message0 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage0,
attachments: [attachmentMessage0, attachmentMessage1, attachmentMessage2],
transaction: transaction)
_ = message0.recordReaction(for: otherAddress,
emoji: "❤️",
sentAtTimestamp: Date.ows_millisecondTimestamp(),
receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
transaction: transaction)
let timestampMessage1 = startingDateMS - (6 * kDayInMs + 30 * kMinuteInMs)
let message1 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_ONE_MESSAGE_ONE",
comment: "This is a message."),
timestamp: timestampMessage1, transaction: transaction)
message1.debugonly_markAsReadNow(transaction: transaction)
_ = message1.recordReaction(for: localAddress,
emoji: "👍",
sentAtTimestamp: Date.ows_millisecondTimestamp(),
receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
transaction: transaction)
let timestampMessage2 = startingDateMS - (6 * kDayInMs + 3 * kMinuteInMs)
let message2 = self.buildOutgoingMessage(thread: thread, messageBody: "☺️",
timestamp: timestampMessage2, transaction: transaction)
message2.update(withReadRecipient: otherAddress, readTimestamp: Date.ows_millisecondTimestamp(), transaction: transaction)
let timestampMessage3 = startingDateMS - (6 * kDayInMs + 3 * kMinuteInMs)
let message3 = self.buildOutgoingMessage(thread: thread, messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_ONE_MESSAGE_TWO",
comment: "This is a message."),
timestamp: timestampMessage3, transaction: transaction)
message3.update(withReadRecipient: otherAddress, readTimestamp: Date.ows_millisecondTimestamp(), transaction: transaction)
let timestampMessage4 = startingDateMS - (6 * kDayInMs + 3 * kMinuteInMs)
let message4 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage4, transaction: transaction)
// Q: Which pack? A: Bandit the Cat.
let packIdHex = "9acc9e8aba563d26a4994e69263e3b25"
let packKeyHex = "5a6dff3948c28efb9b7aaf93ecc375c69fc316e78077ed26867a14d10a0f6a12"
// Which sticker - the index in the pack.
let stickerId0: UInt32 = 4
if let messageSticker = self.buildMessageSticker(packIdHex: packIdHex,
packKeyHex: packKeyHex,
stickerId: stickerId0,
transaction: transaction) {
message4.update(with: messageSticker, transaction: transaction)
}
}
// 1:1 encryption animation for website
if true {
let otherAddress = address4
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
let timestampMessage1 = startingDateMS - (5 * kDayInMs + 12 * kHourInMs)
let message1 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_TWO_MESSAGE_ONE",
comment: "This is a message before an image of mountains + a lake."),
timestamp: timestampMessage1, transaction: transaction)
message1.debugonly_markAsReadNow(transaction: transaction)
let timestampMessage2 = startingDateMS - (5 * kDayInMs + 12 * kHourInMs)
let attachmentMessage2 = buildAttachment(bundleFilename: "nature-8-NewZealand.jpg",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let message2 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress,
messageBody: nil,
timestamp: timestampMessage2,
attachments: [attachmentMessage2], transaction: transaction)
message2.debugonly_markAsReadNow(transaction: transaction)
let timestampMessage3 = startingDateMS - (5 * kDayInMs + 12 * kHourInMs)
let message3 = self.buildOutgoingMessage(thread: thread,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_TWO_MESSAGE_TWO",
comment: "This is a message after an image of mountains + a lake."),
timestamp: timestampMessage3,
transaction: transaction)
message3.update(withReadRecipient: otherAddress, readTimestamp: Date.ows_millisecondTimestamp(), transaction: transaction)
let timestampMessage4 = startingDateMS - (5 * kDayInMs + 12 * kHourInMs)
let message4 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_TWO_MESSAGE_THREE",
comment: "This is a message."),
timestamp: timestampMessage4, transaction: transaction)
message4.debugonly_markAsReadNow(transaction: transaction)
}
// 1:1 outgoing
if true {
let otherAddress = address9
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
let timestampMessage1 = startingDateMS - (4 * kDayInMs)
let message1 = self.buildOutgoingMessage(thread: thread, messageBody: "🤣🤣🤣",
timestamp: timestampMessage1, transaction: transaction)
message1.update(withReadRecipient: otherAddress, readTimestamp: Date.ows_millisecondTimestamp(), transaction: transaction)
}
// 1:1 incoming sticker
if true {
let otherAddress = address6
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
let timestampMessage1 = startingDateMS - (3 * kDayInMs + 12 * kHourInMs)
let message1 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_THREE_MESSAGE_ONE",
comment: "Replace crepes with similar item that you bake or cook i.e. bread, croissants, naan."),
timestamp: timestampMessage1, transaction: transaction)
message1.debugonly_markAsReadNow(transaction: transaction)
}
// Group sent attachment
if true {
let memberAddresses = [
address8,
address9
]
// avatarData should be PNG data.
let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
name: NSLocalizedString("SCREENSHOT_NAME_GROUP_ONE",
comment: "This is for a group of people interested in discussing books they've read."),
avatarData: buildAvatarData(bundleFilename: "address-group-book.jpg"),
transaction: transaction)
let timestampMessage1 = startingDateMS - (3 * kDayInMs + 4 * kHourInMs)
let message1 = self.buildOutgoingMessage(thread: thread, messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_ONE_MESSAGE_ONE",
comment: "This is for a message in the 'Book Club' group chat"),
timestamp: timestampMessage1, transaction: transaction)
let timestampMessage2 = startingDateMS - (3 * kDayInMs + 4 * kMinuteInMs)
let attachmentMessage2 = buildAttachment(bundleFilename: "1984.txt",
mimeType: "text/plain",
sourceFilename: NSLocalizedString("SCREENSHOT_THREAD_GROUP_ONE_FILE_NAME",
comment: "1984 is the book title. The file extension is a text file."),
transaction: transaction)
let message2 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage2,
attachments: [attachmentMessage2],
transaction: transaction)
}
// Group incoming attachment + caption
if true {
let memberAddresses = [
address8,
address9
]
// avatarData should be PNG data.
let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
name: NSLocalizedString("SCREENSHOT_NAME_GROUP_TWO",
comment: "This is for a group chat for people who want weather updates."),
avatarData: buildAvatarData(bundleFilename: "nature-2-trees.JPG"),
transaction: transaction)
let timestampMessage1 = startingDateMS - (2 * kDayInMs + 8 * kHourInMs)
let message1 = self.buildOutgoingMessage(thread: thread, messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_TWO_MESSAGE_ONE",
comment: "This is a message. Please include the emoji if possible."),
timestamp: timestampMessage1, transaction: transaction)
let timestampMessage2 = startingDateMS - (2 * kDayInMs + 8 * kHourInMs + 1 * kMinuteInMs)
let attachmentMessage2 = buildAttachment(bundleFilename: "test-jpg-2.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let message2 = self.buildIncomingMessage(thread: thread,
authorAddress: address9,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_TWO_MESSAGE_TWO",
comment: "This is a message sent with an attachment."),
timestamp: timestampMessage2,
attachments: [attachmentMessage2],
transaction: transaction)
message2.debugonly_markAsReadNow(transaction: transaction)
}
// 1:1 received text
if true {
let otherAddress = address3
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
let message1 = self.buildOutgoingMessage(thread: thread, messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_FOUR_MESSAGE_ONE",
comment: "This is a message."),
transaction: transaction)
// This marks the outgoing message as read
// as opposed to displaying one sent check mark
message1.update(withReadRecipient: otherAddress, readTimestamp: Date.ows_millisecondTimestamp(), transaction: transaction)
let timestampMessage2 = startingDateMS - (2 * kDayInMs + 4 * kHourInMs + 42 * kMinuteInMs)
let message2 = self.buildIncomingMessage(thread: thread,
authorAddress: otherAddress,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_FOUR_MESSAGE_TWO",
comment: "This is a message. Include 'Thanks' + a similar phrase with the :) emoji."),
timestamp: timestampMessage2, transaction: transaction)
// This marks the incoming message as read
// so the "New Messages" indicator/ "Today" is not displayed
message2.debugonly_markAsReadNow(transaction: transaction)
}
// Group received text
if true {
let memberAddresses = [
address6,
address7
]
// avatarData should be PNG data.
let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
name: NSLocalizedString("SCREENSHOT_NAME_GROUP_THREE",
comment: "Please include emoji. This is a group name for people who climb rocks/climb trees/hike mountains/outside mountaineering."),
avatarData: buildAvatarData(bundleFilename: "address-group-climbers.jpg"),
transaction: transaction)
let timestampMessage1 = startingDateMS - (2 * kDayInMs + 2 * kHourInMs)
let message1 = self.buildIncomingMessage(thread: thread, authorAddress: address6,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_THREE_MESSAGE_ONE",
comment: "This is a message in the 'Rock Climbers' group chat. Please translate to make sense for the translated group name. For example: Which way should we go?"),
timestamp: timestampMessage1, transaction: transaction)
message1.debugonly_markAsReadNow(transaction: transaction)
}
// Group received
if true {
let memberAddresses = [
address4,
address5
]
// avatarData should be PNG data.
let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
name: NSLocalizedString("SCREENSHOT_NAME_GROUP_FOUR",
comment: "Please include emoji. This is a group name/channel name for pictures of the sun in the sky."),
avatarData: buildAvatarData(bundleFilename: "nature-4-sunset.jpg"),
transaction: transaction)
let timestampMessage1 = startingDateMS - (1 * kDayInMs + 18 * kHourInMs)
let message1 = self.buildOutgoingMessage(thread: thread, messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_FOUR_MESSAGE_ONE",
comment: "This is a message in the Sunsets group chat."),
timestamp: timestampMessage1, transaction: transaction)
let timestampMessage2 = startingDateMS - (1 * kDayInMs + 18 * kHourInMs + 10 * kMinuteInMs)
let attachmentMessage2 = buildAttachment(bundleFilename: "nature-3-road.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let message2 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage2,
attachments: [attachmentMessage2],
isViewOnceMessage: true,
transaction: transaction)
}
// Example of how to make a simple 1:1 thread.
// TODO check voice note format
if true {
let otherAddress = address7
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
let timestampMessage1 = startingDateMS - (9 * kHourInMs)
let attachmentMessage1 = buildAttachment(bundleFilename: "test-jpg-3.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let message1 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage1,
attachments: [attachmentMessage1], transaction: transaction)
let timestampMessage2 = startingDateMS - (8 * kHourInMs + 27 * kMinuteInMs)
let message2 = self.buildOutgoingMessage(thread: thread,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_FIVE_MESSAGE_ONE",
comment: "This is a message expressing support/happiness/awe/shock."),
timestamp: timestampMessage2, transaction: transaction)
GroupManager.remoteUpdateDisappearingMessages(withContactOrV1GroupThread: thread,
disappearingMessageToken: DisappearingMessageToken(isEnabled: true, durationSeconds: UInt32(24 * kHourInterval)),
groupUpdateSourceAddress: localAddress,
transaction: transaction)
let attachmentMessage3 = buildAttachment(bundleFilename: "sonarping.mp3",
mimeType: "audio/mp3",
transaction: transaction)
attachmentMessage3.attachmentType = .voiceMessage
attachmentMessage3.anyOverwritingUpdate(transaction: transaction)
let timestampMessage3 = startingDateMS - (3 * kHourInMs + 58 * kMinuteInMs)
let message3 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage3,
attachments: [attachmentMessage3],
expiresInSeconds: 10800,
transaction: transaction)
_ = message3.recordReaction(for: otherAddress,
emoji: "❤️",
sentAtTimestamp: Date.ows_millisecondTimestamp(),
receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
transaction: transaction)
let timestampMessage4 = startingDateMS - (3 * kHourInMs + 20 * kMinuteInMs)
let message4 = self.buildIncomingMessage(thread: thread,
authorAddress: otherAddress,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_FIVE_MESSAGE_TWO",
comment: "This is a message. Please include the emoji."),
timestamp: timestampMessage4,
expiresInSeconds: 10800,
transaction: transaction)
message4.debugonly_markAsReadNow(transaction: transaction)
let attachmentMessage5 = buildAttachment(bundleFilename: "test-jpg-2.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let timestampMessage5 = startingDateMS - (2 * kHourInMs + 20 * kMinuteInMs)
let message5 = self.buildIncomingMessage(thread: thread,
authorAddress: otherAddress,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_FIVE_MESSAGE_THREE",
comment: "This is a message."),
timestamp: timestampMessage5,
attachments: [attachmentMessage5],
expiresInSeconds: 10800,
transaction: transaction)
message5.debugonly_markAsReadNow(transaction: transaction)
_ = message5.recordReaction(for: localAddress,
emoji: "👍",
sentAtTimestamp: Date.ows_millisecondTimestamp(),
receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
transaction: transaction)
let timestampMessage6 = startingDateMS - ( 2 * kHourInMs + 2 * kMinuteInMs)
let message6 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage6,
expiresInSeconds: 10800, transaction: transaction)
// Q: Which pack? A: Bandit the Cat.
let packIdHex = "9acc9e8aba563d26a4994e69263e3b25"
let packKeyHex = "5a6dff3948c28efb9b7aaf93ecc375c69fc316e78077ed26867a14d10a0f6a12"
// Which sticker - the index in the pack.
let stickerId0: UInt32 = 14
if let messageSticker = self.buildMessageSticker(packIdHex: packIdHex,
packKeyHex: packKeyHex,
stickerId: stickerId0,
transaction: transaction) {
message6.update(with: messageSticker, transaction: transaction)
}
}
// Group thread received text
if true {
let memberAddresses = [
address1,
address2,
address7,
address6
]
// avatarData should be PNG data.
let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
name: NSLocalizedString("SCREENSHOT_NAME_GROUP_FIVE",
comment: "This is a group chat of family members. Please keep Kirk or replace with a common last name in your locale. Translate 'Family'"),
avatarData: buildAvatarData(bundleFilename: "address-group-family.jpg"),
// avatarData: nil,
transaction: transaction)
let message1 = self.buildOutgoingMessage(thread: thread, messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_FIVE_MESSAGE_ONE",
comment: "This is a message in the group chat of family members."),
transaction: transaction)
let timestampMessage2 = startingDateMS - (1 * kHourInMs + 58 * kMinuteInMs)
let message2 = self.buildIncomingMessage(thread: thread,
authorAddress: address6,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_FIVE_MESSAGE_TWO",
comment: "This is a message in the group chat of family members."),
timestamp: timestampMessage2, transaction: transaction)
}
// 1:1 sent media
if true {
let otherAddress = address5
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
let timestampMessage2 = startingDateMS - (33 * kMinuteInMs)
let message1 = self.buildOutgoingMessage(thread: thread, messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_SIX_MESSAGE_ONE",
comment: "This is a message."),
timestamp: timestampMessage2, transaction: transaction)
// This marks the outgoing message as read
// as opposed to displaying one sent check mark
message1.update(withReadRecipient: otherAddress, readTimestamp: Date.ows_millisecondTimestamp(), transaction: transaction)
let attachmentMessage2 = buildAttachment(bundleFilename: "test-jpg-3.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let message2 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage2,
attachments: [attachmentMessage2], transaction: transaction)
}
// Group other file types -- in focus
// Shows how to send and receive attached images.
if true {
// Shows how to send and receive attached images.
// This file lives on disk in Signal/test/Assets.
// In the project it is in Signal/Signal/test/Assets.
// You'll need to temporarily add it to the Signal target
// before you can use it here.
// You can find files in the repo using something like this...
// find . | grep -i "test-jpg"
// ...where test-jpg is a partial file name.
let attachment1 = buildAttachment(bundleFilename: "test-jpg-2.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let attachment2 = buildAttachment(bundleFilename: "test-jpg-2.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let memberAddresses = [
address1,
address4,
address5,
address6,
address8,
address9,
localAddress
]
// avatarData should be PNG data.
let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
name: NSLocalizedString("SCREENSHOT_NAME_GROUP_SIX",
comment: "This is group chat name for members talking about cats. Please include the emoji."),
avatarData: buildAvatarData(bundleFilename: "address-group-cat.jpg"),
transaction: transaction)
let attachmentMessage1 = buildAttachment(bundleFilename: "nature-2-trees.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let timestampMessage1 = startingDateMS - (23 * kHourInMs + 9 * kMinuteInMs)
let message1 = self.buildIncomingMessage(thread: thread,
authorAddress: address8,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_SIX_MESSAGE_ONE",
comment: "This is a message after seeing a picture."),
timestamp: timestampMessage1,
attachments: [attachmentMessage1], transaction: transaction)
message1.debugonly_markAsReadNow(transaction: transaction)
let attachmentMessage2 = buildAttachment(bundleFilename: "test-jpg-3.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let timestampMessage2 = startingDateMS - (16 * kHourInMs + 5 * kMinuteInMs)
let message2 = self.buildIncomingMessage(thread: thread,
authorAddress: address5,
messageBody: nil,
timestamp: timestampMessage2,
attachments: [attachmentMessage2], transaction: transaction)
message2.debugonly_markAsReadNow(transaction: transaction)
let timestampMessage3 = startingDateMS - (4 * kHourInMs + 7 * kMinuteInMs)
let message3 = self.buildIncomingMessage(thread: thread,
authorAddress: address9,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_SIX_MESSAGE_TWO", comment: "This is a message."),
timestamp: timestampMessage3,
transaction: transaction)
message3.debugonly_markAsReadNow(transaction: transaction)
let attachmentMessage4 = buildAttachment(bundleFilename: "nature-1-sunrise.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let timestampMessage4 = startingDateMS - (4 * kHourInMs + 7 * kMinuteInMs)
let message4 = self.buildIncomingMessage(thread: thread,
authorAddress: address9,
messageBody: nil,
timestamp: timestampMessage4,
attachments: [attachmentMessage4], transaction: transaction)
message4.debugonly_markAsReadNow(transaction: transaction)
let timestampMessage5 = startingDateMS - (15 * kMinuteInMs)
let message5 = self.buildOutgoingMessage(thread: thread,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_SIX_MESSAGE_THREE",
comment: "This is a message in the cat chat group."),
timestamp: timestampMessage5,
transaction: transaction)
_ = message5.recordReaction(for: address1,
emoji: "😂",
sentAtTimestamp: Date.ows_millisecondTimestamp(),
receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
transaction: transaction)
_ = message5.recordReaction(for: address4,
emoji: "😮",
sentAtTimestamp: Date.ows_millisecondTimestamp(),
receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
transaction: transaction)
_ = message5.recordReaction(for: address5,
emoji: "😮",
sentAtTimestamp: Date.ows_millisecondTimestamp(),
receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
transaction: transaction)
let timestampMessage6 = startingDateMS - (13 * kMinuteInMs)
let message6 = self.buildIncomingMessage(thread: thread,
authorAddress: address6,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_SIX_MESSAGE_FOUR", comment: "This is a message in the cat chat group."),
timestamp: timestampMessage6,
transaction: transaction)
message6.debugonly_markAsReadNow(transaction: transaction)
let attachmentMessage7 = buildAttachment(bundleFilename: "test-jpg-3.JPG",
mimeType: OWSMimeTypeImageJpeg,
transaction: transaction)
let timestampMessage7 = startingDateMS - (9 * kMinuteInMs)
let message7 = self.buildOutgoingMessage(thread: thread,
messageBody: nil,
timestamp: timestampMessage7,
attachments: [attachmentMessage7],
isViewOnceMessage: true,
transaction: transaction)
let attachmentMessage8 = buildAttachment(bundleFilename: "certificate.PDF",
mimeType: "application/pdf",
sourceFilename: NSLocalizedString("SCREENSHOT_THREAD_GROUP_SIX_FILE_NAME", comment: "This is a file name 'Instructions' for the cat chat group."),
transaction: transaction)
let timestampMessage8 = startingDateMS - (9 * kMinuteInMs)
let message8 = self.buildIncomingMessage(thread: thread,
authorAddress: address4,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_GROUP_SIX_MESSAGE_FIVE", comment: "This is a message in the cat chat group."),
timestamp: timestampMessage8,
attachments: [attachmentMessage8], transaction: transaction)
message8.debugonly_markAsReadNow(transaction: transaction)
}
// Third thread 1:1 received voice message
if true {
let otherAddress = address2
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
// This will be a build warning because you're not using the message1 variable.
// you can fix that by saying:
// _ = self.buildOutgoingMessage(...)
let timestampMessage7 = startingDateMS - (4 * kMinuteInMs)
let message1 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress, messageBody: "1", timestamp: timestampMessage7, transaction: transaction)
let message2 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress, messageBody: "2", timestamp: timestampMessage7, transaction: transaction)
let message3 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress, messageBody: "3", timestamp: timestampMessage7, transaction: transaction)
let message4 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress, messageBody: "4.", timestamp: timestampMessage7, transaction: transaction)
let message5 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress, messageBody: "5", timestamp: timestampMessage7, transaction: transaction)
let message6 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress, messageBody: "6", timestamp: timestampMessage7, transaction: transaction)
let attachmentMessage7 = buildAttachment(bundleFilename: "sonarping.mp3",
mimeType: "audio/mp3",
transaction: transaction)
attachmentMessage7.attachmentType = .voiceMessage
attachmentMessage7.anyOverwritingUpdate(transaction: transaction)
let message7 = self.buildIncomingMessage(thread: thread,
authorAddress: otherAddress,
messageBody: nil,
timestamp: timestampMessage7,
attachments: [attachmentMessage7], transaction: transaction)
}
// Second Thread -- Missed call or emoji on iPad
if true {
let otherAddress = address1
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
let timestampMessage1 = startingDateMS - (3 * kMinuteInMs)
let message1 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress,
messageBody: "🤣🤣🤣",
timestamp: timestampMessage1, transaction: transaction)
let timestampMessage2 = startingDateMS - (2 * kMinuteInMs)
let message2 = self.buildIncomingMessage(thread: thread, authorAddress: otherAddress,
messageBody: NSLocalizedString("SCREENSHOT_THREAD_DIRECT_SEVEN_MESSAGE_ONE", comment: "This is a message before a call."),
timestamp: timestampMessage1, transaction: transaction)
let timestampCall1 = startingDateMS
// Replace .incomingIncomplete with other values to create other record types.
// Note that you have to remove the obj-c enum prefix.
//
// typedef NS_ENUM(NSUInteger, RPRecentCallType) {
// RPRecentCallTypeIncoming = 1,
// RPRecentCallTypeOutgoing,
// RPRecentCallTypeIncomingMissed,
// // These call types are used until the call connects.
// RPRecentCallTypeOutgoingIncomplete,
// RPRecentCallTypeIncomingIncomplete,
// RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity,
// RPRecentCallTypeIncomingDeclined,
// RPRecentCallTypeOutgoingMissed,
// };
let callRecord = TSCall(callType: .incomingMissed,
offerType: .audio,
thread: thread,
sentAtTimestamp: Date.ows_millisecondTimestamp())
callRecord.anyInsert(transaction: transaction)
}
// First message for disappearing message time set
// Adjust the time of alert or keep this first
if true {
let otherAddress = address8
let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
// let message1 = self.buildOutgoingMessage(thread: thread, messageBody: "Hi yup.", transaction: transaction)
// // This marks the outgoing message as read
// // as opposed to displaying one sent check mark
// message1.update(withReadRecipient: otherAddress, readTimestamp: Date.ows_millisecondTimestamp(), transaction: transaction)
// let timestampMessage2 = startingDateMS - (30 * kHourInMs + 42 * kMinuteInMs)
// let message2 = self.buildIncomingMessage(thread: thread,
// authorAddress: otherAddress,
// messageBody: "Thanks! What a wonderful message to read :)", transaction: transaction)
// // This marks the incoming message as read
// // so the "New Messages" indicator/ "Today" is not displayed
// message2.debugonly_markAsReadNow(transaction: transaction)
GroupManager.remoteUpdateDisappearingMessages(withContactOrV1GroupThread: thread,
disappearingMessageToken: DisappearingMessageToken(isEnabled: true, durationSeconds: UInt32(24 * kHourInterval)),
groupUpdateSourceAddress: localAddress,
transaction: transaction)
}
// // Example of how to enable or disable disappearing messages.
// if true {
// let memberAddresses = [
// address1,
// address2,
// ]
// // avatarData should be PNG data.
// let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
// name: "DMs",
// avatarData: nil,
// transaction: transaction)
// let message1 = self.buildOutgoingMessage(thread: thread, messageBody: "", transaction: transaction)
// // Enable DMs.
// //
// // For the purposes of this debug UI, it's simplest to use the
// // "remote" flavor of this message which is sync.
// GroupManager.remoteUpdateDisappearingMessages(withContactOrV1GroupThread: thread,
// disappearingMessageToken: DisappearingMessageToken(isEnabled: true, durationSeconds: UInt32(24 * kHourInterval)),
// groupUpdateSourceAddress: localAddress,
// transaction: transaction)
// // Disable DMs.
// GroupManager.remoteUpdateDisappearingMessages(withContactOrV1GroupThread: thread,
// disappearingMessageToken: DisappearingMessageToken.disabledToken,
// groupUpdateSourceAddress: localAddress,
// transaction: transaction)
// }
// // Example of how insert call messages.
// if true {
// let otherAddress = address1
// let thread = TSContactThread.getOrCreateThread(withContactAddress: otherAddress, transaction: transaction)
//
// // I think this is a "missed incoming" call.
// //
// // Replace .incomingIncomplete with other values to create other record types.
// // Note that you have to remove the obj-c enum prefix.
// //
// // typedef NS_ENUM(NSUInteger, RPRecentCallType) {
// // RPRecentCallTypeIncoming = 1,
// // RPRecentCallTypeOutgoing,
// // RPRecentCallTypeIncomingMissed,
// // // These call types are used until the call connects.
// // RPRecentCallTypeOutgoingIncomplete,
// // RPRecentCallTypeIncomingIncomplete,
// // RPRecentCallTypeIncomingMissedBecauseOfChangedIdentity,
// // RPRecentCallTypeIncomingDeclined,
// // RPRecentCallTypeOutgoingMissed,
// // };
//// let callRecord = TSCall(callType: .incomingIncomplete,
//// in: thread,
//// sentAtTimestamp: Date.ows_millisecondTimestamp())
// let callRecord = TSCall(callType: .incomingMissed,
// in: thread,
// sentAtTimestamp: Date.ows_millisecondTimestamp())
// callRecord.anyInsert(transaction: transaction)
// }
// // Example of how to insert reactions.
// if true {
// let memberAddresses = [
// address1,
// address2,
// ]
// // avatarData should be PNG data.
// let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
// name: "Reactions",
// avatarData: nil,
// transaction: transaction)
// let outgoingMessage = self.buildOutgoingMessage(thread: thread, messageBody: "something", transaction: transaction)
// let incomingMessage = self.buildIncomingMessage(thread: thread,
// authorAddress: address1,
// messageBody: "Welcome... 1", transaction: transaction)
//
// // Local user (for this device) likes a given message.
// //
// // Reference: ["", "👍", "👎", "😂", "😮", "😢", "😡"]
// let _ = incomingMessage.recordReaction(for: localAddress,
// emoji: "",
// sentAtTimestamp: Date.ows_millisecondTimestamp(),
// receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
// transaction: transaction)
//
// // Some other user reacts to a given message.
// let _ = outgoingMessage.recordReaction(for: address1,
// emoji: "👍",
// sentAtTimestamp: Date.ows_millisecondTimestamp(),
// receivedAtTimestamp: NSDate.ows_millisecondTimeStamp(),
// transaction: transaction)
// }
// // Example of how to insert stickers.
// if true {
// let memberAddresses = [
// address1,
// address2,
// ]
// // avatarData should be PNG data.
// let thread = try! GroupManager.createGroupForTests(members: memberAddresses,
// name: "Stickers",
// avatarData: nil,
// transaction: transaction)
// let outgoingMessage = self.buildOutgoingMessage(thread: thread, messageBody: "", transaction: transaction)
// let incomingMessage = self.buildIncomingMessage(thread: thread,
// authorAddress: address1,
// messageBody: "Welcome... 1", transaction: transaction)
//
// // Q: Which pack? A: Bandit the Cat.
// let packIdHex = "9acc9e8aba563d26a4994e69263e3b25"
// let packKeyHex = "5a6dff3948c28efb9b7aaf93ecc375c69fc316e78077ed26867a14d10a0f6a12"
// // Which sticker - the index in the pack.
// let stickerId0: UInt32 = 0
// let stickerId1: UInt32 = 1
//
// if let messageSticker = self.buildMessageSticker(packIdHex: packIdHex,
// packKeyHex: packKeyHex,
// stickerId: stickerId0,
// transaction: transaction) {
// incomingMessage.update(with: messageSticker, transaction: transaction)
// }
// if let messageSticker = self.buildMessageSticker(packIdHex: packIdHex,
// packKeyHex: packKeyHex,
// stickerId: stickerId1,
// transaction: transaction) {
// outgoingMessage.update(with: messageSticker, transaction: transaction)
// }
// }
}
}
private class func buildMessageSticker(packIdHex: String, packKeyHex: String, stickerId: UInt32, transaction: SDSAnyWriteTransaction) -> MessageSticker? {
guard let stickerPackInfo = StickerPackInfo.parsePackIdHex(packIdHex, packKeyHex: packKeyHex) else {
owsFailDebug("Invalid info")
return nil
}
let allPacks: [StickerPack] = StickerManager.installedStickerPacks(transaction: transaction)
// Find the pack with the matching pack id.
let packList = allPacks.filter { $0.info.packId == stickerPackInfo.packId }
guard let pack: StickerPack = packList.first else {
owsFailDebug("Sticker pack not installed?")
return nil
}
// Find the sticker with the matching stickerId.
let stickerInfos: [StickerInfo] = pack.stickerInfos.filter { $0.stickerId == stickerId }
guard let stickerInfo = stickerInfos.first else {
owsFailDebug("Couldn't find sticker info in pack.")
return nil
}
guard let stickerMetadata = StickerManager.installedStickerMetadataWithSneakyTransaction(stickerInfo: stickerInfo) else {
owsFailDebug("Couldn't find sticker metadata.")
return nil
}
do {
let stickerData = try Data(contentsOf: stickerMetadata.stickerDataUrl)
let stickerDraft = MessageStickerDraft(info: stickerInfo,
stickerData: stickerData,
stickerType: stickerMetadata.stickerType,
emoji: stickerMetadata.firstEmoji)
let messageSticker = try MessageSticker.buildValidatedMessageSticker(fromDraft: stickerDraft,
transaction: transaction)
return messageSticker
} catch {
owsFailDebug("Couldn't create sticker: \(error).")
return nil
}
}
// private class func ensureAccount(phoneNumber: String,
// uuidString: String,
// givenName: String,
// familyName: String?,
// transaction: SDSAnyWriteTransaction) -> SignalServiceAddress {
// let uuid = UUID(uuidString: uuidString)!
// let address = SignalServiceAddress(uuid: uuid, phoneNumber: phoneNumber)
// self.profileManager.setProfileGivenName(givenName,
// familyName: familyName,
// for: address,
// wasLocallyInitiated: false,
// transaction: transaction)
//
// let contact = self.buildContact(address: address, fullName: givenName, transaction: transaction)
// if let existingAccount = contactsManager.fetchSignalAccount(for: address, transaction: transaction) {
// // Do nothing.
// existingAccount.contact = contact
// existingAccount.anyOverwritingUpdate(transaction: transaction)
// } else {
// let newAccount = SignalAccount(contact: contact,
// contactAvatarHash: nil,
// contactAvatarJpegData: nil,
// multipleAccountLabelText: "",
// recipientPhoneNumber: phoneNumber,
// recipientUUID: uuidString)
// newAccount.anyInsert(transaction: transaction)
// }
// return address
// }
private class func ensureAccount(phoneNumber: String,
uuidString: String,
givenName: String,
familyName: String?,
avatarBundleFilename: String? = nil,
transaction: SDSAnyWriteTransaction) -> SignalServiceAddress {
let uuid = UUID(uuidString: uuidString)!
let address = SignalServiceAddress(uuid: uuid, phoneNumber: phoneNumber)
self.profileManager.setProfileGivenName(givenName,
familyName: familyName,
for: address,
wasLocallyInitiated: false,
transaction: transaction)
if let avatarBundleFilename = avatarBundleFilename {
let resourceUrl = Bundle.main.resourceURL!
let fileUrl = resourceUrl.appendingPathComponent(avatarBundleFilename)
let avatarData = try! Data(contentsOf: fileUrl)
let avatarFileName = UUID().uuidString + ".jpg"
try! avatarData.write(to: URL(fileURLWithPath: OWSUserProfile.profileAvatarFilepath(withFilename: avatarFileName)), options: .atomic)
let profile = OWSUserProfile.getOrBuild(for: address, transaction: transaction)
profile.update(withAvatarFileName: avatarFileName, transaction: transaction)
}
let contact = self.buildContact(address: address, fullName: givenName, transaction: transaction)
if let existingAccount = contactsManagerImpl.fetchSignalAccount(for: address, transaction: transaction) {
existingAccount.updateWithContact(contact, transaction: transaction)
} else {
let newAccount = SignalAccount(contact: contact,
contactAvatarHash: nil,
contactAvatarJpegData: nil,
multipleAccountLabelText: "",
recipientPhoneNumber: phoneNumber,
recipientUUID: uuidString)
newAccount.anyInsert(transaction: transaction)
}
return address
}
private class func setLocalProfile(givenName: String,
familyName: String?,
avatarBundleFilename: String? = nil) {
let avatarData: Data?
if let avatarBundleFilename = avatarBundleFilename {
let resourceUrl = Bundle.main.resourceURL!
let fileUrl = resourceUrl.appendingPathComponent(avatarBundleFilename)
avatarData = try! Data(contentsOf: fileUrl)
} else {
avatarData = nil
}
firstly(on: .global()) {
OWSProfileManager.updateLocalProfilePromise(
profileGivenName: givenName,
profileFamilyName: familyName,
profileBio: nil,
profileBioEmoji: nil,
profileAvatarData: avatarData
).asVoid()
}.catch(on: .global()) { error in
owsFailDebug("Error: \(error)")
}
}
private class func buildContact(address: SignalServiceAddress, fullName: String, transaction: SDSAnyWriteTransaction) -> Contact {
var userTextPhoneNumbers: [String] = []
var phoneNumberNameMap: [String: String] = [:]
var parsedPhoneNumbers: [PhoneNumber] = []
if let phoneNumber = address.phoneNumber,
let parsedPhoneNumber = PhoneNumber(fromE164: phoneNumber) {
userTextPhoneNumbers.append(phoneNumber)
parsedPhoneNumbers.append(parsedPhoneNumber)
phoneNumberNameMap[parsedPhoneNumber.toE164()] = CommonStrings.mainPhoneNumberLabel
}
guard let serviceIdentifier = address.serviceIdentifier else {
owsFail("serviceIdentifier was unexpectedly nil")
}
return Contact(uniqueId: serviceIdentifier,
cnContactId: nil,
firstName: nil,
lastName: nil,
nickname: nil,
fullName: fullName,
userTextPhoneNumbers: userTextPhoneNumbers,
phoneNumberNameMap: phoneNumberNameMap,
parsedPhoneNumbers: parsedPhoneNumbers,
emails: [],
imageDataToHash: nil)
}
private class func buildOutgoingMessage(thread: TSThread,
messageBody: String?,
timestamp: UInt64? = nil,
attachments: [TSAttachmentStream]? = nil,
expiresInSeconds: UInt32? = nil,
isViewOnceMessage: Bool? = false,
transaction: SDSAnyWriteTransaction) -> TSOutgoingMessage {
// Manipulate when the message was sent here.
//
// e.g. "yesterday" would be: Date.ows_millisecondTimestamp() - kDayInMs
let builder = TSOutgoingMessageBuilder(thread: thread, messageBody: messageBody)
if let timestamp = timestamp {
builder.timestamp = timestamp
}
if let attachments = attachments {
for attachment in attachments {
builder.addAttachmentId(attachment.uniqueId)
}
}
if let expiresInSeconds = expiresInSeconds {
builder.expiresInSeconds = expiresInSeconds
}
if let isViewOnceMessage = isViewOnceMessage {
builder.isViewOnceMessage = isViewOnceMessage
}
let message = builder.build()
message.replaceReceivedAtTimestamp(timestamp ?? Date.ows_millisecondTimestamp())
message.anyInsert(transaction: transaction)
// Mark as sent.
message.update(withFakeMessageState: .sent, transaction: transaction)
guard let localAddress = tsAccountManager.localAddress else {
owsFailDebug("missing local address.")
return message
}
// Find some recipient of the message (who isn't us).
guard let otherAddress = (thread.recipientAddresses.filter { $0 != localAddress }.first) else {
owsFailDebug("Couldn't find other address in thread.")
return message
}
// Mark as sent to someone.
message.update(withSentRecipient: otherAddress, wasSentByUD: false, transaction: transaction)
// Mark as delivered by someone.
message.update(withDeliveredRecipient: otherAddress,
deliveryTimestamp: nil,
transaction: transaction)
// Mark as read by someone.
message.update(withReadRecipient: otherAddress,
readTimestamp: Date.ows_millisecondTimestamp(),
transaction: transaction )
return message
}
private class func buildIncomingMessage(thread: TSThread,
authorAddress: SignalServiceAddress,
messageBody: String?,
timestamp: UInt64? = nil,
attachments: [TSAttachmentStream]? = nil,
expiresInSeconds: UInt32? = nil,
isViewOnceMessage: Bool? = false,
transaction: SDSAnyWriteTransaction) -> TSIncomingMessage {
// Manipulate when the message was sent here.
//
// e.g. "yesterday" would be: Date.ows_millisecondTimestamp() - kDayInMs
let timestamp = timestamp ?? Date.ows_millisecondTimestamp()
var attachmentIds = [String]()
if let attachments = attachments {
attachmentIds = attachments.map { $0.uniqueId }
}
let expiresInSeconds = expiresInSeconds ?? 0
let isViewOnceMessage = isViewOnceMessage ?? false
let message = TSIncomingMessageBuilder(thread: thread,
timestamp: timestamp,
authorAddress: authorAddress,
messageBody: messageBody,
attachmentIds: attachmentIds,
expiresInSeconds: expiresInSeconds,
isViewOnceMessage: isViewOnceMessage).build()
message.replaceReceivedAtTimestamp(timestamp)
message.anyInsert(transaction: transaction)
return message
}
private class func buildAvatarData(bundleFilename: String) -> Data {
let resourceUrl = Bundle.main.resourceURL!
let fileUrl = resourceUrl.appendingPathComponent(bundleFilename)
return try! Data(contentsOf: fileUrl)
}
private class func buildAttachment(bundleFilename: String,
mimeType: String,
sourceFilename: String? = nil,
caption: String? = nil,
transaction: SDSAnyWriteTransaction) -> TSAttachmentStream {
// Content types are MIME types
// See: MIMETypeUtil.h
let resourceUrl = Bundle.main.resourceURL!
let fileUrl = resourceUrl.appendingPathComponent(bundleFilename)
let fileSize = OWSFileSystem.fileSize(of: fileUrl)!.intValue
let attachment = TSAttachmentStream(contentType: mimeType,
byteCount: UInt32(fileSize),
// This doesn't matter much unless you export the file.
// You can leave it nil.
sourceFilename: sourceFilename,
caption: caption,
// If you want an album, make sure that they all have the same album id.
albumMessageId: nil)
let fileData = try! Data(contentsOf: fileUrl)
try! attachment.write(fileData)
attachment.anyInsert(transaction: transaction)
attachment.updateAsUploaded(withEncryptionKey: Randomness.generateRandomBytes(1),
digest: Randomness.generateRandomBytes(1),
serverId: 1,
cdnKey: "",
cdnNumber: 0,
uploadTimestamp: Date.ows_millisecondTimestamp(),
transaction: transaction)
return attachment
}
}
#endif